diff options
Diffstat (limited to 'drivers/bus')
-rw-r--r-- | drivers/bus/hisi_lpc.c | 47 | ||||
-rw-r--r-- | drivers/bus/ti-sysc.c | 125 |
2 files changed, 104 insertions, 68 deletions
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index 19d7b6ff2f17..20c957185af2 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c @@ -456,6 +456,17 @@ struct hisi_lpc_acpi_cell { size_t pdata_size; }; +static void hisi_lpc_acpi_remove(struct device *hostdev) +{ + struct acpi_device *adev = ACPI_COMPANION(hostdev); + struct acpi_device *child; + + device_for_each_child(hostdev, NULL, hisi_lpc_acpi_remove_subdev); + + list_for_each_entry(child, &adev->children, node) + acpi_device_clear_enumerated(child); +} + /* * hisi_lpc_acpi_probe - probe children for ACPI FW * @hostdev: LPC host device pointer @@ -555,8 +566,7 @@ static int hisi_lpc_acpi_probe(struct device *hostdev) return 0; fail: - device_for_each_child(hostdev, NULL, - hisi_lpc_acpi_remove_subdev); + hisi_lpc_acpi_remove(hostdev); return ret; } @@ -569,6 +579,10 @@ static int hisi_lpc_acpi_probe(struct device *dev) { return -ENODEV; } + +static void hisi_lpc_acpi_remove(struct device *hostdev) +{ +} #endif // CONFIG_ACPI /* @@ -606,24 +620,27 @@ static int hisi_lpc_probe(struct platform_device *pdev) range->fwnode = dev->fwnode; range->flags = LOGIC_PIO_INDIRECT; range->size = PIO_INDIRECT_SIZE; + range->hostdata = lpcdev; + range->ops = &hisi_lpc_ops; + lpcdev->io_host = range; ret = logic_pio_register_range(range); if (ret) { dev_err(dev, "register IO range failed (%d)!\n", ret); return ret; } - lpcdev->io_host = range; /* register the LPC host PIO resources */ if (acpi_device) ret = hisi_lpc_acpi_probe(dev); else ret = of_platform_populate(dev->of_node, NULL, NULL, dev); - if (ret) + if (ret) { + logic_pio_unregister_range(range); return ret; + } - lpcdev->io_host->hostdata = lpcdev; - lpcdev->io_host->ops = &hisi_lpc_ops; + dev_set_drvdata(dev, lpcdev); io_end = lpcdev->io_host->io_start + lpcdev->io_host->size; dev_info(dev, "registered range [%pa - %pa]\n", @@ -632,6 +649,23 @@ static int hisi_lpc_probe(struct platform_device *pdev) return ret; } +static int hisi_lpc_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct acpi_device *acpi_device = ACPI_COMPANION(dev); + struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev); + struct logic_pio_hwaddr *range = lpcdev->io_host; + + if (acpi_device) + hisi_lpc_acpi_remove(dev); + else + of_platform_depopulate(dev); + + logic_pio_unregister_range(range); + + return 0; +} + static const struct of_device_id hisi_lpc_of_match[] = { { .compatible = "hisilicon,hip06-lpc", }, { .compatible = "hisilicon,hip07-lpc", }, @@ -645,5 +679,6 @@ static struct platform_driver hisi_lpc_driver = { .acpi_match_table = ACPI_PTR(hisi_lpc_acpi_match), }, .probe = hisi_lpc_probe, + .remove = hisi_lpc_remove, }; builtin_platform_driver(hisi_lpc_driver); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index e6deabd8305d..9207ac291341 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ti-sysc.c - Texas Instruments sysc interconnect target driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/io.h> @@ -62,18 +54,26 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = { * @module_size: size of the interconnect target module * @module_va: virtual address of the interconnect target module * @offsets: register offsets from module base + * @mdata: ti-sysc to hwmod translation data for a module * @clocks: clocks used by the interconnect target module * @clock_roles: clock role names for the found clocks * @nr_clocks: number of clocks used by the interconnect target module + * @rsts: resets used by the interconnect target module * @legacy_mode: configured for legacy mode if set * @cap: interconnect target module capabilities * @cfg: interconnect target module configuration + * @cookie: data used by legacy platform callbacks * @name: name if available * @revision: interconnect target module revision + * @enabled: sysc runtime enabled status * @needs_resume: runtime resume needed on resume from suspend + * @child_needs_resume: runtime resume needed for child on resume from suspend + * @disable_on_idle: status flag used for disabling modules with resets + * @idle_work: work structure used to perform delayed idle on a module * @clk_enable_quirk: module specific clock enable quirk * @clk_disable_quirk: module specific clock disable quirk * @reset_done_quirk: module specific reset done quirk + * @module_enable_quirk: module specific enable quirk */ struct sysc { struct device *dev; @@ -95,11 +95,11 @@ struct sysc { unsigned int enabled:1; unsigned int needs_resume:1; unsigned int child_needs_resume:1; - unsigned int disable_on_idle:1; struct delayed_work idle_work; void (*clk_enable_quirk)(struct sysc *sysc); void (*clk_disable_quirk)(struct sysc *sysc); void (*reset_done_quirk)(struct sysc *sysc); + void (*module_enable_quirk)(struct sysc *sysc); }; static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, @@ -503,7 +503,7 @@ static void sysc_clkdm_allow_idle(struct sysc *ddata) static int sysc_init_resets(struct sysc *ddata) { ddata->rsts = - devm_reset_control_get_optional(ddata->dev, "rstctrl"); + devm_reset_control_get_optional_shared(ddata->dev, "rstctrl"); if (IS_ERR(ddata->rsts)) return PTR_ERR(ddata->rsts); @@ -615,8 +615,8 @@ static void sysc_check_quirk_stdout(struct sysc *ddata, * node but children have "ti,hwmods". These belong to the interconnect * target node and are managed by this driver. */ -static int sysc_check_one_child(struct sysc *ddata, - struct device_node *np) +static void sysc_check_one_child(struct sysc *ddata, + struct device_node *np) { const char *name; @@ -626,22 +626,14 @@ static int sysc_check_one_child(struct sysc *ddata, sysc_check_quirk_stdout(ddata, np); sysc_parse_dts_quirks(ddata, np, true); - - return 0; } -static int sysc_check_children(struct sysc *ddata) +static void sysc_check_children(struct sysc *ddata) { struct device_node *child; - int error; - for_each_child_of_node(ddata->dev->of_node, child) { - error = sysc_check_one_child(ddata, child); - if (error) - return error; - } - - return 0; + for_each_child_of_node(ddata->dev->of_node, child) + sysc_check_one_child(ddata, child); } /* @@ -794,9 +786,7 @@ static int sysc_map_and_check_registers(struct sysc *ddata) if (error) return error; - error = sysc_check_children(ddata); - if (error) - return error; + sysc_check_children(ddata); error = sysc_parse_registers(ddata); if (error) @@ -940,6 +930,9 @@ set_autoidle: sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); } + if (ddata->module_enable_quirk) + ddata->module_enable_quirk(ddata); + return 0; } @@ -949,7 +942,7 @@ static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode) *best_mode = SYSC_IDLE_SMART_WKUP; else if (idlemodes & BIT(SYSC_IDLE_SMART)) *best_mode = SYSC_IDLE_SMART; - else if (idlemodes & SYSC_IDLE_FORCE) + else if (idlemodes & BIT(SYSC_IDLE_FORCE)) *best_mode = SYSC_IDLE_FORCE; else return -EINVAL; @@ -1031,8 +1024,7 @@ static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev, dev_err(dev, "%s: could not idle: %i\n", __func__, error); - if (ddata->disable_on_idle) - reset_control_assert(ddata->rsts); + reset_control_assert(ddata->rsts); return 0; } @@ -1043,8 +1035,7 @@ static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev, struct ti_sysc_platform_data *pdata; int error; - if (ddata->disable_on_idle) - reset_control_deassert(ddata->rsts); + reset_control_deassert(ddata->rsts); pdata = dev_get_platdata(ddata->dev); if (!pdata) @@ -1091,10 +1082,9 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev) ddata->enabled = false; err_allow_idle: - sysc_clkdm_allow_idle(ddata); + reset_control_assert(ddata->rsts); - if (ddata->disable_on_idle) - reset_control_assert(ddata->rsts); + sysc_clkdm_allow_idle(ddata); return error; } @@ -1109,11 +1099,11 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev) if (ddata->enabled) return 0; - if (ddata->disable_on_idle) - reset_control_deassert(ddata->rsts); sysc_clkdm_deny_idle(ddata); + reset_control_deassert(ddata->rsts); + if (sysc_opt_clks_needed(ddata)) { error = sysc_enable_opt_clocks(ddata); if (error) @@ -1256,6 +1246,9 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_MODULE_QUIRK_I2C), SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, SYSC_MODULE_QUIRK_I2C), + SYSC_QUIRK("gpu", 0x50000000, 0x14, -1, -1, 0x00010201, 0xffffffff, 0), + SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff, + SYSC_MODULE_QUIRK_SGX), SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, SYSC_MODULE_QUIRK_WDT), @@ -1267,11 +1260,15 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0), SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902, 0xffff00f0, 0), - SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0), + SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0xa3170504, 0xffffffff, 0), + SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0x4edb1902, 0xffffffff, 0), SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0), SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0), + SYSC_QUIRK("d2d", 0x4a0b6000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), + SYSC_QUIRK("d2d", 0x4a0cd000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0), SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0), + SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff, 0), SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0), SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0), @@ -1423,6 +1420,15 @@ static void sysc_clk_disable_quirk_i2c(struct sysc *ddata) sysc_clk_quirk_i2c(ddata, false); } +/* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */ +static void sysc_module_enable_quirk_sgx(struct sysc *ddata) +{ + int offset = 0xff08; /* OCP_DEBUG_CONFIG */ + u32 val = BIT(31); /* THALIA_INT_BYPASS */ + + sysc_write(ddata, offset, val); +} + /* Watchdog timer needs a disable sequence after reset */ static void sysc_reset_done_quirk_wdt(struct sysc *ddata) { @@ -1465,6 +1471,9 @@ static void sysc_init_module_quirks(struct sysc *ddata) return; } + if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX) + ddata->module_enable_quirk = sysc_module_enable_quirk_sgx; + if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_WDT) ddata->reset_done_quirk = sysc_reset_done_quirk_wdt; } @@ -1531,7 +1540,7 @@ static int sysc_legacy_init(struct sysc *ddata) */ static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset) { - int error, val; + int error; if (!ddata->rsts) return 0; @@ -1542,14 +1551,9 @@ static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset) return error; } - error = reset_control_deassert(ddata->rsts); - if (error == -EEXIST) - return 0; + reset_control_deassert(ddata->rsts); - error = readx_poll_timeout(reset_control_status, ddata->rsts, val, - val == 0, 100, MAX_MODULE_SOFTRESET_WAIT); - - return error; + return 0; } /* @@ -1558,12 +1562,11 @@ static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset) */ static int sysc_reset(struct sysc *ddata) { - int sysc_offset, syss_offset, sysc_val, rstval, quirks, error = 0; + int sysc_offset, syss_offset, sysc_val, rstval, error = 0; u32 sysc_mask, syss_done; sysc_offset = ddata->offsets[SYSC_SYSCONFIG]; syss_offset = ddata->offsets[SYSC_SYSSTATUS]; - quirks = ddata->cfg.quirks; if (ddata->legacy_mode || sysc_offset < 0 || ddata->cap->regbits->srst_shift < 0 || @@ -1692,10 +1695,7 @@ static int sysc_init_sysc_mask(struct sysc *ddata) if (error) return 0; - if (val) - ddata->cfg.sysc_val = val & ddata->cap->sysc_mask; - else - ddata->cfg.sysc_val = ddata->cap->sysc_mask; + ddata->cfg.sysc_val = val & ddata->cap->sysc_mask; return 0; } @@ -2385,27 +2385,27 @@ static int sysc_probe(struct platform_device *pdev) error = sysc_init_dts_quirks(ddata); if (error) - goto unprepare; + return error; error = sysc_map_and_check_registers(ddata); if (error) - goto unprepare; + return error; error = sysc_init_sysc_mask(ddata); if (error) - goto unprepare; + return error; error = sysc_init_idlemodes(ddata); if (error) - goto unprepare; + return error; error = sysc_init_syss_mask(ddata); if (error) - goto unprepare; + return error; error = sysc_init_pdata(ddata); if (error) - goto unprepare; + return error; sysc_init_early_quirks(ddata); @@ -2415,7 +2415,7 @@ static int sysc_probe(struct platform_device *pdev) error = sysc_init_resets(ddata); if (error) - return error; + goto unprepare; error = sysc_init_module(ddata); if (error) @@ -2429,6 +2429,10 @@ static int sysc_probe(struct platform_device *pdev) goto unprepare; } + /* Balance reset counts */ + if (ddata->rsts) + reset_control_assert(ddata->rsts); + sysc_show_registers(ddata); ddata->dev->type = &sysc_device_type; @@ -2448,9 +2452,6 @@ static int sysc_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); } - if (!of_get_available_child_count(ddata->dev->of_node)) - ddata->disable_on_idle = true; - return 0; err: |