From 0273612cb845932f3086ceb7f6c7b43a8a338ae7 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 10 Sep 2012 20:29:13 -0400 Subject: [PATCH 001/148] ARM: davinci: da8xx_register_spi() should not register SPI board info Without this patch, da8xx_register_spi() registers the SPI board info, the SPI controller, and sets its number of chipselect to the size of the static spi_board_info array. This is bad because a SPI board info may declare devices for different SPI buses, and because other code can also call spi_register_board_info() (e.g. a daughter board might provide additional SPI devices). This patch removes the spi_register_board_info() call from da8xx_register_spi(), renames this last one to da8xx_register_spi_bus() to be more explicit, takes the number of chipselect as a function parameter, and updates the impacted board-da8{3,5}0-evm.c, and board-mityomapl138.c files accordingly. It also sets the SPI platform data static, as it doesn't need to be exported. Signed-off-by: Vivien Didelot [nsekhar@ti.com: fixed conflicts with v3.7-rc7, converted to use pr_warn(), modified print messages to use __func__] Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/board-da830-evm.c | 9 +++++++-- arch/arm/mach-davinci/board-da850-evm.c | 9 +++++++-- arch/arm/mach-davinci/board-mityomapl138.c | 9 +++++++-- arch/arm/mach-davinci/devices-da8xx.c | 14 +++----------- arch/arm/mach-davinci/include/mach/da8xx.h | 4 +--- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 95b5e102ceb1..f3c79bcaf31e 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -652,8 +652,13 @@ static __init void da830_evm_init(void) if (ret) pr_warning("da830_evm_init: rtc setup failed: %d\n", ret); - ret = da8xx_register_spi(0, da830evm_spi_info, - ARRAY_SIZE(da830evm_spi_info)); + ret = spi_register_board_info(da830evm_spi_info, + ARRAY_SIZE(da830evm_spi_info)); + if (ret) + pr_warn("%s: spi info registration failed: %d\n", __func__, + ret); + + ret = da8xx_register_spi_bus(0, ARRAY_SIZE(da830evm_spi_info)); if (ret) pr_warning("da830_evm_init: spi 0 registration failed: %d\n", ret); diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 0299915575a8..709607427a80 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1565,8 +1565,13 @@ static __init void da850_evm_init(void) da850_vpif_init(); - ret = da8xx_register_spi(1, da850evm_spi_info, - ARRAY_SIZE(da850evm_spi_info)); + ret = spi_register_board_info(da850evm_spi_info, + ARRAY_SIZE(da850evm_spi_info)); + if (ret) + pr_warn("%s: spi info registration failed: %d\n", __func__, + ret); + + ret = da8xx_register_spi_bus(1, ARRAY_SIZE(da850evm_spi_info)); if (ret) pr_warning("da850_evm_init: spi 1 registration failed: %d\n", ret); diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 43e4a0d663fa..5281979c0206 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -529,8 +529,13 @@ static void __init mityomapl138_init(void) mityomapl138_setup_nand(); - ret = da8xx_register_spi(1, mityomapl138_spi_flash_info, - ARRAY_SIZE(mityomapl138_spi_flash_info)); + ret = spi_register_board_info(mityomapl138_spi_flash_info, + ARRAY_SIZE(mityomapl138_spi_flash_info)); + if (ret) + pr_warn("spi info registration failed: %d\n", ret); + + ret = da8xx_register_spi_bus(1, + ARRAY_SIZE(mityomapl138_spi_flash_info)); if (ret) pr_warning("spi 1 registration failed: %d\n", ret); diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 2d5502d84a22..30da05f22ef4 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -832,7 +832,7 @@ static struct resource da8xx_spi1_resources[] = { }, }; -struct davinci_spi_platform_data da8xx_spi_pdata[] = { +static struct davinci_spi_platform_data da8xx_spi_pdata[] = { [0] = { .version = SPI_VERSION_2, .intr_line = 1, @@ -866,20 +866,12 @@ static struct platform_device da8xx_spi_device[] = { }, }; -int __init da8xx_register_spi(int instance, const struct spi_board_info *info, - unsigned len) +int __init da8xx_register_spi_bus(int instance, unsigned num_chipselect) { - int ret; - if (instance < 0 || instance > 1) return -EINVAL; - ret = spi_register_board_info(info, len); - if (ret) - pr_warning("%s: failed to register board info for spi %d :" - " %d\n", __func__, instance, ret); - - da8xx_spi_pdata[instance].num_chipselect = len; + da8xx_spi_pdata[instance].num_chipselect = num_chipselect; if (instance == 1 && cpu_is_davinci_da850()) { da8xx_spi1_resources[0].start = DA850_SPI1_BASE; diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 700d311c6854..1b14aea40310 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -82,8 +82,7 @@ void __init da850_init(void); int da830_register_edma(struct edma_rsv_info *rsv); int da850_register_edma(struct edma_rsv_info *rsv[2]); int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata); -int da8xx_register_spi(int instance, - const struct spi_board_info *info, unsigned len); +int da8xx_register_spi_bus(int instance, unsigned num_chipselect); int da8xx_register_watchdog(void); int da8xx_register_usb20(unsigned mA, unsigned potpgt); int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata); @@ -110,7 +109,6 @@ extern struct platform_device da8xx_serial_device; extern struct emac_platform_data da8xx_emac_pdata; extern struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata; extern struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata; -extern struct davinci_spi_platform_data da8xx_spi_pdata[]; extern struct platform_device da8xx_wdt_device; From 8d31bfa551b9a1a61119e6d8fde08d0fa8cdfafb Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Sat, 12 Jan 2013 15:51:24 +1300 Subject: [PATCH 002/148] arm: vt8500: Add support for Wondermedia WM8750/WM8850 This patch adds support for the WM8750 (ARMv6) and WM8850 (ARMv7). Devicetree documentation is updated for new SoCs. Signed-off-by: Tony Prisk --- Documentation/devicetree/bindings/arm/vt8500.txt | 8 ++++++++ arch/arm/mach-vt8500/Kconfig | 16 ++++++++++++++++ arch/arm/mach-vt8500/vt8500.c | 2 ++ 3 files changed, 26 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/vt8500.txt b/Documentation/devicetree/bindings/arm/vt8500.txt index d657832c6819..87dc1ddf4770 100644 --- a/Documentation/devicetree/bindings/arm/vt8500.txt +++ b/Documentation/devicetree/bindings/arm/vt8500.txt @@ -12,3 +12,11 @@ compatible = "wm,wm8505"; Boards with the Wondermedia WM8650 SoC shall have the following properties: Required root node property: compatible = "wm,wm8650"; + +Boards with the Wondermedia WM8750 SoC shall have the following properties: +Required root node property: +compatible = "wm,wm8750"; + +Boards with the Wondermedia WM8850 SoC shall have the following properties: +Required root node property: +compatible = "wm,wm8850"; diff --git a/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig index cdcc4329b4a8..747aa14d0475 100644 --- a/arch/arm/mach-vt8500/Kconfig +++ b/arch/arm/mach-vt8500/Kconfig @@ -15,3 +15,19 @@ config ARCH_WM8505 select ARCH_VT8500 select CPU_ARM926T help + +config ARCH_WM8750 + bool "WonderMedia WM8750" + depends on ARCH_MULTI_V6 + select ARCH_VT8500 + select CPU_V6 + help + Support for WonderMedia WM8750 System-on-Chip. + +config ARCH_WM8850 + bool "WonderMedia WM8850" + depends on ARCH_MULTI_V7 + select ARCH_VT8500 + select CPU_V7 + help + Support for WonderMedia WM8850 System-on-Chip. diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c index 3c66d48ea082..55162ab1a943 100644 --- a/arch/arm/mach-vt8500/vt8500.c +++ b/arch/arm/mach-vt8500/vt8500.c @@ -183,6 +183,8 @@ static const char * const vt8500_dt_compat[] = { "via,vt8500", "wm,wm8650", "wm,wm8505", + "wm,wm8750", + "wm,wm8850", }; DT_MACHINE_START(WMT_DT, "VIA/Wondermedia SoC (Device Tree Support)") From 526d239c301e6cb7fe6657642c43d6c524590745 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 24 Dec 2012 21:55:01 -0700 Subject: [PATCH 003/148] clk: bcm2835: probe for fixed-clock in device tree This will allow fixed-clocks to be registered in device tree, which in turn will allow clock clients to look up their clocks in device tree. The first driver to use this feature will be the bcm2835 SDHCI/MMC driver. In the long run, it is likely these fixed clocks will be replaced with an actual clock implementation which speaks to the VideoCore processor, but this change should be transparent to clock consumers. Cc: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/clk-bcm2835.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c index e69991aab43a..792bc57a9db7 100644 --- a/drivers/clk/clk-bcm2835.c +++ b/drivers/clk/clk-bcm2835.c @@ -20,6 +20,13 @@ #include #include #include +#include +#include + +static const __initconst struct of_device_id clk_match[] = { + { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, + { } +}; /* * These are fixed clocks. They're probably not all root clocks and it may @@ -56,4 +63,6 @@ void __init bcm2835_init_clocks(void) ret = clk_register_clkdev(clk, NULL, "20215000.uart"); if (ret) pr_err("uart1_pclk alias not registered\n"); + + of_clk_init(clk_match); } From 45e9d77a22b7b25373c7b8c0ea0b146168025360 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Sat, 27 Oct 2012 21:14:50 -0600 Subject: [PATCH 004/148] ARM: bcm2835: add a pm_power_off implementation Add a pm_power_off function that resets the SoC, and indicates to bootcode.bin not to boot. Should allow a lower power 'off' state, even if it's not really off. This is commit 48efdd2 "Add a pm_power_off function that resets us, ..." downstream. Signed-off-by: Dom Cobley [swarren: Various non-semantic rework for upstreaming] Signed-off-by: Stephen Warren --- arch/arm/mach-bcm2835/bcm2835.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm/mach-bcm2835/bcm2835.c b/arch/arm/mach-bcm2835/bcm2835.c index f0d739f4b7a3..c867d0e8cf7c 100644 --- a/arch/arm/mach-bcm2835/bcm2835.c +++ b/arch/arm/mach-bcm2835/bcm2835.c @@ -26,11 +26,13 @@ #include #define PM_RSTC 0x1c +#define PM_RSTS 0x20 #define PM_WDOG 0x24 #define PM_PASSWORD 0x5a000000 #define PM_RSTC_WRCFG_MASK 0x00000030 #define PM_RSTC_WRCFG_FULL_RESET 0x00000020 +#define PM_RSTS_HADWRH_SET 0x00000040 static void __iomem *wdt_regs; @@ -67,6 +69,29 @@ static void bcm2835_restart(char mode, const char *cmd) mdelay(1); } +/* + * We can't really power off, but if we do the normal reset scheme, and + * indicate to bootcode.bin not to reboot, then most of the chip will be + * powered off. + */ +static void bcm2835_power_off(void) +{ + u32 val; + + /* + * We set the watchdog hard reset bit here to distinguish this reset + * from the normal (full) reset. bootcode.bin will not reboot after a + * hard reset. + */ + val = readl_relaxed(wdt_regs + PM_RSTS); + val &= ~PM_RSTC_WRCFG_MASK; + val |= PM_PASSWORD | PM_RSTS_HADWRH_SET; + writel_relaxed(val, wdt_regs + PM_RSTS); + + /* Continue with normal reset mechanism */ + bcm2835_restart(0, ""); +} + static struct map_desc io_map __initdata = { .virtual = BCM2835_PERIPH_VIRT, .pfn = __phys_to_pfn(BCM2835_PERIPH_PHYS), @@ -84,6 +109,9 @@ static void __init bcm2835_init(void) int ret; bcm2835_setup_restart(); + if (wdt_regs) + pm_power_off = bcm2835_power_off; + bcm2835_init_clocks(); ret = of_platform_populate(NULL, of_default_bus_match_table, NULL, From d2e0c18a9751229b31bf9bc7a5c1b9ab4a7a9651 Mon Sep 17 00:00:00 2001 From: Robert Tivy Date: Thu, 10 Jan 2013 16:23:20 -0800 Subject: [PATCH 005/148] ARM: davinci: devices-da8xx.c: change pr_warning() to pr_warn() Changed all pr_warning() calls to pr_warn(), as advised by checkpatch.pl. Signed-off-by: Robert Tivy Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/devices-da8xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 30da05f22ef4..aa402bc160c8 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -751,7 +751,7 @@ void __iomem * __init da8xx_get_mem_ctlr(void) da8xx_ddr2_ctlr_base = ioremap(DA8XX_DDR2_CTL_BASE, SZ_32K); if (!da8xx_ddr2_ctlr_base) - pr_warning("%s: Unable to map DDR2 controller", __func__); + pr_warn("%s: Unable to map DDR2 controller", __func__); return da8xx_ddr2_ctlr_base; } From 35031f9df569913ac0c46b03c8033fc1deed749d Mon Sep 17 00:00:00 2001 From: Robert Tivy Date: Thu, 10 Jan 2013 16:23:21 -0800 Subject: [PATCH 006/148] ARM: davinci: psc.c: change pr_warning() to pr_warn() Change all pr_warning() calls to pr_warn(), as advised by checkpatch.pl. Signed-off-by: Robert Tivy Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/psc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c index d7e210f4b55c..bddaba9628e1 100644 --- a/arch/arm/mach-davinci/psc.c +++ b/arch/arm/mach-davinci/psc.c @@ -35,7 +35,7 @@ int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id) struct davinci_soc_info *soc_info = &davinci_soc_info; if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { - pr_warning("PSC: Bad psc data: 0x%x[%d]\n", + pr_warn("PSC: Bad psc data: 0x%x[%d]\n", (int)soc_info->psc_bases, ctlr); return 0; } @@ -58,7 +58,7 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, u32 next_state = PSC_STATE_ENABLE; if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { - pr_warning("PSC: Bad psc data: 0x%x[%d]\n", + pr_warn("PSC: Bad psc data: 0x%x[%d]\n", (int)soc_info->psc_bases, ctlr); return; } From def4d6c044ea1f5f58ed6d422e6797fb0b1cfb63 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Sat, 19 Jan 2013 19:44:28 +1300 Subject: [PATCH 007/148] dts: vt8500: Add initial dts support for WM8850 This patch adds a soc dtsi for the Wondermedia WM8850. A board dts file is also included for the W70v2 tablet, with support for all the drivers currently in mainline. Signed-off-by: Tony Prisk Signed-off-by: Olof Johansson --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/wm8850-w70v2.dts | 47 ++++++ arch/arm/boot/dts/wm8850.dtsi | 224 +++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/wm8850-w70v2.dts create mode 100644 arch/arm/boot/dts/wm8850.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index e44da40d984f..3212573b94e7 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -151,7 +151,8 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ xenvm-4.2.dtb dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ wm8505-ref.dtb \ - wm8650-mid.dtb + wm8650-mid.dtb \ + wm8850-w70v2.dtb dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb targets += dtbs diff --git a/arch/arm/boot/dts/wm8850-w70v2.dts b/arch/arm/boot/dts/wm8850-w70v2.dts new file mode 100644 index 000000000000..fcc660c89540 --- /dev/null +++ b/arch/arm/boot/dts/wm8850-w70v2.dts @@ -0,0 +1,47 @@ +/* + * wm8850-w70v2.dts + * - Device tree file for Wondermedia WM8850 Tablet + * - 'W70-V2' mainboard + * - HongLianYing 'HLY070ML268-21A' 7" LCD panel + * + * Copyright (C) 2012 Tony Prisk + * + * Licensed under GPLv2 or later + */ + +/dts-v1/; +/include/ "wm8850.dtsi" + +/ { + model = "Wondermedia WM8850-W70v2 Tablet"; + + /* + * Display node is based on Sascha Hauer's patch on dri-devel. + * Added a bpp property to calculate the size of the framebuffer + * until the binding is formalized. + */ + display: display@0 { + modes { + mode0: mode@0 { + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hfront-porch = <40>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + clock = <0>; /* unused but required */ + bpp = <16>; /* non-standard but required */ + }; + }; + }; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 50000 1>; /* duty inverted */ + + brightness-levels = <0 40 60 80 100 130 190 255>; + default-brightness-level = <5>; + }; +}; diff --git a/arch/arm/boot/dts/wm8850.dtsi b/arch/arm/boot/dts/wm8850.dtsi new file mode 100644 index 000000000000..e8cbfdc87bba --- /dev/null +++ b/arch/arm/boot/dts/wm8850.dtsi @@ -0,0 +1,224 @@ +/* + * wm8850.dtsi - Device tree file for Wondermedia WM8850 SoC + * + * Copyright (C) 2012 Tony Prisk + * + * Licensed under GPLv2 or later + */ + +/include/ "skeleton.dtsi" + +/ { + compatible = "wm,wm8850"; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + interrupt-parent = <&intc0>; + + intc0: interrupt-controller@d8140000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + reg = <0xd8140000 0x10000>; + #interrupt-cells = <1>; + }; + + /* Secondary IC cascaded to intc0 */ + intc1: interrupt-controller@d8150000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xD8150000 0x10000>; + interrupts = <56 57 58 59 60 61 62 63>; + }; + + gpio: gpio-controller@d8110000 { + compatible = "wm,wm8650-gpio"; + gpio-controller; + reg = <0xd8110000 0x10000>; + #gpio-cells = <3>; + }; + + pmc@d8130000 { + compatible = "via,vt8500-pmc"; + reg = <0xd8130000 0x1000>; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + ref25: ref25M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + ref24: ref24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + plla: plla { + #clock-cells = <0>; + compatible = "wm,wm8750-pll-clock"; + clocks = <&ref25>; + reg = <0x200>; + }; + + pllb: pllb { + #clock-cells = <0>; + compatible = "wm,wm8750-pll-clock"; + clocks = <&ref25>; + reg = <0x204>; + }; + + clkuart0: uart0 { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&ref24>; + enable-reg = <0x254>; + enable-bit = <24>; + }; + + clkuart1: uart1 { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&ref24>; + enable-reg = <0x254>; + enable-bit = <25>; + }; + + clkuart2: uart2 { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&ref24>; + enable-reg = <0x254>; + enable-bit = <26>; + }; + + clkuart3: uart3 { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&ref24>; + enable-reg = <0x254>; + enable-bit = <27>; + }; + + clkpwm: pwm { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&pllb>; + divisor-reg = <0x350>; + enable-reg = <0x250>; + enable-bit = <17>; + }; + + clksdhc: sdhc { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&pllb>; + divisor-reg = <0x330>; + divisor-mask = <0x3f>; + enable-reg = <0x250>; + enable-bit = <0>; + }; + }; + }; + + fb@d8051700 { + compatible = "wm,wm8505-fb"; + reg = <0xd8051700 0x200>; + display = <&display>; + default-mode = <&mode0>; + }; + + ge_rops@d8050400 { + compatible = "wm,prizm-ge-rops"; + reg = <0xd8050400 0x100>; + }; + + pwm: pwm@d8220000 { + #pwm-cells = <3>; + compatible = "via,vt8500-pwm"; + reg = <0xd8220000 0x100>; + clocks = <&clkpwm>; + }; + + timer@d8130100 { + compatible = "via,vt8500-timer"; + reg = <0xd8130100 0x28>; + interrupts = <36>; + }; + + ehci@d8007900 { + compatible = "via,vt8500-ehci"; + reg = <0xd8007900 0x200>; + interrupts = <26>; + }; + + uhci@d8007b00 { + compatible = "platform-uhci"; + reg = <0xd8007b00 0x200>; + interrupts = <26>; + }; + + uhci@d8008d00 { + compatible = "platform-uhci"; + reg = <0xd8008d00 0x200>; + interrupts = <26>; + }; + + uart0: uart@d8200000 { + compatible = "via,vt8500-uart"; + reg = <0xd8200000 0x1040>; + interrupts = <32>; + clocks = <&clkuart0>; + }; + + uart1: uart@d82b0000 { + compatible = "via,vt8500-uart"; + reg = <0xd82b0000 0x1040>; + interrupts = <33>; + clocks = <&clkuart1>; + }; + + uart2: uart@d8210000 { + compatible = "via,vt8500-uart"; + reg = <0xd8210000 0x1040>; + interrupts = <47>; + clocks = <&clkuart2>; + }; + + uart3: uart@d82c0000 { + compatible = "via,vt8500-uart"; + reg = <0xd82c0000 0x1040>; + interrupts = <50>; + clocks = <&clkuart3>; + }; + + rtc@d8100000 { + compatible = "via,vt8500-rtc"; + reg = <0xd8100000 0x10000>; + interrupts = <48>; + }; + + sdhc@d800a000 { + compatible = "wm,wm8505-sdhc"; + reg = <0xd800a000 0x1000>; + interrupts = <20 21>; + clocks = <&clksdhc>; + bus-width = <4>; + sdon-inverted; + }; + }; +}; From 09180e5b4e673a92f1a8f47061948f524ceba8df Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 17:07:38 +0800 Subject: [PATCH 008/148] ARM: PRIMA2: add CSR SiRFmarco device tree .dts SiRFmarco is a dual-core cortex-a9 SMP SoC from CSR. this patch adds the .dtsi and a basic evb board .dts for it. Signed-off-by: Barry Song Reviewed-by: Mark Rutland --- .../devicetree/bindings/arm/sirf.txt | 10 +- arch/arm/boot/dts/marco-evb.dts | 54 ++ arch/arm/boot/dts/marco.dtsi | 756 ++++++++++++++++++ 3 files changed, 818 insertions(+), 2 deletions(-) create mode 100644 arch/arm/boot/dts/marco-evb.dts create mode 100644 arch/arm/boot/dts/marco.dtsi diff --git a/Documentation/devicetree/bindings/arm/sirf.txt b/Documentation/devicetree/bindings/arm/sirf.txt index 1881e1c6dda5..c6ba6d3c747f 100644 --- a/Documentation/devicetree/bindings/arm/sirf.txt +++ b/Documentation/devicetree/bindings/arm/sirf.txt @@ -1,3 +1,9 @@ -prima2 "cb" evaluation board +CSR SiRFprimaII and SiRFmarco device tree bindings. +======================================== + Required root node properties: - - compatible = "sirf,prima2-cb", "sirf,prima2"; + - compatible: + - "sirf,prima2-cb" : prima2 "cb" evaluation board + - "sirf,marco-cb" : marco "cb" evaluation board + - "sirf,prima2" : prima2 device based board + - "sirf,marco" : marco device based board diff --git a/arch/arm/boot/dts/marco-evb.dts b/arch/arm/boot/dts/marco-evb.dts new file mode 100644 index 000000000000..5130aeacfca5 --- /dev/null +++ b/arch/arm/boot/dts/marco-evb.dts @@ -0,0 +1,54 @@ +/* + * DTS file for CSR SiRFmarco Evaluation Board + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +/dts-v1/; + +/include/ "marco.dtsi" + +/ { + model = "CSR SiRFmarco Evaluation Board"; + compatible = "sirf,marco-cb", "sirf,marco"; + + memory { + reg = <0x40000000 0x60000000>; + }; + + axi { + peri-iobg { + uart1: uart@cc060000 { + status = "okay"; + }; + uart2: uart@cc070000 { + status = "okay"; + }; + i2c0: i2c@cc0e0000 { + status = "okay"; + fpga-cpld@4d { + compatible = "sirf,fpga-cpld"; + reg = <0x4d>; + }; + }; + spi1: spi@cc170000 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins_a>; + spi@0 { + compatible = "spidev"; + reg = <0>; + spi-max-frequency = <1000000>; + }; + }; + pci-iobg { + sd0: sdhci@cd000000 { + bus-width = <8>; + status = "okay"; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/marco.dtsi b/arch/arm/boot/dts/marco.dtsi new file mode 100644 index 000000000000..1579c3491ccd --- /dev/null +++ b/arch/arm/boot/dts/marco.dtsi @@ -0,0 +1,756 @@ +/* + * DTS file for CSR SiRFmarco SoC + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +/include/ "skeleton.dtsi" +/ { + compatible = "sirf,marco"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <1>; + }; + }; + + axi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x40000000 0xa0000000>; + + l2-cache-controller@c0030000 { + compatible = "sirf,marco-pl310-cache", "arm,pl310-cache"; + reg = <0xc0030000 0x1000>; + interrupts = <0 59 0>; + arm,tag-latency = <1 1 1>; + arm,data-latency = <1 1 1>; + arm,filter-ranges = <0x40000000 0x80000000>; + }; + + gic: interrupt-controller@c0011000 { + compatible = "arm,cortex-a9-gic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0xc0011000 0x1000>, + <0xc0010100 0x0100>; + }; + + rstc-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc2000000 0xc2000000 0x1000000>; + + reset-controller@c2000000 { + compatible = "sirf,marco-rstc"; + reg = <0xc2000000 0x10000>; + }; + }; + + sys-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc3000000 0xc3000000 0x1000000>; + + clock-controller@c3000000 { + compatible = "sirf,marco-clkc"; + reg = <0xc3000000 0x1000>; + interrupts = <0 3 0>; + }; + + rsc-controller@c3010000 { + compatible = "sirf,marco-rsc"; + reg = <0xc3010000 0x1000>; + }; + }; + + mem-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc4000000 0xc4000000 0x1000000>; + + memory-controller@c4000000 { + compatible = "sirf,marco-memc"; + reg = <0xc4000000 0x10000>; + interrupts = <0 27 0>; + }; + }; + + disp-iobg0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc5000000 0xc5000000 0x1000000>; + + display0@c5000000 { + compatible = "sirf,marco-lcd"; + reg = <0xc5000000 0x10000>; + interrupts = <0 30 0>; + }; + + vpp0@c5010000 { + compatible = "sirf,marco-vpp"; + reg = <0xc5010000 0x10000>; + interrupts = <0 31 0>; + }; + }; + + disp-iobg1 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc6000000 0xc6000000 0x1000000>; + + display1@c6000000 { + compatible = "sirf,marco-lcd"; + reg = <0xc6000000 0x10000>; + interrupts = <0 62 0>; + }; + + vpp1@c6010000 { + compatible = "sirf,marco-vpp"; + reg = <0xc6010000 0x10000>; + interrupts = <0 63 0>; + }; + }; + + graphics-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc8000000 0xc8000000 0x1000000>; + + graphics@c8000000 { + compatible = "powervr,sgx540"; + reg = <0xc8000000 0x1000000>; + interrupts = <0 6 0>; + }; + }; + + multimedia-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc9000000 0xc9000000 0x1000000>; + + multimedia@a0000000 { + compatible = "sirf,marco-video-codec"; + reg = <0xc9000000 0x1000000>; + interrupts = <0 5 0>; + }; + }; + + dsp-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xca000000 0xca000000 0x2000000>; + + dspif@ca000000 { + compatible = "sirf,marco-dspif"; + reg = <0xca000000 0x10000>; + interrupts = <0 9 0>; + }; + + gps@ca010000 { + compatible = "sirf,marco-gps"; + reg = <0xca010000 0x10000>; + interrupts = <0 7 0>; + }; + + dsp@cb000000 { + compatible = "sirf,marco-dsp"; + reg = <0xcb000000 0x1000000>; + interrupts = <0 8 0>; + }; + }; + + peri-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xcc000000 0xcc000000 0x2000000>; + + timer@cc020000 { + compatible = "sirf,marco-tick"; + reg = <0xcc020000 0x1000>; + interrupts = <0 0 0>, + <0 1 0>, + <0 2 0>, + <0 49 0>, + <0 50 0>, + <0 51 0>; + }; + + nand@cc030000 { + compatible = "sirf,marco-nand"; + reg = <0xcc030000 0x10000>; + interrupts = <0 41 0>; + }; + + audio@cc040000 { + compatible = "sirf,marco-audio"; + reg = <0xcc040000 0x10000>; + interrupts = <0 35 0>; + }; + + uart0: uart@cc050000 { + cell-index = <0>; + compatible = "sirf,marco-uart"; + reg = <0xcc050000 0x1000>; + interrupts = <0 17 0>; + fifosize = <128>; + status = "disabled"; + }; + + uart1: uart@cc060000 { + cell-index = <1>; + compatible = "sirf,marco-uart"; + reg = <0xcc060000 0x1000>; + interrupts = <0 18 0>; + fifosize = <32>; + status = "disabled"; + }; + + uart2: uart@cc070000 { + cell-index = <2>; + compatible = "sirf,marco-uart"; + reg = <0xcc070000 0x1000>; + interrupts = <0 19 0>; + fifosize = <128>; + status = "disabled"; + }; + + uart3: uart@cc190000 { + cell-index = <3>; + compatible = "sirf,marco-uart"; + reg = <0xcc190000 0x1000>; + interrupts = <0 66 0>; + fifosize = <128>; + status = "disabled"; + }; + + uart4: uart@cc1a0000 { + cell-index = <4>; + compatible = "sirf,marco-uart"; + reg = <0xcc1a0000 0x1000>; + interrupts = <0 69 0>; + fifosize = <128>; + status = "disabled"; + }; + + usp0: usp@cc080000 { + cell-index = <0>; + compatible = "sirf,marco-usp"; + reg = <0xcc080000 0x10000>; + interrupts = <0 20 0>; + status = "disabled"; + }; + + usp1: usp@cc090000 { + cell-index = <1>; + compatible = "sirf,marco-usp"; + reg = <0xcc090000 0x10000>; + interrupts = <0 21 0>; + status = "disabled"; + }; + + usp2: usp@cc0a0000 { + cell-index = <2>; + compatible = "sirf,marco-usp"; + reg = <0xcc0a0000 0x10000>; + interrupts = <0 22 0>; + status = "disabled"; + }; + + dmac0: dma-controller@cc0b0000 { + cell-index = <0>; + compatible = "sirf,marco-dmac"; + reg = <0xcc0b0000 0x10000>; + interrupts = <0 12 0>; + }; + + dmac1: dma-controller@cc160000 { + cell-index = <1>; + compatible = "sirf,marco-dmac"; + reg = <0xcc160000 0x10000>; + interrupts = <0 13 0>; + }; + + vip@cc0c0000 { + compatible = "sirf,marco-vip"; + reg = <0xcc0c0000 0x10000>; + }; + + spi0: spi@cc0d0000 { + cell-index = <0>; + compatible = "sirf,marco-spi"; + reg = <0xcc0d0000 0x10000>; + interrupts = <0 15 0>; + sirf,spi-num-chipselects = <1>; + cs-gpios = <&gpio 0 0>; + sirf,spi-dma-rx-channel = <25>; + sirf,spi-dma-tx-channel = <20>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@cc170000 { + cell-index = <1>; + compatible = "sirf,marco-spi"; + reg = <0xcc170000 0x10000>; + interrupts = <0 16 0>; + sirf,spi-num-chipselects = <1>; + cs-gpios = <&gpio 0 0>; + sirf,spi-dma-rx-channel = <12>; + sirf,spi-dma-tx-channel = <13>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c0: i2c@cc0e0000 { + cell-index = <0>; + compatible = "sirf,marco-i2c"; + reg = <0xcc0e0000 0x10000>; + interrupts = <0 24 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@cc0f0000 { + cell-index = <1>; + compatible = "sirf,marco-i2c"; + reg = <0xcc0f0000 0x10000>; + interrupts = <0 25 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + tsc@cc110000 { + compatible = "sirf,marco-tsc"; + reg = <0xcc110000 0x10000>; + interrupts = <0 33 0>; + }; + + gpio: pinctrl@cc120000 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "sirf,marco-pinctrl"; + reg = <0xcc120000 0x10000>; + interrupts = <0 43 0>, + <0 44 0>, + <0 45 0>, + <0 46 0>, + <0 47 0>; + gpio-controller; + interrupt-controller; + + lcd_16pins_a: lcd0_0 { + lcd { + sirf,pins = "lcd_16bitsgrp"; + sirf,function = "lcd_16bits"; + }; + }; + lcd_18pins_a: lcd0_1 { + lcd { + sirf,pins = "lcd_18bitsgrp"; + sirf,function = "lcd_18bits"; + }; + }; + lcd_24pins_a: lcd0_2 { + lcd { + sirf,pins = "lcd_24bitsgrp"; + sirf,function = "lcd_24bits"; + }; + }; + lcdrom_pins_a: lcdrom0_0 { + lcd { + sirf,pins = "lcdromgrp"; + sirf,function = "lcdrom"; + }; + }; + uart0_pins_a: uart0_0 { + uart { + sirf,pins = "uart0grp"; + sirf,function = "uart0"; + }; + }; + uart1_pins_a: uart1_0 { + uart { + sirf,pins = "uart1grp"; + sirf,function = "uart1"; + }; + }; + uart2_pins_a: uart2_0 { + uart { + sirf,pins = "uart2grp"; + sirf,function = "uart2"; + }; + }; + uart2_noflow_pins_a: uart2_1 { + uart { + sirf,pins = "uart2_nostreamctrlgrp"; + sirf,function = "uart2_nostreamctrl"; + }; + }; + spi0_pins_a: spi0_0 { + spi { + sirf,pins = "spi0grp"; + sirf,function = "spi0"; + }; + }; + spi1_pins_a: spi1_0 { + spi { + sirf,pins = "spi1grp"; + sirf,function = "spi1"; + }; + }; + i2c0_pins_a: i2c0_0 { + i2c { + sirf,pins = "i2c0grp"; + sirf,function = "i2c0"; + }; + }; + i2c1_pins_a: i2c1_0 { + i2c { + sirf,pins = "i2c1grp"; + sirf,function = "i2c1"; + }; + }; + pwm0_pins_a: pwm0_0 { + pwm { + sirf,pins = "pwm0grp"; + sirf,function = "pwm0"; + }; + }; + pwm1_pins_a: pwm1_0 { + pwm { + sirf,pins = "pwm1grp"; + sirf,function = "pwm1"; + }; + }; + pwm2_pins_a: pwm2_0 { + pwm { + sirf,pins = "pwm2grp"; + sirf,function = "pwm2"; + }; + }; + pwm3_pins_a: pwm3_0 { + pwm { + sirf,pins = "pwm3grp"; + sirf,function = "pwm3"; + }; + }; + gps_pins_a: gps_0 { + gps { + sirf,pins = "gpsgrp"; + sirf,function = "gps"; + }; + }; + vip_pins_a: vip_0 { + vip { + sirf,pins = "vipgrp"; + sirf,function = "vip"; + }; + }; + sdmmc0_pins_a: sdmmc0_0 { + sdmmc0 { + sirf,pins = "sdmmc0grp"; + sirf,function = "sdmmc0"; + }; + }; + sdmmc1_pins_a: sdmmc1_0 { + sdmmc1 { + sirf,pins = "sdmmc1grp"; + sirf,function = "sdmmc1"; + }; + }; + sdmmc2_pins_a: sdmmc2_0 { + sdmmc2 { + sirf,pins = "sdmmc2grp"; + sirf,function = "sdmmc2"; + }; + }; + sdmmc3_pins_a: sdmmc3_0 { + sdmmc3 { + sirf,pins = "sdmmc3grp"; + sirf,function = "sdmmc3"; + }; + }; + sdmmc4_pins_a: sdmmc4_0 { + sdmmc4 { + sirf,pins = "sdmmc4grp"; + sirf,function = "sdmmc4"; + }; + }; + sdmmc5_pins_a: sdmmc5_0 { + sdmmc5 { + sirf,pins = "sdmmc5grp"; + sirf,function = "sdmmc5"; + }; + }; + i2s_pins_a: i2s_0 { + i2s { + sirf,pins = "i2sgrp"; + sirf,function = "i2s"; + }; + }; + ac97_pins_a: ac97_0 { + ac97 { + sirf,pins = "ac97grp"; + sirf,function = "ac97"; + }; + }; + nand_pins_a: nand_0 { + nand { + sirf,pins = "nandgrp"; + sirf,function = "nand"; + }; + }; + usp0_pins_a: usp0_0 { + usp0 { + sirf,pins = "usp0grp"; + sirf,function = "usp0"; + }; + }; + usp1_pins_a: usp1_0 { + usp1 { + sirf,pins = "usp1grp"; + sirf,function = "usp1"; + }; + }; + usp2_pins_a: usp2_0 { + usp2 { + sirf,pins = "usp2grp"; + sirf,function = "usp2"; + }; + }; + usb0_utmi_drvbus_pins_a: usb0_utmi_drvbus_0 { + usb0_utmi_drvbus { + sirf,pins = "usb0_utmi_drvbusgrp"; + sirf,function = "usb0_utmi_drvbus"; + }; + }; + usb1_utmi_drvbus_pins_a: usb1_utmi_drvbus_0 { + usb1_utmi_drvbus { + sirf,pins = "usb1_utmi_drvbusgrp"; + sirf,function = "usb1_utmi_drvbus"; + }; + }; + warm_rst_pins_a: warm_rst_0 { + warm_rst { + sirf,pins = "warm_rstgrp"; + sirf,function = "warm_rst"; + }; + }; + pulse_count_pins_a: pulse_count_0 { + pulse_count { + sirf,pins = "pulse_countgrp"; + sirf,function = "pulse_count"; + }; + }; + cko0_rst_pins_a: cko0_rst_0 { + cko0_rst { + sirf,pins = "cko0_rstgrp"; + sirf,function = "cko0_rst"; + }; + }; + cko1_rst_pins_a: cko1_rst_0 { + cko1_rst { + sirf,pins = "cko1_rstgrp"; + sirf,function = "cko1_rst"; + }; + }; + }; + + pwm@cc130000 { + compatible = "sirf,marco-pwm"; + reg = <0xcc130000 0x10000>; + }; + + efusesys@cc140000 { + compatible = "sirf,marco-efuse"; + reg = <0xcc140000 0x10000>; + }; + + pulsec@cc150000 { + compatible = "sirf,marco-pulsec"; + reg = <0xcc150000 0x10000>; + interrupts = <0 48 0>; + }; + + pci-iobg { + compatible = "sirf,marco-pciiobg", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xcd000000 0xcd000000 0x1000000>; + + sd0: sdhci@cd000000 { + cell-index = <0>; + compatible = "sirf,marco-sdhc"; + reg = <0xcd000000 0x100000>; + interrupts = <0 38 0>; + status = "disabled"; + }; + + sd1: sdhci@cd100000 { + cell-index = <1>; + compatible = "sirf,marco-sdhc"; + reg = <0xcd100000 0x100000>; + interrupts = <0 38 0>; + status = "disabled"; + }; + + sd2: sdhci@cd200000 { + cell-index = <2>; + compatible = "sirf,marco-sdhc"; + reg = <0xcd200000 0x100000>; + interrupts = <0 23 0>; + status = "disabled"; + }; + + sd3: sdhci@cd300000 { + cell-index = <3>; + compatible = "sirf,marco-sdhc"; + reg = <0xcd300000 0x100000>; + interrupts = <0 23 0>; + status = "disabled"; + }; + + sd4: sdhci@cd400000 { + cell-index = <4>; + compatible = "sirf,marco-sdhc"; + reg = <0xcd400000 0x100000>; + interrupts = <0 39 0>; + status = "disabled"; + }; + + sd5: sdhci@cd500000 { + cell-index = <5>; + compatible = "sirf,marco-sdhc"; + reg = <0xcd500000 0x100000>; + interrupts = <0 39 0>; + status = "disabled"; + }; + + pci-copy@cd900000 { + compatible = "sirf,marco-pcicp"; + reg = <0xcd900000 0x100000>; + interrupts = <0 40 0>; + }; + + rom-interface@cda00000 { + compatible = "sirf,marco-romif"; + reg = <0xcda00000 0x100000>; + }; + }; + }; + + rtc-iobg { + compatible = "sirf,marco-rtciobg", "sirf-marco-rtciobg-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xc1000000 0x10000>; + + gpsrtc@1000 { + compatible = "sirf,marco-gpsrtc"; + reg = <0x1000 0x1000>; + interrupts = <0 55 0>, + <0 56 0>, + <0 57 0>; + }; + + sysrtc@2000 { + compatible = "sirf,marco-sysrtc"; + reg = <0x2000 0x1000>; + interrupts = <0 52 0>, + <0 53 0>, + <0 54 0>; + }; + + pwrc@3000 { + compatible = "sirf,marco-pwrc"; + reg = <0x3000 0x1000>; + interrupts = <0 32 0>; + }; + }; + + uus-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xce000000 0xce000000 0x1000000>; + + usb0: usb@ce000000 { + compatible = "chipidea,ci13611a-marco"; + reg = <0xce000000 0x10000>; + interrupts = <0 10 0>; + }; + + usb1: usb@ce010000 { + compatible = "chipidea,ci13611a-marco"; + reg = <0xce010000 0x10000>; + interrupts = <0 11 0>; + }; + + security@ce020000 { + compatible = "sirf,marco-security"; + reg = <0xce020000 0x10000>; + interrupts = <0 42 0>; + }; + }; + + can-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xd0000000 0xd0000000 0x1000000>; + + can0: can@d0000000 { + compatible = "sirf,marco-can"; + reg = <0xd0000000 0x10000>; + }; + + can1: can@d0010000 { + compatible = "sirf,marco-can"; + reg = <0xd0010000 0x10000>; + }; + }; + + lvds-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xd1000000 0xd1000000 0x1000000>; + + lvds@d1000000 { + compatible = "sirf,marco-lvds"; + reg = <0xd1000000 0x10000>; + interrupts = <0 64 0>; + }; + }; + }; +}; From 20ddfa9324b470764125f5ca555c315b5af13507 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 17:14:10 +0800 Subject: [PATCH 009/148] ARM: PRIMA2: enable AUTO_ZRELADDR for SIRF in Kconfig prima2 and marco have different memory base address. prima2 begins from 0 and marco begins from 0x40000000. This patch enables AUTO_ZRELADDR so that kernel can detect the physical address automatically. Signed-off-by: Barry Song CC: Mark Rutland --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index f95ba14ae3d0..13f89a262fa8 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -394,6 +394,7 @@ config ARCH_GEMINI config ARCH_SIRF bool "CSR SiRF" select ARCH_REQUIRE_GPIOLIB + select AUTO_ZRELADDR select COMMON_CLK select GENERIC_CLOCKEVENTS select GENERIC_IRQ_CHIP From ea38960fb63ab5cce2442fa88f5041bcfb1ae8e3 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 17:20:46 +0800 Subject: [PATCH 010/148] ARM: PRIMA2: initialize l2x0 according to mach from DT prima2 and marco have diffetent l2 cache configuration, so we initialize l2x0 cache based on dtb given to kernel. Signed-off-by: Barry Song Reviewed-by: Mark Rutland --- arch/arm/mach-prima2/l2x0.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c index c99837797d76..cbcbe9cb094c 100644 --- a/arch/arm/mach-prima2/l2x0.c +++ b/arch/arm/mach-prima2/l2x0.c @@ -11,19 +11,38 @@ #include #include -static struct of_device_id prima2_l2x0_ids[] = { - { .compatible = "sirf,prima2-pl310-cache" }, +struct l2x0_aux +{ + u32 val; + u32 mask; +}; + +static struct l2x0_aux prima2_l2x0_aux __initconst = { + .val = 2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT, + .mask = 0, +}; + +static struct l2x0_aux marco_l2x0_aux __initconst = { + .val = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | + (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT), + .mask = L2X0_AUX_CTRL_MASK, +}; + +static struct of_device_id sirf_l2x0_ids[] __initconst = { + { .compatible = "sirf,prima2-pl310-cache", .data = &prima2_l2x0_aux, }, + { .compatible = "sirf,marco-pl310-cache", .data = &marco_l2x0_aux, }, {}, }; static int __init sirfsoc_l2x0_init(void) { struct device_node *np; + const struct l2x0_aux *aux; - np = of_find_matching_node(NULL, prima2_l2x0_ids); + np = of_find_matching_node(NULL, sirf_l2x0_ids); if (np) { - pr_info("Initializing prima2 L2 cache\n"); - return l2x0_of_init(0x40000, 0); + aux = of_match_node(sirf_l2x0_ids, np)->data; + return l2x0_of_init(aux->val, aux->mask); } return 0; From 0d5983a62ad5749068a507e0c579af88f4753261 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 17:33:49 +0800 Subject: [PATCH 011/148] ARM: PRIMA2: mv timer to timer-prima2 as we will add timer-marco Marco timer has different timer IP with prima2, so rename the current timer to timer-prima2 so that we can add timer-marco. at the same time, if we don't find prima2 timer node in dt, don't panic the system as we will make prima2 and marco use same kernel image. Signed-off-by: Barry Song --- arch/arm/mach-prima2/Makefile | 2 +- arch/arm/mach-prima2/common.c | 2 +- arch/arm/mach-prima2/common.h | 2 +- arch/arm/mach-prima2/{timer.c => timer-prima2.c} | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) rename arch/arm/mach-prima2/{timer.c => timer-prima2.c} (98%) diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile index fc9ce22e2b5a..0007a6ec78f2 100644 --- a/arch/arm/mach-prima2/Makefile +++ b/arch/arm/mach-prima2/Makefile @@ -1,4 +1,3 @@ -obj-y := timer.o obj-y += rstc.o obj-y += common.o obj-y += rtciobrg.o @@ -6,3 +5,4 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o obj-$(CONFIG_CACHE_L2X0) += l2x0.o obj-$(CONFIG_SUSPEND) += pm.o sleep.o obj-$(CONFIG_SIRF_IRQ) += irq.o +obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c index ed3570e5eb8f..8e6f6681b546 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c @@ -40,7 +40,7 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") /* Maintainer: Barry Song */ .map_io = sirfsoc_map_lluart, .init_irq = sirfsoc_of_irq_init, - .init_time = sirfsoc_timer_init, + .init_time = sirfsoc_prima2_timer_init, .dma_zone_size = SZ_256M, .init_machine = sirfsoc_mach_init, .init_late = sirfsoc_init_late, diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index 9c75f124e3cf..d6890b6833c9 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -12,7 +12,7 @@ #include #include -extern void sirfsoc_timer_init(void); +extern void sirfsoc_prima2_timer_init(void); extern void __init sirfsoc_of_irq_init(void); extern void __init sirfsoc_of_clk_init(void); diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer-prima2.c similarity index 98% rename from arch/arm/mach-prima2/timer.c rename to arch/arm/mach-prima2/timer-prima2.c index 8c732a5beb7f..309e724735b7 100644 --- a/arch/arm/mach-prima2/timer.c +++ b/arch/arm/mach-prima2/timer-prima2.c @@ -187,7 +187,7 @@ static void __init sirfsoc_clockevent_init(void) } /* initialize the kernel jiffy timer source */ -void __init sirfsoc_timer_init(void) +void __init sirfsoc_prima2_timer_init(void) { unsigned long rate; struct clk *clk; @@ -226,14 +226,14 @@ static struct of_device_id timer_ids[] = { {}, }; -void __init sirfsoc_of_timer_map(void) +static void __init sirfsoc_of_timer_map(void) { struct device_node *np; const unsigned int *intspec; np = of_find_matching_node(NULL, timer_ids); if (!np) - panic("unable to find compatible timer node in dtb\n"); + return; sirfsoc_timer_base = of_iomap(np, 0); if (!sirfsoc_timer_base) panic("unable to map timer cpu registers\n"); From 0ecb40ca35b093aa38f8b94069b6cbd3c7a25831 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 17:40:47 +0800 Subject: [PATCH 012/148] ARM: PRIMA2: rstc: enable the support for Marco marco has SET/CLEAR registers pair for rstc to avoid read-modify-write, this patch detects the mach typer and access registers based on SoC. Signed-off-by: Barry Song --- arch/arm/mach-prima2/rstc.c | 45 +++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c index 762adb73ab7c..435019ca0a48 100644 --- a/arch/arm/mach-prima2/rstc.c +++ b/arch/arm/mach-prima2/rstc.c @@ -19,6 +19,7 @@ static DEFINE_MUTEX(rstc_lock); static struct of_device_id rstc_ids[] = { { .compatible = "sirf,prima2-rstc" }, + { .compatible = "sirf,marco-rstc" }, {}, }; @@ -42,27 +43,37 @@ early_initcall(sirfsoc_of_rstc_init); int sirfsoc_reset_device(struct device *dev) { - const unsigned int *prop = of_get_property(dev->of_node, "reset-bit", NULL); - unsigned int reset_bit; + u32 reset_bit; - if (!prop) - return -ENODEV; - - reset_bit = be32_to_cpup(prop); + if (of_property_read_u32(dev->of_node, "reset-bit", &reset_bit)) + return -EINVAL; mutex_lock(&rstc_lock); - /* - * Writing 1 to this bit resets corresponding block. Writing 0 to this - * bit de-asserts reset signal of the corresponding block. - * datasheet doesn't require explicit delay between the set and clear - * of reset bit. it could be shorter if tests pass. - */ - writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit, - sirfsoc_rstc_base + (reset_bit / 32) * 4); - msleep(10); - writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit, - sirfsoc_rstc_base + (reset_bit / 32) * 4); + if (of_device_is_compatible(dev->of_node, "sirf,prima2-rstc")) { + /* + * Writing 1 to this bit resets corresponding block. Writing 0 to this + * bit de-asserts reset signal of the corresponding block. + * datasheet doesn't require explicit delay between the set and clear + * of reset bit. it could be shorter if tests pass. + */ + writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit, + sirfsoc_rstc_base + (reset_bit / 32) * 4); + msleep(10); + writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit, + sirfsoc_rstc_base + (reset_bit / 32) * 4); + } else { + /* + * For MARCO and POLO + * Writing 1 to SET register resets corresponding block. Writing 1 to CLEAR + * register de-asserts reset signal of the corresponding block. + * datasheet doesn't require explicit delay between the set and clear + * of reset bit. it could be shorter if tests pass. + */ + writel(reset_bit, sirfsoc_rstc_base + (reset_bit / 32) * 8); + msleep(10); + writel(reset_bit, sirfsoc_rstc_base + (reset_bit / 32) * 8 + 4); + } mutex_unlock(&rstc_lock); From 598548facd3c55d1da230a2cc0e6026053b04594 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 17:44:19 +0800 Subject: [PATCH 013/148] ARM: PRIMA2: rtciobg: it is also compatible with marco Signed-off-by: Barry Song --- arch/arm/mach-prima2/rtciobrg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-prima2/rtciobrg.c b/arch/arm/mach-prima2/rtciobrg.c index 9d80f1e20a98..fc6c4ab963f2 100644 --- a/arch/arm/mach-prima2/rtciobrg.c +++ b/arch/arm/mach-prima2/rtciobrg.c @@ -104,6 +104,7 @@ EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_writel); static const struct of_device_id rtciobrg_ids[] = { { .compatible = "sirf,prima2-rtciobg" }, + { .compatible = "sirf,marco-rtciobg" }, {} }; From f2a94192d953990c5c928f52dd4122a67f93b980 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 19:11:18 +0800 Subject: [PATCH 014/148] ARM: PRIMA2: irq: make prima2 irq can work even we enable GIC for Marco in Marco, we will use GIC. this patch prepares the handle_irq for prima2 to avoid the compiling errors since we want only one defconfig and zImage for both prima2 and marco that means we will need handle_irq for both. Signed-off-by: Baohua Song --- arch/arm/mach-prima2/common.c | 3 +++ arch/arm/mach-prima2/common.h | 2 ++ arch/arm/mach-prima2/include/mach/irqs.h | 4 ++-- arch/arm/mach-prima2/irq.c | 16 ++++++++++++++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c index 8e6f6681b546..99f9c7e391f5 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c @@ -41,6 +41,9 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") .map_io = sirfsoc_map_lluart, .init_irq = sirfsoc_of_irq_init, .init_time = sirfsoc_prima2_timer_init, +#ifdef CONFIG_MULTI_IRQ_HANDLER + .handle_irq = sirfsoc_handle_irq, +#endif .dma_zone_size = SZ_256M, .init_machine = sirfsoc_mach_init, .init_late = sirfsoc_init_late, diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index d6890b6833c9..a4f91a6de55e 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -11,12 +11,14 @@ #include #include +#include extern void sirfsoc_prima2_timer_init(void); extern void __init sirfsoc_of_irq_init(void); extern void __init sirfsoc_of_clk_init(void); extern void sirfsoc_restart(char, const char *); +extern asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs); #ifndef CONFIG_DEBUG_LL static inline void sirfsoc_map_lluart(void) {} diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h index f6014a07541f..b778a0f248ed 100644 --- a/arch/arm/mach-prima2/include/mach/irqs.h +++ b/arch/arm/mach-prima2/include/mach/irqs.h @@ -10,8 +10,8 @@ #define __ASM_ARCH_IRQS_H #define SIRFSOC_INTENAL_IRQ_START 0 -#define SIRFSOC_INTENAL_IRQ_END 59 +#define SIRFSOC_INTENAL_IRQ_END 127 #define SIRFSOC_GPIO_IRQ_START (SIRFSOC_INTENAL_IRQ_END + 1) -#define NR_IRQS 220 +#define NR_IRQS 288 #endif diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c index 7dee9176e77a..6c0f3e9c43fb 100644 --- a/arch/arm/mach-prima2/irq.c +++ b/arch/arm/mach-prima2/irq.c @@ -9,17 +9,19 @@ #include #include #include -#include -#include #include #include #include #include +#include +#include +#include #define SIRFSOC_INT_RISC_MASK0 0x0018 #define SIRFSOC_INT_RISC_MASK1 0x001C #define SIRFSOC_INT_RISC_LEVEL0 0x0020 #define SIRFSOC_INT_RISC_LEVEL1 0x0024 +#define SIRFSOC_INIT_IRQ_ID 0x0038 void __iomem *sirfsoc_intc_base; @@ -52,6 +54,16 @@ static __init void sirfsoc_irq_init(void) writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1); } +asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs) +{ + u32 irqstat, irqnr; + + irqstat = readl_relaxed(sirfsoc_intc_base + SIRFSOC_INIT_IRQ_ID); + irqnr = irqstat & 0xff; + + handle_IRQ(irqnr, regs); +} + static struct of_device_id intc_ids[] = { { .compatible = "sirf,prima2-intc" }, {}, From 4898de3d15d8ba34aa7a1b0f753a476d52ebdf92 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 19:37:32 +0800 Subject: [PATCH 015/148] ARM: PRIMA2: add new SiRFmarco SMP SoC infrastructures this patch adds tick timer, smp entries and generic DT machine for SiRFmarco dual-core SMP chips. with the added marco, we change the defconfig, using the same defconfig, we get a zImage which can work on both prima2 and marco. Signed-off-by: Barry Song Cc: Mark Rutland --- arch/arm/boot/dts/Makefile | 1 + arch/arm/configs/prima2_defconfig | 3 + arch/arm/mach-prima2/Kconfig | 10 + arch/arm/mach-prima2/Makefile | 3 + arch/arm/mach-prima2/common.c | 40 +++- arch/arm/mach-prima2/common.h | 11 + arch/arm/mach-prima2/headsmp.S | 79 ++++++++ arch/arm/mach-prima2/hotplug.c | 41 ++++ arch/arm/mach-prima2/platsmp.c | 163 +++++++++++++++ arch/arm/mach-prima2/timer-marco.c | 316 +++++++++++++++++++++++++++++ 10 files changed, 666 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-prima2/headsmp.S create mode 100644 arch/arm/mach-prima2/hotplug.c create mode 100644 arch/arm/mach-prima2/platsmp.c create mode 100644 arch/arm/mach-prima2/timer-marco.c diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index e44da40d984f..6af9901d3d2f 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -73,6 +73,7 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-dns320.dtb \ kirkwood-ts219-6281.dtb \ kirkwood-ts219-6282.dtb \ kirkwood-openblocks_a6.dtb +dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb dtb-$(CONFIG_ARCH_MSM) += msm8660-surf.dtb \ msm8960-cdp.dtb dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \ diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig index 6a936c7c078a..002a1ceadceb 100644 --- a/arch/arm/configs/prima2_defconfig +++ b/arch/arm/configs/prima2_defconfig @@ -11,6 +11,9 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_BSD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y CONFIG_ARCH_SIRF=y +# CONFIG_SWP_EMULATE is not set +CONFIG_SMP=y +CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_KEXEC=y diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index 558ccfb8d458..4f7379fe01e2 100644 --- a/arch/arm/mach-prima2/Kconfig +++ b/arch/arm/mach-prima2/Kconfig @@ -11,6 +11,16 @@ config ARCH_PRIMA2 help Support for CSR SiRFSoC ARM Cortex A9 Platform +config ARCH_MARCO + bool "CSR SiRFSoC MARCO ARM Cortex A9 Platform" + default y + select ARM_GIC + select CPU_V7 + select HAVE_SMP + select SMP_ON_UP + help + Support for CSR SiRFSoC ARM Cortex A9 Platform + endmenu config SIRF_IRQ diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile index 0007a6ec78f2..bfe360cbd177 100644 --- a/arch/arm/mach-prima2/Makefile +++ b/arch/arm/mach-prima2/Makefile @@ -5,4 +5,7 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o obj-$(CONFIG_CACHE_L2X0) += l2x0.o obj-$(CONFIG_SUSPEND) += pm.o sleep.o obj-$(CONFIG_SIRF_IRQ) += irq.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o +obj-$(CONFIG_ARCH_MARCO) += timer-marco.o diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c index 99f9c7e391f5..00a65649a7e2 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c @@ -8,9 +8,11 @@ #include #include +#include #include #include #include +#include #include #include #include "common.h" @@ -30,6 +32,12 @@ void __init sirfsoc_init_late(void) sirfsoc_pm_init(); } +static __init void sirfsoc_map_io(void) +{ + sirfsoc_map_lluart(); + sirfsoc_map_scu(); +} + #ifdef CONFIG_ARCH_PRIMA2 static const char *prima2_dt_match[] __initdata = { "sirf,prima2", @@ -38,7 +46,7 @@ static const char *prima2_dt_match[] __initdata = { DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") /* Maintainer: Barry Song */ - .map_io = sirfsoc_map_lluart, + .map_io = sirfsoc_map_io, .init_irq = sirfsoc_of_irq_init, .init_time = sirfsoc_prima2_timer_init, #ifdef CONFIG_MULTI_IRQ_HANDLER @@ -51,3 +59,33 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") .restart = sirfsoc_restart, MACHINE_END #endif + +#ifdef CONFIG_ARCH_MARCO +static const struct of_device_id marco_irq_match[] __initconst = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + { /* sentinel */ } +}; + +static void __init marco_init_irq(void) +{ + of_irq_init(marco_irq_match); +} + +static const char *marco_dt_match[] __initdata = { + "sirf,marco", + NULL +}; + +DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)") + /* Maintainer: Barry Song */ + .smp = smp_ops(sirfsoc_smp_ops), + .map_io = sirfsoc_map_io, + .init_irq = marco_init_irq, + .init_time = sirfsoc_marco_timer_init, + .handle_irq = gic_handle_irq, + .init_machine = sirfsoc_mach_init, + .init_late = sirfsoc_init_late, + .dt_compat = marco_dt_match, + .restart = sirfsoc_restart, +MACHINE_END +#endif diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index a4f91a6de55e..b7c26b62e4a7 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -14,6 +14,11 @@ #include extern void sirfsoc_prima2_timer_init(void); +extern void sirfsoc_marco_timer_init(void); + +extern struct smp_operations sirfsoc_smp_ops; +extern void sirfsoc_secondary_startup(void); +extern void sirfsoc_cpu_die(unsigned int cpu); extern void __init sirfsoc_of_irq_init(void); extern void __init sirfsoc_of_clk_init(void); @@ -26,6 +31,12 @@ static inline void sirfsoc_map_lluart(void) {} extern void __init sirfsoc_map_lluart(void); #endif +#ifndef CONFIG_SMP +static inline void sirfsoc_map_scu(void) {} +#else +extern void sirfsoc_map_scu(void); +#endif + #ifdef CONFIG_SUSPEND extern int sirfsoc_pm_init(void); #else diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S new file mode 100644 index 000000000000..6ec19d51a271 --- /dev/null +++ b/arch/arm/mach-prima2/headsmp.S @@ -0,0 +1,79 @@ +/* + * Entry of the second core for CSR Marco dual-core SMP SoCs + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include + + __INIT +/* + * Cold boot and hardware reset show different behaviour, + * system will be always panic if we warm-reset the board + * Here we invalidate L1 of CPU1 to make sure there isn't + * uninitialized data written into memory later + */ +ENTRY(v7_invalidate_l1) + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mcr p15, 2, r0, c0, c0, 0 + mrc p15, 1, r0, c0, c0, 0 + + ldr r1, =0x7fff + and r2, r1, r0, lsr #13 + + ldr r1, =0x3ff + + and r3, r1, r0, lsr #3 @ NumWays - 1 + add r2, r2, #1 @ NumSets + + and r0, r0, #0x7 + add r0, r0, #4 @ SetShift + + clz r1, r3 @ WayShift + add r4, r3, #1 @ NumWays +1: sub r2, r2, #1 @ NumSets-- + mov r3, r4 @ Temp = NumWays +2: subs r3, r3, #1 @ Temp-- + mov r5, r3, lsl r1 + mov r6, r2, lsl r0 + orr r5, r5, r6 @ Reg = (Temp< +#include +#include + +#include +#include + +static inline void platform_do_lowpower(unsigned int cpu) +{ + flush_cache_all(); + + /* we put the platform to just WFI */ + for (;;) { + __asm__ __volatile__("dsb\n\t" "wfi\n\t" + : : : "memory"); + if (pen_release == cpu_logical_map(cpu)) { + /* + * OK, proper wakeup, we're done + */ + break; + } + } +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void sirfsoc_cpu_die(unsigned int cpu) +{ + platform_do_lowpower(cpu); +} diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c new file mode 100644 index 000000000000..2395022bc733 --- /dev/null +++ b/arch/arm/mach-prima2/platsmp.c @@ -0,0 +1,163 @@ +/* + * plat smp support for CSR Marco dual-core SMP SoCs + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static void __iomem *scu_base; +static void __iomem *rsc_base; + +static DEFINE_SPINLOCK(boot_lock); + +static struct map_desc scu_io_desc __initdata = { + .length = SZ_4K, + .type = MT_DEVICE, +}; + +void __init sirfsoc_map_scu(void) +{ + unsigned long base; + + /* Get SCU base */ + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); + + scu_io_desc.virtual = SIRFSOC_VA(base); + scu_io_desc.pfn = __phys_to_pfn(base); + iotable_init(&scu_io_desc, 1); + + scu_base = (void __iomem *)SIRFSOC_VA(base); +} + +static void __cpuinit sirfsoc_secondary_init(unsigned int cpu) +{ + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); + + /* + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + pen_release = -1; + smp_wmb(); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +static struct of_device_id rsc_ids[] = { + { .compatible = "sirf,marco-rsc" }, + {}, +}; + +static int __cpuinit sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + struct device_node *np; + + np = of_find_matching_node(NULL, rsc_ids); + if (!np) + return -ENODEV; + + rsc_base = of_iomap(np, 0); + if (!rsc_base) + return -ENOMEM; + + /* + * write the address of secondary startup into the sram register + * at offset 0x2C, then write the magic number 0x3CAF5D62 to the + * RSC register at offset 0x28, which is what boot rom code is + * waiting for. This would wake up the secondary core from WFE + */ +#define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2C + __raw_writel(virt_to_phys(sirfsoc_secondary_startup), + rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET); + +#define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x28 + __raw_writel(0x3CAF5D62, + rsc_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET); + + /* make sure write buffer is drained */ + mb(); + + spin_lock(&boot_lock); + + /* + * The secondary processor is waiting to be released from + * the holding pen - release it, then wait for it to flag + * that it has been released by resetting pen_release. + * + * Note that "pen_release" is the hardware CPU ID, whereas + * "cpu" is Linux's internal ID. + */ + pen_release = cpu_logical_map(cpu); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + + /* + * Send the secondary CPU SEV, thereby causing the boot monitor to read + * the JUMPADDR and WAKEMAGIC, and branch to the address found there. + */ + dsb_sev(); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + smp_rmb(); + if (pen_release == -1) + break; + + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return pen_release != -1 ? -ENOSYS : 0; +} + +static void __init sirfsoc_smp_init_cpus(void) +{ + set_smp_cross_call(gic_raise_softirq); +} + +static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus) +{ + scu_enable(scu_base); +} + +struct smp_operations sirfsoc_smp_ops __initdata = { + .smp_init_cpus = sirfsoc_smp_init_cpus, + .smp_prepare_cpus = sirfsoc_smp_prepare_cpus, + .smp_secondary_init = sirfsoc_secondary_init, + .smp_boot_secondary = sirfsoc_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = sirfsoc_cpu_die, +#endif +}; diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c new file mode 100644 index 000000000000..f4eea2e97eb0 --- /dev/null +++ b/arch/arm/mach-prima2/timer-marco.c @@ -0,0 +1,316 @@ +/* + * System timer for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 +#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004 +#define SIRFSOC_TIMER_MATCH_0 0x0018 +#define SIRFSOC_TIMER_MATCH_1 0x001c +#define SIRFSOC_TIMER_COUNTER_0 0x0048 +#define SIRFSOC_TIMER_COUNTER_1 0x004c +#define SIRFSOC_TIMER_INTR_STATUS 0x0060 +#define SIRFSOC_TIMER_WATCHDOG_EN 0x0064 +#define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068 +#define SIRFSOC_TIMER_64COUNTER_LO 0x006c +#define SIRFSOC_TIMER_64COUNTER_HI 0x0070 +#define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074 +#define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078 +#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c +#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080 + +#define SIRFSOC_TIMER_REG_CNT 6 + +static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { + SIRFSOC_TIMER_WATCHDOG_EN, + SIRFSOC_TIMER_32COUNTER_0_CTRL, + SIRFSOC_TIMER_32COUNTER_1_CTRL, + SIRFSOC_TIMER_64COUNTER_CTRL, + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO, + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI, +}; + +static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT]; + +static void __iomem *sirfsoc_timer_base; +static void __init sirfsoc_of_timer_map(void); + +/* disable count and interrupt */ +static inline void sirfsoc_timer_count_disable(int idx) +{ + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7, + sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); +} + +/* enable count and interrupt */ +static inline void sirfsoc_timer_count_enable(int idx) +{ + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x7, + sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); +} + +/* timer interrupt handler */ +static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ce = dev_id; + int cpu = smp_processor_id(); + + /* clear timer interrupt */ + writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); + + if (ce->mode == CLOCK_EVT_MODE_ONESHOT) + sirfsoc_timer_count_disable(cpu); + + ce->event_handler(ce); + + return IRQ_HANDLED; +} + +/* read 64-bit timer counter */ +static cycle_t sirfsoc_timer_read(struct clocksource *cs) +{ + u64 cycles; + + writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + + cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI); + cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO); + + return cycles; +} + +static int sirfsoc_timer_set_next_event(unsigned long delta, + struct clock_event_device *ce) +{ + int cpu = smp_processor_id(); + + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 + + 4 * cpu); + writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 + + 4 * cpu); + + /* enable the tick */ + sirfsoc_timer_count_enable(cpu); + + return 0; +} + +static void sirfsoc_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *ce) +{ + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + /* enable in set_next_event */ + break; + default: + break; + } + + sirfsoc_timer_count_disable(smp_processor_id()); +} + +static void sirfsoc_clocksource_suspend(struct clocksource *cs) +{ + int i; + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) + sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); +} + +static void sirfsoc_clocksource_resume(struct clocksource *cs) +{ + int i; + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++) + writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); + + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], + sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], + sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); + + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); +} + +static struct clock_event_device sirfsoc_clockevent = { + .name = "sirfsoc_clockevent", + .rating = 200, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_mode = sirfsoc_timer_set_mode, + .set_next_event = sirfsoc_timer_set_next_event, +}; + +static struct clocksource sirfsoc_clocksource = { + .name = "sirfsoc_clocksource", + .rating = 200, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .read = sirfsoc_timer_read, + .suspend = sirfsoc_clocksource_suspend, + .resume = sirfsoc_clocksource_resume, +}; + +static struct irqaction sirfsoc_timer_irq = { + .name = "sirfsoc_timer0", + .flags = IRQF_TIMER | IRQF_NOBALANCING, + .handler = sirfsoc_timer_interrupt, + .dev_id = &sirfsoc_clockevent, +}; + +#ifdef CONFIG_LOCAL_TIMERS + +static struct irqaction sirfsoc_timer1_irq = { + .name = "sirfsoc_timer1", + .flags = IRQF_TIMER | IRQF_NOBALANCING, + .handler = sirfsoc_timer_interrupt, +}; + +static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce) +{ + /* Use existing clock_event for cpu 0 */ + if (!smp_processor_id()) + return 0; + + ce->irq = sirfsoc_timer1_irq.irq; + ce->name = "local_timer"; + ce->features = sirfsoc_clockevent.features; + ce->rating = sirfsoc_clockevent.rating; + ce->set_mode = sirfsoc_timer_set_mode; + ce->set_next_event = sirfsoc_timer_set_next_event; + ce->shift = sirfsoc_clockevent.shift; + ce->mult = sirfsoc_clockevent.mult; + ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns; + ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns; + + sirfsoc_timer1_irq.dev_id = ce; + BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq)); + irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1)); + + clockevents_register_device(ce); + return 0; +} + +static void sirfsoc_local_timer_stop(struct clock_event_device *ce) +{ + sirfsoc_timer_count_disable(1); + + remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); +} + +static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = { + .setup = sirfsoc_local_timer_setup, + .stop = sirfsoc_local_timer_stop, +}; +#endif /* CONFIG_LOCAL_TIMERS */ + +static void __init sirfsoc_clockevent_init(void) +{ + clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); + + sirfsoc_clockevent.max_delta_ns = + clockevent_delta2ns(-2, &sirfsoc_clockevent); + sirfsoc_clockevent.min_delta_ns = + clockevent_delta2ns(2, &sirfsoc_clockevent); + + sirfsoc_clockevent.cpumask = cpumask_of(0); + clockevents_register_device(&sirfsoc_clockevent); +#ifdef CONFIG_LOCAL_TIMERS + local_timer_register(&sirfsoc_local_timer_ops); +#endif +} + +/* initialize the kernel jiffy timer source */ +void __init sirfsoc_marco_timer_init(void) +{ + unsigned long rate; + u32 timer_div; + struct clk *clk; + + /* initialize clocking early, we want to set the OS timer */ + sirfsoc_of_clk_init(); + + /* timer's input clock is io clock */ + clk = clk_get_sys("io", NULL); + + BUG_ON(IS_ERR(clk)); + rate = clk_get_rate(clk); + + BUG_ON(rate < CLOCK_TICK_RATE); + BUG_ON(rate % CLOCK_TICK_RATE); + + sirfsoc_of_timer_map(); + + /* Initialize the timer dividers */ + timer_div = rate / CLOCK_TICK_RATE - 1; + writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); + writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL); + + /* Initialize timer counters to 0 */ + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1); + + /* Clear all interrupts */ + writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); + + BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); + + BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); + + sirfsoc_clockevent_init(); +} + +static struct of_device_id timer_ids[] = { + { .compatible = "sirf,marco-tick" }, + {}, +}; + +static void __init sirfsoc_of_timer_map(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, timer_ids); + if (!np) + return; + sirfsoc_timer_base = of_iomap(np, 0); + if (!sirfsoc_timer_base) + panic("unable to map timer cpu registers\n"); + + sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); + if (!sirfsoc_timer_irq.irq) + panic("No irq passed for timer0 via DT\n"); + +#ifdef CONFIG_LOCAL_TIMERS + sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); + if (!sirfsoc_timer1_irq.irq) + panic("No irq passed for timer1 via DT\n"); +#endif + + of_node_put(np); +} From 7f46a10724e0d31c83029436e54298be2cc558fa Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 20 Dec 2012 19:45:25 +0800 Subject: [PATCH 016/148] ARM: PRIMA2: provide two DEBUG_LL ports for prima2 and marco prima2 and marco has different memory base, the old code will fail if we enable DEBUG_LL in marco. this patch adds two debuf port, while debugging, we select one of PRIMA2 and MARCO debug ports, in the products, we disable DEBUG_LL. Signed-off-by: Barry Song --- arch/arm/Kconfig.debug | 14 ++++++++++++++ arch/arm/mach-prima2/include/mach/uart.h | 6 ++++++ arch/arm/mach-prima2/include/mach/uncompress.h | 3 +++ 3 files changed, 23 insertions(+) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 661030d6bc6c..00ad1f895da2 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -386,6 +386,20 @@ choice Say Y here if you want kernel low-level debugging support on Tegra based platforms. + config DEBUG_SIRFPRIMA2_UART1 + bool "Kernel low-level debugging messages via SiRFprimaII UART1" + depends on ARCH_PRIMA2 + help + Say Y here if you want the debug print routines to direct + their output to the uart1 port on SiRFprimaII devices. + + config DEBUG_SIRFMARCO_UART1 + bool "Kernel low-level debugging messages via SiRFmarco UART1" + depends on ARCH_MARCO + help + Say Y here if you want the debug print routines to direct + their output to the uart1 port on SiRFmarco devices. + config DEBUG_VEXPRESS_UART0_DETECT bool "Autodetect UART0 on Versatile Express Cortex-A core tiles" depends on ARCH_VEXPRESS && CPU_CP15_MMU diff --git a/arch/arm/mach-prima2/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h index c98b4d5ac24a..c10510d01a44 100644 --- a/arch/arm/mach-prima2/include/mach/uart.h +++ b/arch/arm/mach-prima2/include/mach/uart.h @@ -10,7 +10,13 @@ #define __MACH_PRIMA2_SIRFSOC_UART_H /* UART-1: used as serial debug port */ +#if defined(CONFIG_DEBUG_SIRFPRIMA2_UART1) #define SIRFSOC_UART1_PA_BASE 0xb0060000 +#elif defined(CONFIG_DEBUG_SIRFMARCO_UART1) +#define SIRFSOC_UART1_PA_BASE 0xcc060000 +#else +#define SIRFSOC_UART1_PA_BASE 0 +#endif #define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000) #define SIRFSOC_UART1_SIZE SZ_4K diff --git a/arch/arm/mach-prima2/include/mach/uncompress.h b/arch/arm/mach-prima2/include/mach/uncompress.h index 0c898fcf909c..15f3edcfbb47 100644 --- a/arch/arm/mach-prima2/include/mach/uncompress.h +++ b/arch/arm/mach-prima2/include/mach/uncompress.h @@ -25,6 +25,9 @@ static __inline__ void putc(char c) * during kernel decompression, all mappings are flat: * virt_addr == phys_addr */ + if (!SIRFSOC_UART1_PA_BASE) + return; + while (__raw_readl((void __iomem *)SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS) & SIRFSOC_UART1_TXFIFO_FULL) barrier(); From af47e6bb8866ad57cfcfeceecf799edc3a658660 Mon Sep 17 00:00:00 2001 From: Robert Tivy Date: Thu, 10 Jan 2013 16:23:23 -0800 Subject: [PATCH 017/148] ARM: davinci: psc: introduce reset API Introduce an IP reset API for use on DaVinci SoC. There is no existing "reset" framework support for SoC devices. The remoteproc driver needs explicit control of the DSP's reset line. To support this, a new DaVinci specific API is added. This private API will disappear with DT migration. Some discussion regarding a proposed DT "reset" binding is here: https://patchwork.kernel.org/patch/1635051/ Modify davinci_clk_init() to set clk "reset" function for clocks that indicate PSC_LRST support. Also fix indentation issue with function opening curly brace. Signed-off-by: Robert Tivy [nsekhar@ti.com: rename davinci_psc_config_reset() to davinci_psc_reset()] Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/clock.c | 39 +++++++++++++++++++++- arch/arm/mach-davinci/clock.h | 3 ++ arch/arm/mach-davinci/include/mach/clock.h | 3 ++ arch/arm/mach-davinci/include/mach/psc.h | 3 ++ arch/arm/mach-davinci/psc.c | 25 ++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 34668ead53c7..d458558ee84a 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -52,6 +52,40 @@ static void __clk_disable(struct clk *clk) __clk_disable(clk->parent); } +int davinci_clk_reset(struct clk *clk, bool reset) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + spin_lock_irqsave(&clockfw_lock, flags); + if (clk->flags & CLK_PSC) + davinci_psc_reset(clk->gpsc, clk->lpsc, reset); + spin_unlock_irqrestore(&clockfw_lock, flags); + + return 0; +} +EXPORT_SYMBOL(davinci_clk_reset); + +int davinci_clk_reset_assert(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk) || !clk->reset) + return -EINVAL; + + return clk->reset(clk, true); +} +EXPORT_SYMBOL(davinci_clk_reset_assert); + +int davinci_clk_reset_deassert(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk) || !clk->reset) + return -EINVAL; + + return clk->reset(clk, false); +} +EXPORT_SYMBOL(davinci_clk_reset_deassert); + int clk_enable(struct clk *clk) { unsigned long flags; @@ -535,7 +569,7 @@ int davinci_set_refclk_rate(unsigned long rate) } int __init davinci_clk_init(struct clk_lookup *clocks) - { +{ struct clk_lookup *c; struct clk *clk; size_t num_clocks = 0; @@ -576,6 +610,9 @@ int __init davinci_clk_init(struct clk_lookup *clocks) if (clk->lpsc) clk->flags |= CLK_PSC; + if (clk->flags & PSC_LRST) + clk->reset = davinci_clk_reset; + clk_register(clk); num_clocks++; diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h index 46f0f1bf1a4c..8694b395fc92 100644 --- a/arch/arm/mach-davinci/clock.h +++ b/arch/arm/mach-davinci/clock.h @@ -103,6 +103,7 @@ struct clk { unsigned long (*recalc) (struct clk *); int (*set_rate) (struct clk *clk, unsigned long rate); int (*round_rate) (struct clk *clk, unsigned long rate); + int (*reset) (struct clk *clk, bool reset); }; /* Clock flags: SoC-specific flags start at BIT(16) */ @@ -112,6 +113,7 @@ struct clk { #define PRE_PLL BIT(4) /* source is before PLL mult/div */ #define PSC_SWRSTDISABLE BIT(5) /* Disable state is SwRstDisable */ #define PSC_FORCE BIT(6) /* Force module state transtition */ +#define PSC_LRST BIT(8) /* Use local reset on enable/disable */ #define CLK(dev, con, ck) \ { \ @@ -126,6 +128,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate); int davinci_set_refclk_rate(unsigned long rate); int davinci_simple_set_rate(struct clk *clk, unsigned long rate); +int davinci_clk_reset(struct clk *clk, bool reset); extern struct platform_device davinci_wdt_device; extern void davinci_watchdog_reset(struct platform_device *); diff --git a/arch/arm/mach-davinci/include/mach/clock.h b/arch/arm/mach-davinci/include/mach/clock.h index a3b040219876..3e8af6a0b64c 100644 --- a/arch/arm/mach-davinci/include/mach/clock.h +++ b/arch/arm/mach-davinci/include/mach/clock.h @@ -18,4 +18,7 @@ struct clk; extern int clk_register(struct clk *clk); extern void clk_unregister(struct clk *clk); +int davinci_clk_reset_assert(struct clk *c); +int davinci_clk_reset_deassert(struct clk *c); + #endif diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 40a0027838e8..0a22710493fd 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -246,6 +246,7 @@ #define MDSTAT_STATE_MASK 0x3f #define PDSTAT_STATE_MASK 0x1f +#define MDCTL_LRST BIT(8) #define MDCTL_FORCE BIT(31) #define PDCTL_NEXT BIT(0) #define PDCTL_EPCGOOD BIT(8) @@ -253,6 +254,8 @@ #ifndef __ASSEMBLER__ extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id); +extern void davinci_psc_reset(unsigned int ctlr, unsigned int id, + bool reset); extern void davinci_psc_config(unsigned int domain, unsigned int ctlr, unsigned int id, bool enable, u32 flags); diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c index bddaba9628e1..82fdc69d5728 100644 --- a/arch/arm/mach-davinci/psc.c +++ b/arch/arm/mach-davinci/psc.c @@ -48,6 +48,31 @@ int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id) return mdstat & BIT(12); } +/* Control "reset" line associated with PSC domain */ +void davinci_psc_reset(unsigned int ctlr, unsigned int id, bool reset) +{ + u32 mdctl; + void __iomem *psc_base; + struct davinci_soc_info *soc_info = &davinci_soc_info; + + if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { + pr_warn("PSC: Bad psc data: 0x%x[%d]\n", + (int)soc_info->psc_bases, ctlr); + return; + } + + psc_base = ioremap(soc_info->psc_bases[ctlr], SZ_4K); + + mdctl = readl(psc_base + MDCTL + 4 * id); + if (reset) + mdctl &= ~MDCTL_LRST; + else + mdctl |= MDCTL_LRST; + writel(mdctl, psc_base + MDCTL + 4 * id); + + iounmap(psc_base); +} + /* Enable or disable a PSC domain */ void davinci_psc_config(unsigned int domain, unsigned int ctlr, unsigned int id, bool enable, u32 flags) From 09810a853b9a7920ba8c250d18815ef236effc47 Mon Sep 17 00:00:00 2001 From: Robert Tivy Date: Thu, 10 Jan 2013 16:23:22 -0800 Subject: [PATCH 018/148] ARM: davinci: da850: add dsp clock definition Added dsp clock definition, keyed to "davinci-rproc.0". DSP clocks is derived from pll0 sysclk1. Add a clock tree node for that too. Signed-off-by: Robert Tivy [nsekhar@ti.com: merge addition of pll0 sysclk1 and dsp clock into one commit. Add PSC_FORCE to dsp clock node to handle the case where DSP does not go into IDLE and its clock needs to be disabled.] Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/da850.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 6b9154e9f908..0c4a26ddebba 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -76,6 +76,13 @@ static struct clk pll0_aux_clk = { .flags = CLK_PLL | PRE_PLL, }; +static struct clk pll0_sysclk1 = { + .name = "pll0_sysclk1", + .parent = &pll0_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV1, +}; + static struct clk pll0_sysclk2 = { .name = "pll0_sysclk2", .parent = &pll0_clk, @@ -368,10 +375,19 @@ static struct clk sata_clk = { .flags = PSC_FORCE, }; +static struct clk dsp_clk = { + .name = "dsp", + .parent = &pll0_sysclk1, + .domain = DAVINCI_GPSC_DSPDOMAIN, + .lpsc = DA8XX_LPSC0_GEM, + .flags = PSC_LRST | PSC_FORCE, +}; + static struct clk_lookup da850_clks[] = { CLK(NULL, "ref", &ref_clk), CLK(NULL, "pll0", &pll0_clk), CLK(NULL, "pll0_aux", &pll0_aux_clk), + CLK(NULL, "pll0_sysclk1", &pll0_sysclk1), CLK(NULL, "pll0_sysclk2", &pll0_sysclk2), CLK(NULL, "pll0_sysclk3", &pll0_sysclk3), CLK(NULL, "pll0_sysclk4", &pll0_sysclk4), @@ -413,6 +429,7 @@ static struct clk_lookup da850_clks[] = { CLK("spi_davinci.1", NULL, &spi1_clk), CLK("vpif", NULL, &vpif_clk), CLK("ahci", NULL, &sata_clk), + CLK("davinci-rproc.0", NULL, &dsp_clk), CLK(NULL, NULL, NULL), }; From f977ec94f7f2d1211305ac0c79b8e79155c236ef Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 20 Nov 2012 06:39:09 +0000 Subject: [PATCH 019/148] ARM: shmobile: Remove duplicate inclusion of dma-mapping.h in setup-r8a7740.c linux/dma-mapping.h was included twice. Signed-off-by: Sachin Kamat Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7740.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 03c69f9979aa..9ef397d41158 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include From e67d7afc567437246ec425f1989ea38b372571df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Dec 2012 02:08:09 -0800 Subject: [PATCH 020/148] ARM: shmobile: r8a7740: add TMU timer support This patch enabled TMU0 timer on r8a7740. But TMU1 timer is not supported yet Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7740.c | 6 +- arch/arm/mach-shmobile/setup-r8a7740.c | 94 ++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c index eac49d59782f..19ce885a3b43 100644 --- a/arch/arm/mach-shmobile/clock-r8a7740.c +++ b/arch/arm/mach-shmobile/clock-r8a7740.c @@ -581,10 +581,14 @@ static struct clk_lookup lookups[] = { /* MSTP32 clocks */ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), - CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP111]), + CLKDEV_DEV_ID("sh_tmu.3", &mstp_clks[MSTP111]), + CLKDEV_DEV_ID("sh_tmu.4", &mstp_clks[MSTP111]), + CLKDEV_DEV_ID("sh_tmu.5", &mstp_clks[MSTP111]), CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), + CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), + CLKDEV_DEV_ID("sh_tmu.2", &mstp_clks[MSTP125]), CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[MSTP128]), diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 9ef397d41158..847567d55487 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -261,6 +261,97 @@ static struct platform_device cmt10_device = { .num_resources = ARRAY_SIZE(cmt10_resources), }; +/* TMU */ +static struct sh_timer_config tmu00_platform_data = { + .name = "TMU00", + .channel_offset = 0x4, + .timer_bit = 0, + .clockevent_rating = 200, +}; + +static struct resource tmu00_resources[] = { + [0] = { + .name = "TMU00", + .start = 0xfff80008, + .end = 0xfff80014 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0xe80), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device tmu00_device = { + .name = "sh_tmu", + .id = 0, + .dev = { + .platform_data = &tmu00_platform_data, + }, + .resource = tmu00_resources, + .num_resources = ARRAY_SIZE(tmu00_resources), +}; + +static struct sh_timer_config tmu01_platform_data = { + .name = "TMU01", + .channel_offset = 0x10, + .timer_bit = 1, + .clocksource_rating = 200, +}; + +static struct resource tmu01_resources[] = { + [0] = { + .name = "TMU01", + .start = 0xfff80014, + .end = 0xfff80020 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0xea0), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device tmu01_device = { + .name = "sh_tmu", + .id = 1, + .dev = { + .platform_data = &tmu01_platform_data, + }, + .resource = tmu01_resources, + .num_resources = ARRAY_SIZE(tmu01_resources), +}; + +static struct sh_timer_config tmu02_platform_data = { + .name = "TMU02", + .channel_offset = 0x1C, + .timer_bit = 2, + .clocksource_rating = 200, +}; + +static struct resource tmu02_resources[] = { + [0] = { + .name = "TMU02", + .start = 0xfff80020, + .end = 0xfff8002C - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0xec0), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device tmu02_device = { + .name = "sh_tmu", + .id = 2, + .dev = { + .platform_data = &tmu02_platform_data, + }, + .resource = tmu02_resources, + .num_resources = ARRAY_SIZE(tmu02_resources), +}; + static struct platform_device *r8a7740_early_devices[] __initdata = { &scif0_device, &scif1_device, @@ -272,6 +363,9 @@ static struct platform_device *r8a7740_early_devices[] __initdata = { &scif7_device, &scifb_device, &cmt10_device, + &tmu00_device, + &tmu01_device, + &tmu02_device, }; /* DMA */ From bf519bfb66019c06fc44413a90715f3f5b1d7e9f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 4 Dec 2012 17:43:29 -0800 Subject: [PATCH 021/148] ARM: shmobile: sh73a0: fixup div4_clks bitmap div4_clks's bitmap of sh73a0 was wrong. This patch is based on v2.0 datasheet. Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-sh73a0.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 516ff7f3e434..5f57701da16e 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -264,17 +264,17 @@ enum { DIV4_I, DIV4_ZG, DIV4_M3, DIV4_B, DIV4_M1, DIV4_M2, SH_CLK_DIV4(&pll1_clk, _reg, _bit, _mask, _flags) static struct clk div4_clks[DIV4_NR] = { - [DIV4_I] = DIV4(FRQCRA, 20, 0xfff, CLK_ENABLE_ON_INIT), - [DIV4_ZG] = DIV4(FRQCRA, 16, 0xbff, CLK_ENABLE_ON_INIT), - [DIV4_M3] = DIV4(FRQCRA, 12, 0xfff, CLK_ENABLE_ON_INIT), - [DIV4_B] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT), - [DIV4_M1] = DIV4(FRQCRA, 4, 0xfff, 0), - [DIV4_M2] = DIV4(FRQCRA, 0, 0xfff, 0), - [DIV4_Z] = DIV4(FRQCRB, 24, 0xbff, 0), - [DIV4_ZTR] = DIV4(FRQCRB, 20, 0xfff, 0), - [DIV4_ZT] = DIV4(FRQCRB, 16, 0xfff, 0), - [DIV4_ZX] = DIV4(FRQCRB, 12, 0xfff, 0), - [DIV4_HP] = DIV4(FRQCRB, 4, 0xfff, 0), + [DIV4_I] = DIV4(FRQCRA, 20, 0xdff, CLK_ENABLE_ON_INIT), + [DIV4_ZG] = DIV4(FRQCRA, 16, 0xd7f, CLK_ENABLE_ON_INIT), + [DIV4_M3] = DIV4(FRQCRA, 12, 0x1dff, CLK_ENABLE_ON_INIT), + [DIV4_B] = DIV4(FRQCRA, 8, 0xdff, CLK_ENABLE_ON_INIT), + [DIV4_M1] = DIV4(FRQCRA, 4, 0x1dff, 0), + [DIV4_M2] = DIV4(FRQCRA, 0, 0x1dff, 0), + [DIV4_Z] = DIV4(FRQCRB, 24, 0x97f, 0), + [DIV4_ZTR] = DIV4(FRQCRB, 20, 0xdff, 0), + [DIV4_ZT] = DIV4(FRQCRB, 16, 0xdff, 0), + [DIV4_ZX] = DIV4(FRQCRB, 12, 0xdff, 0), + [DIV4_HP] = DIV4(FRQCRB, 4, 0xdff, 0), }; enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1, From 6333ae1432039003c4d9c76f0ecec41bb982898a Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Fri, 14 Dec 2012 12:43:12 +0900 Subject: [PATCH 022/148] ARM: mach-shmobile: sh73a0 external IRQ wake update Use sh73a0_set_wake() for external IRQ signals on sh73a0. The sh73a0 IRQ hardware for external IRQ pins consists of the INTCA interrupt controller and the GIC together doing their best to limp along. These external IRQ pins are treated as a special case where interrupts need to be managed in both interrupt controllers in parallel. The ->irq_set_wake() callback for the external IRQ pins can be dealt with in the same way as INTCA-only without involving the GIC. So this patch updates the external IRQ pin code for sh73a0 to no longer involve the GIC. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/intc-sh73a0.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index 978369973be4..45973b59dd58 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -315,11 +315,6 @@ static int intca_gic_set_type(struct irq_data *data, unsigned int type) return irq_cbp(irq_set_type, to_intca_reloc_irq(data), type); } -static int intca_gic_set_wake(struct irq_data *data, unsigned int on) -{ - return irq_cbp(irq_set_wake, to_intca_reloc_irq(data), on); -} - #ifdef CONFIG_SMP static int intca_gic_set_affinity(struct irq_data *data, const struct cpumask *cpumask, @@ -339,7 +334,7 @@ struct irq_chip intca_gic_irq_chip = { .irq_disable = intca_gic_disable, .irq_shutdown = intca_gic_disable, .irq_set_type = intca_gic_set_type, - .irq_set_wake = intca_gic_set_wake, + .irq_set_wake = sh73a0_set_wake, #ifdef CONFIG_SMP .irq_set_affinity = intca_gic_set_affinity, #endif From 529a7b323507c1aa0873066d84487b1ca7c28af5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 14 Dec 2012 17:45:28 +0100 Subject: [PATCH 023/148] ARM: sh7372: add clock lookup entries for DT-based devices When booting with DT, devices are named differently. To get their clocks additional entries have to be added to the lookup table. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-sh7372.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 3ca6757b129a..45d21fe317f4 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -544,6 +544,7 @@ static struct clk_lookup lookups[] = { /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ + CLKDEV_DEV_ID("fff30000.i2c", &mstp_clks[MSTP001]), /* IIC2 */ CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[MSTP000]), /* MSIOF0 */ CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */ CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */ @@ -556,6 +557,7 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX0 */ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */ CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ + CLKDEV_DEV_ID("fff20000.i2c", &mstp_clks[MSTP116]), /* IIC0 */ CLKDEV_DEV_ID("sh_mobile_meram.0", &mstp_clks[MSTP113]), /* MERAM */ CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */ CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */ @@ -577,18 +579,25 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ + CLKDEV_DEV_ID("e6c20000.i2c", &mstp_clks[MSTP323]), /* IIC1 */ CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */ CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */ CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP322]), /* USB0 */ CLKDEV_DEV_ID("sh_flctl.0", &mstp_clks[MSTP315]), /* FLCTL */ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ + CLKDEV_DEV_ID("e6850000.sdhi", &mstp_clks[MSTP314]), /* SDHI0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ + CLKDEV_DEV_ID("e6860000.sdhi", &mstp_clks[MSTP313]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */ + CLKDEV_DEV_ID("e6bd0000.mmcif", &mstp_clks[MSTP312]), /* MMC */ CLKDEV_DEV_ID("sh-mipi-dsi.1", &mstp_clks[MSTP423]), /* DSITX1 */ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */ + CLKDEV_DEV_ID("e6870000.sdhi", &mstp_clks[MSTP415]), /* SDHI2 */ CLKDEV_DEV_ID("sh-mobile-hdmi", &mstp_clks[MSTP413]), /* HDMI */ CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */ + CLKDEV_DEV_ID("e6d20000.i2c", &mstp_clks[MSTP411]), /* IIC3 */ CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */ + CLKDEV_DEV_ID("e6d30000.i2c", &mstp_clks[MSTP410]), /* IIC4 */ CLKDEV_DEV_ID("sh-dma-engine.4", &mstp_clks[MSTP407]), /* USB-DMAC1 */ CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */ CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */ From 9916152438a99b15c009e26f0f9cb38efba086d3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 28 Dec 2012 12:32:54 +0100 Subject: [PATCH 024/148] ARM: sh7372: fix cache clean / invalidate order According to the Cortex A8 TRM the L2 cache should be first cleaned and then disabled. Fix the swapped order on sh7372. Signed-off-by: Guennadi Liakhovetski Reviewed-by: Santosh Shilimkar Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/sleep-sh7372.S | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S index 1d564674451d..a9df53b69ab8 100644 --- a/arch/arm/mach-shmobile/sleep-sh7372.S +++ b/arch/arm/mach-shmobile/sleep-sh7372.S @@ -59,16 +59,18 @@ sh7372_do_idle_sysc: mcr p15, 0, r0, c1, c0, 0 isb + /* + * Clean and invalidate data cache again. + */ + ldr r1, kernel_flush + blx r1 + /* disable L2 cache in the aux control register */ mrc p15, 0, r10, c1, c0, 1 bic r10, r10, #2 mcr p15, 0, r10, c1, c0, 1 + isb - /* - * Invalidate data cache again. - */ - ldr r1, kernel_flush - blx r1 /* * The kernel doesn't interwork: v7_flush_dcache_all in particluar will * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled. From 8a21cdaee85e28489a6fe606b8eb0fef32ebf635 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 31 Dec 2012 11:23:50 +0000 Subject: [PATCH 025/148] ARM: shmobile: add function declarations for sh7372 DT helper functions sh7372_add_early_devices_dt() and sh7372_add_standard_devices_dt() are defined as global functions in arch/arm/mach-shmobile/setup-sh7372.c, but their declarations are missing. Add them to common.h, where similar functions for this and other SoC types are already declared. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/include/mach/common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index a57439eec11a..2d1686becdd5 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -23,6 +23,8 @@ extern void sh7372_map_io(void); extern void sh7372_earlytimer_init(void); extern void sh7372_add_early_devices(void); extern void sh7372_add_standard_devices(void); +extern void sh7372_add_early_devices_dt(void); +extern void sh7372_add_standard_devices_dt(void); extern void sh7372_clock_init(void); extern void sh7372_pinmux_init(void); extern void sh7372_pm_init(void); From 13baf88bd69ed3cf7e2374eec4a7128f62ae9c1f Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Wed, 5 Dec 2012 12:13:06 +0000 Subject: [PATCH 026/148] ARM: shmobile: sh73a0: Add CPU sleep suspend Add the lighest possible sleep mode on Cortex-A9 cores: CPU sleep. It is entered by a simple dsb and wfi instruction via cpu_do_idle(). As just clocks are stopped there is no need to save or restore any state of the system. Signed-off-by: Bastian Hecht Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Makefile | 1 + arch/arm/mach-shmobile/board-kzm9g.c | 2 ++ arch/arm/mach-shmobile/include/mach/common.h | 1 + arch/arm/mach-shmobile/pm-sh73a0.c | 32 ++++++++++++++++++++ 4 files changed, 36 insertions(+) create mode 100644 arch/arm/mach-shmobile/pm-sh73a0.c diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 0b7147928aa3..f6aba6d61d89 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_ARCH_SHMOBILE) += pm-rmobile.o obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o obj-$(CONFIG_ARCH_R8A7740) += pm-r8a7740.o obj-$(CONFIG_ARCH_R8A7779) += pm-r8a7779.o +obj-$(CONFIG_ARCH_SH73A0) += pm-sh73a0.o # Board objects obj-$(CONFIG_MACH_AP4EVB) += board-ap4evb.o diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index ac9428530d7b..363c6edfa3cd 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -772,6 +772,8 @@ static void __init kzm_init(void) sh73a0_add_standard_devices(); platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices)); + + sh73a0_pm_init(); } static void kzm9g_restart(char mode, const char *cmd) diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 2d1686becdd5..f221c116e968 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -40,6 +40,7 @@ extern void sh73a0_add_early_devices(void); extern void sh73a0_add_standard_devices(void); extern void sh73a0_clock_init(void); extern void sh73a0_pinmux_init(void); +extern void sh73a0_pm_init(void); extern struct clk sh73a0_extal1_clk; extern struct clk sh73a0_extal2_clk; extern struct clk sh73a0_extcki_clk; diff --git a/arch/arm/mach-shmobile/pm-sh73a0.c b/arch/arm/mach-shmobile/pm-sh73a0.c new file mode 100644 index 000000000000..99086e98fbbc --- /dev/null +++ b/arch/arm/mach-shmobile/pm-sh73a0.c @@ -0,0 +1,32 @@ +/* + * sh73a0 Power management support + * + * Copyright (C) 2012 Bastian Hecht + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include + +#ifdef CONFIG_SUSPEND +static int sh73a0_enter_suspend(suspend_state_t suspend_state) +{ + cpu_do_idle(); + return 0; +} + +static void sh73a0_suspend_init(void) +{ + shmobile_suspend_ops.enter = sh73a0_enter_suspend; +} +#else +static void sh73a0_suspend_init(void) {} +#endif + +void __init sh73a0_pm_init(void) +{ + sh73a0_suspend_init(); +} From 895d3b53fd910f78c52cba89243107fb132538f3 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Wed, 5 Dec 2012 12:13:07 +0000 Subject: [PATCH 027/148] ARM: shmobile: r8a7740: Add CPU sleep suspend Add the lighest possible sleep mode on Cortex-A9 cores: CPU sleep. It is entered by a simple dsb and wfi instruction via cpu_do_idle(). As just clocks are stopped there is no need to save or restore any state of the system. Signed-off-by: Bastian Hecht Acked-by: Magnus Damm [ horms@verge.net.au: Added missing includes ] Signed-off-by: Simon Horman --- .../arm/mach-shmobile/board-armadillo800eva.c | 2 ++ arch/arm/mach-shmobile/include/mach/common.h | 1 + arch/arm/mach-shmobile/pm-r8a7740.c | 22 +++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index e7912447ad50..65731370da81 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -1181,6 +1181,8 @@ static void __init eva_init(void) rmobile_add_device_to_domain("A4LC", &hdmi_lcdc_device); if (usb) rmobile_add_device_to_domain("A3SP", usb); + + r8a7740_pm_init(); } static void __init eva_earlytimer_init(void) diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index f221c116e968..c0ab595bc18f 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -52,6 +52,7 @@ extern void r8a7740_add_early_devices(void); extern void r8a7740_add_standard_devices(void); extern void r8a7740_clock_init(u8 md_ck); extern void r8a7740_pinmux_init(void); +extern void r8a7740_pm_init(void); extern void r8a7779_init_irq(void); extern void r8a7779_map_io(void); diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index 21e5316d2d88..40b87aa1d448 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -9,7 +9,9 @@ * for more details. */ #include +#include #include +#include #ifdef CONFIG_PM static int r8a7740_pd_a4s_suspend(void) @@ -58,3 +60,23 @@ void __init r8a7740_init_pm_domains(void) } #endif /* CONFIG_PM */ + +#ifdef CONFIG_SUSPEND +static int r8a7740_enter_suspend(suspend_state_t suspend_state) +{ + cpu_do_idle(); + return 0; +} + +static void r8a7740_suspend_init(void) +{ + shmobile_suspend_ops.enter = r8a7740_enter_suspend; +} +#else +static void r8a7740_suspend_init(void) {} +#endif + +void __init r8a7740_pm_init(void) +{ + r8a7740_suspend_init(); +} From 33419a69a56436dda8e9187cf09ff0bde74d8a01 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Wed, 9 Jan 2013 19:41:51 +0000 Subject: [PATCH 028/148] ARM: SH-Mobile: sh73a0: Secondary CPUs handle own SCU flags When booting secondary CPUs we have used the main CPU to set up the Snoop Control Unit flags of these CPUs. It is a cleaner approach if every CPU takes care of its own flags. We avoid the need for locking and the program logic is more concise. With this patch the file headsmp-sh73a0.S is added that contains a startup vector for secondary CPUs that sets up its own SCU flags. Further in sh73a0_smp_prepare_cpus() we can rely on the generic ARM helper scu_power_mode(). This is possible as we don't cross borders anymore (every CPU handles its own flags) and need no locking. So we can throw out the needless function modify_scu_cpu_psr(). Signed-off-by: Bastian Hecht Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Makefile | 2 +- arch/arm/mach-shmobile/headsmp-sh73a0.S | 50 ++++++++++++++++++++ arch/arm/mach-shmobile/include/mach/common.h | 1 + arch/arm/mach-shmobile/smp-sh73a0.c | 30 ++---------- 4 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 arch/arm/mach-shmobile/headsmp-sh73a0.S diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index f6aba6d61d89..700e6623aa86 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o # SMP objects smp-y := platsmp.o headsmp.o smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o -smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o +smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o headsmp-sh73a0.o smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o diff --git a/arch/arm/mach-shmobile/headsmp-sh73a0.S b/arch/arm/mach-shmobile/headsmp-sh73a0.S new file mode 100644 index 000000000000..bec4c0d9b713 --- /dev/null +++ b/arch/arm/mach-shmobile/headsmp-sh73a0.S @@ -0,0 +1,50 @@ +/* + * SMP support for SoC sh73a0 + * + * Copyright (C) 2012 Bastian Hecht + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + + __CPUINIT +/* + * Reset vector for secondary CPUs. + * + * First we turn on L1 cache coherency for our CPU. Then we jump to + * shmobile_invalidate_start that invalidates the cache and hands over control + * to the common ARM startup code. + * This function will be mapped to address 0 by the SBAR register. + * A normal branch is out of range here so we need a long jump. We jump to + * the physical address as the MMU is still turned off. + */ + .align 12 +ENTRY(sh73a0_secondary_vector) + mrc p15, 0, r0, c0, c0, 5 @ read MIPDR + and r0, r0, #3 @ mask out cpu ID + lsl r0, r0, #3 @ we will shift by cpu_id * 8 bits + mov r1, #0xf0000000 @ SCU base address + ldr r2, [r1, #8] @ SCU Power Status Register + mov r3, #3 + bic r2, r2, r3, lsl r0 @ Clear bits of our CPU (Run Mode) + str r2, [r1, #8] @ write back + + ldr pc, 1f +1: .long shmobile_invalidate_start - PAGE_OFFSET + PLAT_PHYS_OFFSET +ENDPROC(sh73a0_secondary_vector) diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index c0ab595bc18f..4b1af936fae9 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -41,6 +41,7 @@ extern void sh73a0_add_standard_devices(void); extern void sh73a0_clock_init(void); extern void sh73a0_pinmux_init(void); extern void sh73a0_pm_init(void); +extern void sh73a0_secondary_vector(void); extern struct clk sh73a0_extal1_clk; extern struct clk sh73a0_extal2_clk; extern struct clk sh73a0_extcki_clk; diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 5c5bcb595350..430b44ea85f2 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -41,9 +41,6 @@ static void __iomem *scu_base_addr(void) return (void __iomem *)0xf0000000; } -static DEFINE_SPINLOCK(scu_lock); -static unsigned long tmp; - #ifdef CONFIG_HAVE_ARM_TWD static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29); void __init sh73a0_register_twd(void) @@ -52,20 +49,6 @@ void __init sh73a0_register_twd(void) } #endif -static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) -{ - void __iomem *scu_base = scu_base_addr(); - - spin_lock(&scu_lock); - tmp = __raw_readl(scu_base + 8); - tmp &= ~clr; - tmp |= set; - spin_unlock(&scu_lock); - - /* disable cache coherency after releasing the lock */ - __raw_writel(tmp, scu_base + 8); -} - static unsigned int __init sh73a0_get_core_count(void) { void __iomem *scu_base = scu_base_addr(); @@ -82,9 +65,6 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct { cpu = cpu_logical_map(cpu); - /* enable cache coherency */ - modify_scu_cpu_psr(0, 3 << (cpu * 8)); - if (((__raw_readl(PSTR) >> (4 * cpu)) & 3) == 3) __raw_writel(1 << cpu, WUPCR); /* wake up */ else @@ -95,16 +75,14 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus) { - int cpu = cpu_logical_map(0); - scu_enable(scu_base_addr()); - /* Map the reset vector (in headsmp.S) */ + /* Map the reset vector (in headsmp-sh73a0.S) */ __raw_writel(0, APARMBAREA); /* 4k */ - __raw_writel(__pa(shmobile_secondary_vector), SBAR); + __raw_writel(__pa(sh73a0_secondary_vector), SBAR); - /* enable cache coherency on CPU0 */ - modify_scu_cpu_psr(0, 3 << (cpu * 8)); + /* enable cache coherency on booting CPU */ + scu_power_mode(scu_base_addr(), SCU_PM_NORMAL); } static void __init sh73a0_smp_init_cpus(void) From 20aa11358d52e1a3fc037d601ffe704e6f55c5fb Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Wed, 9 Jan 2013 19:41:52 +0000 Subject: [PATCH 029/148] ARM: SH-Mobile: sh73a0: Add CPU Hotplug Add the capability to add and remove CPUs on the fly. The Cortex-A9 offers the possibility to take single cores out of the MP Core. We add this capabilty taking care that caches are kept coherent. For verifying the shutdown we rely on the internal SH73A0 Power Status Register PSTR. Signed-off-by: Bastian Hecht Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/smp-sh73a0.c | 38 +++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 430b44ea85f2..9812ea3255c9 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,8 @@ #define SBAR IOMEM(0xe6180020) #define APARMBAREA IOMEM(0xe6f10020) +#define PSTR_SHUTDOWN_MODE 3 + static void __iomem *scu_base_addr(void) { return (void __iomem *)0xf0000000; @@ -92,16 +95,20 @@ static void __init sh73a0_smp_init_cpus(void) shmobile_smp_init_cpus(ncores); } -static int __maybe_unused sh73a0_cpu_kill(unsigned int cpu) +#ifdef CONFIG_HOTPLUG_CPU +static int sh73a0_cpu_kill(unsigned int cpu) { - int k; - /* this function is running on another CPU than the offline target, - * here we need wait for shutdown code in platform_cpu_die() to - * finish before asking SoC-specific code to power off the CPU core. + int k; + u32 pstr; + + /* + * wait until the power status register confirms the shutdown of the + * offline target */ for (k = 0; k < 1000; k++) { - if (shmobile_cpu_is_dead(cpu)) + pstr = (__raw_readl(PSTR) >> (4 * cpu)) & 3; + if (pstr == PSTR_SHUTDOWN_MODE) return 1; mdelay(1); @@ -110,6 +117,23 @@ static int __maybe_unused sh73a0_cpu_kill(unsigned int cpu) return 0; } +static void sh73a0_cpu_die(unsigned int cpu) +{ + /* + * The ARM MPcore does not issue a cache coherency request for the L1 + * cache when powering off single CPUs. We must take care of this and + * further caches. + */ + dsb(); + flush_cache_all(); + + /* Set power off mode. This takes the CPU out of the MP cluster */ + scu_power_mode(scu_base_addr(), SCU_PM_POWEROFF); + + /* Enter shutdown mode */ + cpu_do_idle(); +} +#endif /* CONFIG_HOTPLUG_CPU */ struct smp_operations sh73a0_smp_ops __initdata = { .smp_init_cpus = sh73a0_smp_init_cpus, @@ -118,7 +142,7 @@ struct smp_operations sh73a0_smp_ops __initdata = { .smp_boot_secondary = sh73a0_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU .cpu_kill = sh73a0_cpu_kill, - .cpu_die = shmobile_cpu_die, + .cpu_die = sh73a0_cpu_die, .cpu_disable = shmobile_cpu_disable, #endif }; From a3f22db5102238197d5f6bbcad2f720ec7f09e10 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 21 Nov 2012 21:12:43 +0900 Subject: [PATCH 030/148] ARM: mach-shmobile: sh73a0: Allow initialisation of GIC by DT This allows the GIC interrupt controller of the sh73a0 SoC to be initialised using a flattened device tree blob. It does not allow the INTC interrupt controller which is also present on the sh73a0 SoC to be enabled via device tree. Nor does it handle sharing of interrupts between the GIC and INTC interrupt controllers. This limits the usefulness of this code to applications which only wish to access devices which use interrupts that can be handled by the GIC interrupt controller. Other applications should, for now, continue using non-device tree initialisation of the sh72a0 interrupt controllers. Includes update to use irqchip_init() by Thierry Reding Cc: Thierry Reding Signed-off-by: Simon Horman --- arch/arm/boot/dts/sh73a0.dtsi | 33 ++++++++++++++++++++ arch/arm/mach-shmobile/include/mach/common.h | 1 + arch/arm/mach-shmobile/intc-sh73a0.c | 9 ++++++ 3 files changed, 43 insertions(+) create mode 100644 arch/arm/boot/dts/sh73a0.dtsi diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi new file mode 100644 index 000000000000..7dae1f4e9be3 --- /dev/null +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -0,0 +1,33 @@ +/* + * Device Tree Source for the SH73A0 SoC + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/include/ "skeleton.dtsi" + +/ { + compatible = "renesas,sh73a0"; + + cpus { + cpu@0 { + compatible = "arm,cortex-a9"; + }; + cpu@1 { + compatible = "arm,cortex-a9"; + }; + }; + + gic: interrupt-controller@f0001000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + interrupt-controller; + reg = <0xf0001000 0x1000>, + <0xf0000100 0x100>; + }; +}; diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 4b1af936fae9..e2ba16b6ae8e 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -34,6 +34,7 @@ extern struct clk sh7372_extal1_clk; extern struct clk sh7372_extal2_clk; extern void sh73a0_init_irq(void); +extern void sh73a0_init_irq_dt(void); extern void sh73a0_map_io(void); extern void sh73a0_earlytimer_init(void); extern void sh73a0_add_early_devices(void); diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index 45973b59dd58..91faba666d46 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -459,3 +460,11 @@ void __init sh73a0_init_irq(void) sh73a0_pint1_cascade.handler = sh73a0_pint1_demux; setup_irq(gic_spi(34), &sh73a0_pint1_cascade); } + +#ifdef CONFIG_OF +void __init sh73a0_init_irq_dt(void) +{ + irqchip_init(); + gic_arch_extn.irq_set_wake = sh73a0_set_wake; +} +#endif From 486095331af0ab4582879aa1421757f51a92d4e7 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 21 Nov 2012 22:00:15 +0900 Subject: [PATCH 031/148] ARM: mach-shmobile: sh73a0: Minimal setup using DT Allow a minimal setup of the sh73a0 SoC using a flattened device tree. In particular, Configure the i2c controllers using a flattened device tree. SCI serial controller and CMT clock source, whose drivers do not yet support configuration using a flattened device tree, are still configured using C code in order to allow booting of a board with this SoC. *** Please note that the clock initialisation scheme used in this patch does not currently work with SMP as there is a yet to be resolved lock-up in workqueue initialisation. CONFIG_SMP must be disabled when using this code. *** Includes update from Thierry Reding to no longer use gic_handle_irq() Cc: Thierry Reding Signed-off-by: Simon Horman fix --- arch/arm/boot/dts/sh73a0.dtsi | 60 +++++++++++++++++++ arch/arm/mach-shmobile/clock-sh73a0.c | 12 ++++ arch/arm/mach-shmobile/include/mach/common.h | 2 + arch/arm/mach-shmobile/setup-sh73a0.c | 62 +++++++++++++++++++- 4 files changed, 135 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi index 7dae1f4e9be3..721f48668f98 100644 --- a/arch/arm/boot/dts/sh73a0.dtsi +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -30,4 +30,64 @@ reg = <0xf0001000 0x1000>, <0xf0000100 0x100>; }; + + i2c0: i2c@0xe6820000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xe6820000 0x425>; + interrupt-parent = <&gic>; + interrupts = <0 167 0x4 + 0 168 0x4 + 0 169 0x4 + 0 170 0x4>; + }; + + i2c1: i2c@0xe6822000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xe6822000 0x425>; + interrupt-parent = <&gic>; + interrupts = <0 51 0x4 + 0 52 0x4 + 0 53 0x4 + 0 54 0x4>; + }; + + i2c2: i2c@0xe6824000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xe6824000 0x425>; + interrupt-parent = <&gic>; + interrupts = <0 171 0x4 + 0 172 0x4 + 0 173 0x4 + 0 174 0x4>; + }; + + i2c3: i2c@0xe6826000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xe6826000 0x425>; + interrupt-parent = <&gic>; + interrupts = <0 183 0x4 + 0 184 0x4 + 0 185 0x4 + 0 186 0x4>; + }; + + i2c4: i2c@0xe6828000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xe6828000 0x425>; + interrupt-parent = <&gic>; + interrupts = <0 187 0x4 + 0 188 0x4 + 0 189 0x4 + 0 190 0x4>; + }; }; diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 5f57701da16e..eab26675c852 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -525,6 +525,13 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */ }; +/* The lookups structure below includes duplicate entries for some clocks + * with alternate names. + * - The traditional name used when a device is initialised with platform data + * - The name used when a device is initialised using device tree + * The longer-term aim is to remove these duplicates, and indeed the + * lookups table entirely, by describing clocks using device tree. + */ static struct clk_lookup lookups[] = { /* main clocks */ CLKDEV_CON_ID("r_clk", &r_clk), @@ -545,6 +552,7 @@ static struct clk_lookup lookups[] = { /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */ + CLKDEV_DEV_ID("e6824000.i2c", &mstp_clks[MSTP001]), /* I2C2 */ CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[MSTP129]), /* CEU1 */ CLKDEV_DEV_ID("sh-mobile-csi2.1", &mstp_clks[MSTP128]), /* CSI2-RX1 */ CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU0 */ @@ -553,6 +561,7 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), /* TMU01 */ CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */ CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* I2C0 */ + CLKDEV_DEV_ID("e6820000.i2c", &mstp_clks[MSTP116]), /* I2C0 */ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */ CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP219]), /* SCIFA7 */ CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* SY-DMAC */ @@ -569,6 +578,7 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI */ CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */ + CLKDEV_DEV_ID("e6822000.i2c", &mstp_clks[MSTP323]), /* I2C1 */ CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP322]), /* USB */ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ @@ -579,7 +589,9 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("leds-renesas-tpu.30", &mstp_clks[MSTP301]), /* TPU3 */ CLKDEV_DEV_ID("leds-renesas-tpu.41", &mstp_clks[MSTP300]), /* TPU4 */ CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */ + CLKDEV_DEV_ID("e6826000.i2c", &mstp_clks[MSTP411]), /* I2C3 */ CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */ + CLKDEV_DEV_ID("e6828000.i2c", &mstp_clks[MSTP410]), /* I2C4 */ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ }; diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index e2ba16b6ae8e..64c0622ae7d6 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -38,7 +38,9 @@ extern void sh73a0_init_irq_dt(void); extern void sh73a0_map_io(void); extern void sh73a0_earlytimer_init(void); extern void sh73a0_add_early_devices(void); +extern void sh73a0_add_early_devices_dt(void); extern void sh73a0_add_standard_devices(void); +extern void sh73a0_add_standard_devices_dt(void); extern void sh73a0_clock_init(void); extern void sh73a0_pinmux_init(void); extern void sh73a0_pm_init(void); diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 8c2d6424f470..f7ecb0bc1bec 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -754,7 +755,7 @@ static struct platform_device pmu_device = { .resource = pmu_resources, }; -static struct platform_device *sh73a0_early_devices[] __initdata = { +static struct platform_device *sh73a0_early_devices_dt[] __initdata = { &scif0_device, &scif1_device, &scif2_device, @@ -765,6 +766,9 @@ static struct platform_device *sh73a0_early_devices[] __initdata = { &scif7_device, &scif8_device, &cmt10_device, +}; + +static struct platform_device *sh73a0_early_devices[] __initdata = { &tmu00_device, &tmu01_device, }; @@ -787,6 +791,8 @@ void __init sh73a0_add_standard_devices(void) /* Clear software reset bit on SY-DMAC module */ __raw_writel(__raw_readl(SRCR2) & ~(1 << 18), SRCR2); + platform_add_devices(sh73a0_early_devices_dt, + ARRAY_SIZE(sh73a0_early_devices_dt)); platform_add_devices(sh73a0_early_devices, ARRAY_SIZE(sh73a0_early_devices)); platform_add_devices(sh73a0_late_devices, @@ -805,9 +811,63 @@ void __init sh73a0_earlytimer_init(void) void __init sh73a0_add_early_devices(void) { + early_platform_add_devices(sh73a0_early_devices_dt, + ARRAY_SIZE(sh73a0_early_devices_dt)); early_platform_add_devices(sh73a0_early_devices, ARRAY_SIZE(sh73a0_early_devices)); /* setup early console here as well */ shmobile_setup_console(); } + +#ifdef CONFIG_USE_OF + +/* Please note that the clock initialisation shcheme used in + * sh73a0_add_early_devices_dt() and sh73a0_add_standard_devices_dt() + * does not work with SMP as there is a yet to be resolved lock-up in + * workqueue initialisation. + * + * CONFIG_SMP should be disabled when using this code. + */ + +void __init sh73a0_add_early_devices_dt(void) +{ + shmobile_setup_delay(1196, 44, 46); /* Cortex-A9 @ 1196MHz */ + + early_platform_add_devices(sh73a0_early_devices_dt, + ARRAY_SIZE(sh73a0_early_devices_dt)); + + /* setup early console here as well */ + shmobile_setup_console(); +} + +static const struct of_dev_auxdata sh73a0_auxdata_lookup[] __initconst = { + {}, +}; + +void __init sh73a0_add_standard_devices_dt(void) +{ + /* clocks are setup late during boot in the case of DT */ + sh73a0_clock_init(); + + platform_add_devices(sh73a0_early_devices_dt, + ARRAY_SIZE(sh73a0_early_devices_dt)); + of_platform_populate(NULL, of_default_bus_match_table, + sh73a0_auxdata_lookup, NULL); +} + +static const char *sh73a0_boards_compat_dt[] __initdata = { + "renesas,sh73a0", + NULL, +}; + +DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") + .map_io = sh73a0_map_io, + .init_early = sh73a0_add_early_devices_dt, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = sh73a0_init_irq_dt, + .init_machine = sh73a0_add_standard_devices_dt, + .init_time = shmobile_timer_init, + .dt_compat = sh73a0_boards_compat_dt, +MACHINE_END +#endif /* CONFIG_USE_OF */ From 93301f5dbd72bd60882f88b4d04cafa3db4c85ed Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 26 Nov 2012 18:26:17 +0900 Subject: [PATCH 032/148] ARM: mach-shmobile: sh73a0: Initialise MMCIF using DT This device also requires a voltage regulator which should be defined in a board-specific maner. An example dts snipped follows. / { fixedregulator1v8: fixedregulator@0 { compatible = "regulator-fixed"; regulator-name = "fixed-1.8V"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; }; &mmcif { vmmc-supply = <&fixedregulator1v8>; vqmmc-supply = <&fixedregulator1v8>; }; Signed-off-by: Simon Horman --- arch/arm/boot/dts/sh73a0-reference.dtsi | 24 ++++++++++++++++++++++++ arch/arm/mach-shmobile/clock-sh73a0.c | 1 + 2 files changed, 25 insertions(+) create mode 100644 arch/arm/boot/dts/sh73a0-reference.dtsi diff --git a/arch/arm/boot/dts/sh73a0-reference.dtsi b/arch/arm/boot/dts/sh73a0-reference.dtsi new file mode 100644 index 000000000000..d4bb0125b2b2 --- /dev/null +++ b/arch/arm/boot/dts/sh73a0-reference.dtsi @@ -0,0 +1,24 @@ +/* + * Device Tree Source for the SH73A0 SoC + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/include/ "sh73a0.dtsi" + +/ { + compatible = "renesas,sh73a0"; + + mmcif: mmcif@0x10010000 { + compatible = "renesas,sh-mmcif"; + reg = <0xe6bd0000 0x100>; + interrupt-parent = <&gic>; + interrupts = <0 140 0x4 + 0 141 0x4>; + reg-io-width = <4>; + }; +}; diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index eab26675c852..afa5423a0f93 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -583,6 +583,7 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */ + CLKDEV_DEV_ID("e6bd0000.mmcif", &mstp_clks[MSTP312]), /* MMCIF0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), /* SDHI2 */ CLKDEV_DEV_ID("leds-renesas-tpu.12", &mstp_clks[MSTP303]), /* TPU1 */ CLKDEV_DEV_ID("leds-renesas-tpu.21", &mstp_clks[MSTP302]), /* TPU2 */ From ff8de98d50e551057978ea90d09255c528fde1ac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 18 Jan 2013 01:40:42 -0800 Subject: [PATCH 033/148] ARM: shmobile: r8a7779: scif .irqs used SCIx_IRQ_MUXED() This patch tidyup scif .irqs settings by using SCIx_IRQ_MUXED() macro. Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7779.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index a181ced09e45..7e87ab3eb8d3 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -66,8 +66,7 @@ static struct plat_sci_port scif0_platform_data = { .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, - .irqs = { gic_spi(88), gic_spi(88), - gic_spi(88), gic_spi(88) }, + .irqs = SCIx_IRQ_MUXED(gic_spi(88)), }; static struct platform_device scif0_device = { @@ -84,8 +83,7 @@ static struct plat_sci_port scif1_platform_data = { .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, - .irqs = { gic_spi(89), gic_spi(89), - gic_spi(89), gic_spi(89) }, + .irqs = SCIx_IRQ_MUXED(gic_spi(89)), }; static struct platform_device scif1_device = { @@ -102,8 +100,7 @@ static struct plat_sci_port scif2_platform_data = { .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, - .irqs = { gic_spi(90), gic_spi(90), - gic_spi(90), gic_spi(90) }, + .irqs = SCIx_IRQ_MUXED(gic_spi(90)), }; static struct platform_device scif2_device = { @@ -120,8 +117,7 @@ static struct plat_sci_port scif3_platform_data = { .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, - .irqs = { gic_spi(91), gic_spi(91), - gic_spi(91), gic_spi(91) }, + .irqs = SCIx_IRQ_MUXED(gic_spi(91)), }; static struct platform_device scif3_device = { @@ -138,8 +134,7 @@ static struct plat_sci_port scif4_platform_data = { .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, - .irqs = { gic_spi(92), gic_spi(92), - gic_spi(92), gic_spi(92) }, + .irqs = SCIx_IRQ_MUXED(gic_spi(92)), }; static struct platform_device scif4_device = { @@ -156,8 +151,7 @@ static struct plat_sci_port scif5_platform_data = { .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, - .irqs = { gic_spi(93), gic_spi(93), - gic_spi(93), gic_spi(93) }, + .irqs = SCIx_IRQ_MUXED(gic_spi(93)), }; static struct platform_device scif5_device = { From 1a81dbde4df4e2fd94a5424b25bc78c19f446691 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 22 Nov 2012 17:10:44 -0200 Subject: [PATCH 034/148] ARM: Let CONFIG_MACH_IMX31_DT be built by default Let CONFIG_MACH_IMX31_DT be built by default. Signed-off-by: Fabio Estevam Signed-off-by: Sascha Hauer --- arch/arm/configs/imx_v6_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 69667133321f..31e143224142 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -19,6 +19,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_ARCH_MXC=y CONFIG_ARCH_MULTI_V6=y CONFIG_ARCH_MULTI_V7=y +CONFIG_MACH_IMX31_DT=y CONFIG_MACH_MX31LILLY=y CONFIG_MACH_MX31LITE=y CONFIG_MACH_PCM037=y From 8a1a9540384e06ca94296ec571f42ebcdc6c33ce Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 22 Nov 2012 17:10:45 -0200 Subject: [PATCH 035/148] ARM: clk-imx31: Add dummy clock Add dummy clock as it is required by some i.mx drivers. Signed-off-by: Fabio Estevam Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/clk-imx31.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c index 8be64e0a4ace..590dd876d66a 100644 --- a/arch/arm/mach-imx/clk-imx31.c +++ b/arch/arm/mach-imx/clk-imx31.c @@ -34,8 +34,8 @@ static const char *csi_sel[] = { "upll", "spll", }; static const char *fir_sel[] = { "mcu_main", "upll", "spll" }; enum mx31_clks { - ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg, per_div, - per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre, + dummy, ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg, + per_div, per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre, fir_div_post, sdhc1_gate, sdhc2_gate, gpt_gate, epit1_gate, epit2_gate, iim_gate, ata_gate, sdma_gate, cspi3_gate, rng_gate, uart1_gate, uart2_gate, ssi1_gate, i2c1_gate, i2c2_gate, i2c3_gate, hantro_gate, @@ -52,6 +52,7 @@ int __init mx31_clocks_init(unsigned long fref) void __iomem *base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR); int i; + clk[dummy] = imx_clk_fixed("dummy", 0); clk[ckih] = imx_clk_fixed("ckih", fref); clk[ckil] = imx_clk_fixed("ckil", 32768); clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MXC_CCM_MPCTL); From ef0e4a606fb6d30ed8b8a72df6369068bc86ac3a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 22 Nov 2012 17:10:46 -0200 Subject: [PATCH 036/148] ARM: mx31: Replace clk_register_clkdev with clock DT lookup Similarly as it was done for mx6q, use a DT lookup in order to make maintainance task for the clock devices easier. Signed-off-by: Fabio Estevam Signed-off-by: Sascha Hauer --- .../devicetree/bindings/clock/imx31-clock.txt | 91 +++++++++++++++++++ arch/arm/boot/dts/imx31.dtsi | 17 ++++ arch/arm/mach-imx/clk-imx31.c | 10 ++ arch/arm/mach-imx/imx31-dt.c | 17 +--- 4 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx31-clock.txt diff --git a/Documentation/devicetree/bindings/clock/imx31-clock.txt b/Documentation/devicetree/bindings/clock/imx31-clock.txt new file mode 100644 index 000000000000..19df842c694f --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx31-clock.txt @@ -0,0 +1,91 @@ +* Clock bindings for Freescale i.MX31 + +Required properties: +- compatible: Should be "fsl,imx31-ccm" +- reg: Address and length of the register set +- interrupts: Should contain CCM interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX31 +clocks and IDs. + + Clock ID + ----------------------- + dummy 0 + ckih 1 + ckil 2 + mpll 3 + spll 4 + upll 5 + mcu_main 6 + hsp 7 + ahb 8 + nfc 9 + ipg 10 + per_div 11 + per 12 + csi_sel 13 + fir_sel 14 + csi_div 15 + usb_div_pre 16 + usb_div_post 17 + fir_div_pre 18 + fir_div_post 19 + sdhc1_gate 20 + sdhc2_gate 21 + gpt_gate 22 + epit1_gate 23 + epit2_gate 24 + iim_gate 25 + ata_gate 26 + sdma_gate 27 + cspi3_gate 28 + rng_gate 29 + uart1_gate 30 + uart2_gate 31 + ssi1_gate 32 + i2c1_gate 33 + i2c2_gate 34 + i2c3_gate 35 + hantro_gate 36 + mstick1_gate 37 + mstick2_gate 38 + csi_gate 39 + rtc_gate 40 + wdog_gate 41 + pwm_gate 42 + sim_gate 43 + ect_gate 44 + usb_gate 45 + kpp_gate 46 + ipu_gate 47 + uart3_gate 48 + uart4_gate 49 + uart5_gate 50 + owire_gate 51 + ssi2_gate 52 + cspi1_gate 53 + cspi2_gate 54 + gacc_gate 55 + emi_gate 56 + rtic_gate 57 + firi_gate 58 + +Examples: + +clks: ccm@53f80000{ + compatible = "fsl,imx31-ccm"; + reg = <0x53f80000 0x4000>; + interrupts = <0 31 0x04 0 53 0x04>; + #clock-cells = <1>; +}; + +uart1: serial@43f90000 { + compatible = "fsl,imx31-uart", "fsl,imx21-uart"; + reg = <0x43f90000 0x4000>; + interrupts = <45>; + clocks = <&clks 10>, <&clks 30>; + clock-names = "ipg", "per"; + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx31.dtsi b/arch/arm/boot/dts/imx31.dtsi index eef7099f3e3c..454c2d175402 100644 --- a/arch/arm/boot/dts/imx31.dtsi +++ b/arch/arm/boot/dts/imx31.dtsi @@ -45,6 +45,8 @@ compatible = "fsl,imx31-uart", "fsl,imx21-uart"; reg = <0x43f90000 0x4000>; interrupts = <45>; + clocks = <&clks 10>, <&clks 30>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -52,12 +54,16 @@ compatible = "fsl,imx31-uart", "fsl,imx21-uart"; reg = <0x43f94000 0x4000>; interrupts = <32>; + clocks = <&clks 10>, <&clks 31>; + clock-names = "ipg", "per"; status = "disabled"; }; uart4: serial@43fb0000 { compatible = "fsl,imx31-uart", "fsl,imx21-uart"; reg = <0x43fb0000 0x4000>; + clocks = <&clks 10>, <&clks 49>; + clock-names = "ipg", "per"; interrupts = <46>; status = "disabled"; }; @@ -66,6 +72,8 @@ compatible = "fsl,imx31-uart", "fsl,imx21-uart"; reg = <0x43fb4000 0x4000>; interrupts = <47>; + clocks = <&clks 10>, <&clks 50>; + clock-names = "ipg", "per"; status = "disabled"; }; }; @@ -81,8 +89,17 @@ compatible = "fsl,imx31-uart", "fsl,imx21-uart"; reg = <0x5000c000 0x4000>; interrupts = <18>; + clocks = <&clks 10>, <&clks 48>; + clock-names = "ipg", "per"; status = "disabled"; }; + + clks: ccm@53f80000{ + compatible = "fsl,imx31-ccm"; + reg = <0x53f80000 0x4000>; + interrupts = <0 31 0x04 0 53 0x04>; + #clock-cells = <1>; + }; }; }; }; diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c index 590dd876d66a..a42494d22c59 100644 --- a/arch/arm/mach-imx/clk-imx31.c +++ b/arch/arm/mach-imx/clk-imx31.c @@ -46,11 +46,13 @@ enum mx31_clks { }; static struct clk *clk[clk_max]; +static struct clk_onecell_data clk_data; int __init mx31_clocks_init(unsigned long fref) { void __iomem *base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR); int i; + struct device_node *np; clk[dummy] = imx_clk_fixed("dummy", 0); clk[ckih] = imx_clk_fixed("ckih", fref); @@ -117,6 +119,14 @@ int __init mx31_clocks_init(unsigned long fref) pr_err("imx31 clk %d: register failed with %ld\n", i, PTR_ERR(clk[i])); + np = of_find_compatible_node(NULL, NULL, "fsl,imx31-ccm"); + + if (np) { + clk_data.clks = clk; + clk_data.clk_num = ARRAY_SIZE(clk); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + } + clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); clk_register_clkdev(clk[cspi1_gate], NULL, "imx31-cspi.0"); diff --git a/arch/arm/mach-imx/imx31-dt.c b/arch/arm/mach-imx/imx31-dt.c index af476de2570e..dc083d33a758 100644 --- a/arch/arm/mach-imx/imx31-dt.c +++ b/arch/arm/mach-imx/imx31-dt.c @@ -18,24 +18,9 @@ #include "common.h" #include "mx31.h" -static const struct of_dev_auxdata imx31_auxdata_lookup[] __initconst = { - OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART1_BASE_ADDR, - "imx21-uart.0", NULL), - OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART2_BASE_ADDR, - "imx21-uart.1", NULL), - OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART3_BASE_ADDR, - "imx21-uart.2", NULL), - OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART4_BASE_ADDR, - "imx21-uart.3", NULL), - OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART5_BASE_ADDR, - "imx21-uart.4", NULL), - { /* sentinel */ } -}; - static void __init imx31_dt_init(void) { - of_platform_populate(NULL, of_default_bus_match_table, - imx31_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static void __init imx31_timer_init(void) From b7eed2076183994dbda2c19bc7fba99b65a135e3 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sun, 13 Jan 2013 15:15:01 +0100 Subject: [PATCH 037/148] ARM: imx27: add a clock gate to activate SPLL clock A clock gate is mandatory to activate SPLL clock needed, at least, for usb. Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/clk-imx27.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index 4c1d1e4efc74..4f066d1383fe 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -62,7 +62,7 @@ static const char *clko_sel_clks[] = { "32k", "usb_div", "dptc", }; -static const char *ssi_sel_clks[] = { "spll", "mpll", }; +static const char *ssi_sel_clks[] = { "spll_gate", "mpll", }; enum mx27_clks { dummy, ckih, ckil, mpll, spll, mpll_main2, ahb, ipg, nfc_div, per1_div, @@ -82,7 +82,7 @@ enum mx27_clks { csi_ahb_gate, brom_ahb_gate, ata_ahb_gate, wdog_ipg_gate, usb_ipg_gate, uart6_ipg_gate, uart5_ipg_gate, uart4_ipg_gate, uart3_ipg_gate, uart2_ipg_gate, uart1_ipg_gate, ckih_div1p5, fpm, mpll_osc_sel, - mpll_sel, clk_max + mpll_sel, spll_gate, clk_max }; static struct clk *clk[clk_max]; @@ -104,6 +104,7 @@ int __init mx27_clocks_init(unsigned long fref) ARRAY_SIZE(mpll_sel_clks)); clk[mpll] = imx_clk_pllv1("mpll", "mpll_sel", CCM_MPCTL0); clk[spll] = imx_clk_pllv1("spll", "ckih", CCM_SPCTL0); + clk[spll_gate] = imx_clk_gate("spll_gate", "spll", CCM_CSCR, 1); clk[mpll_main2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3); if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { @@ -121,7 +122,7 @@ int __init mx27_clocks_init(unsigned long fref) clk[per4_div] = imx_clk_divider("per4_div", "mpll_main2", CCM_PCDR1, 24, 6); clk[vpu_sel] = imx_clk_mux("vpu_sel", CCM_CSCR, 21, 1, vpu_sel_clks, ARRAY_SIZE(vpu_sel_clks)); clk[vpu_div] = imx_clk_divider("vpu_div", "vpu_sel", CCM_PCDR0, 10, 6); - clk[usb_div] = imx_clk_divider("usb_div", "spll", CCM_CSCR, 28, 3); + clk[usb_div] = imx_clk_divider("usb_div", "spll_gate", CCM_CSCR, 28, 3); clk[cpu_sel] = imx_clk_mux("cpu_sel", CCM_CSCR, 15, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks)); clk[clko_sel] = imx_clk_mux("clko_sel", CCM_CCSR, 0, 5, clko_sel_clks, ARRAY_SIZE(clko_sel_clks)); if (mx27_revision() >= IMX_CHIP_REVISION_2_0) From 3ea8098572280d16163a429e0f8dfd90492a5934 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 8 Jan 2013 23:37:01 -0200 Subject: [PATCH 038/148] ARM: clk-imx35: Fix build warnings with W=1 Fix the following warnings when building with W=1 option: arch/arm/mach-imx/clk-imx35.c: In function 'mx35_clocks_init': arch/arm/mach-imx/clk-imx35.c:70:12: warning: old-style function definition [-Wold-style-definition] arch/arm/mach-imx/clk-imx35.c:201:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] Signed-off-by: Fabio Estevam Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/clk-imx35.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c index 66f3d65ea275..219ab6c35e1e 100644 --- a/arch/arm/mach-imx/clk-imx35.c +++ b/arch/arm/mach-imx/clk-imx35.c @@ -67,13 +67,13 @@ enum mx35_clks { static struct clk *clk[clk_max]; -int __init mx35_clocks_init() +int __init mx35_clocks_init(void) { void __iomem *base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR); u32 pdr0, consumer_sel, hsp_sel; struct arm_ahb_div *aad; unsigned char *hsp_div; - int i; + u32 i; pdr0 = __raw_readl(base + MXC_CCM_PDR0); consumer_sel = (pdr0 >> 16) & 0xf; From c1d1cd597fc77af3086470f8627d77f52f7f8b6c Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:48:53 -0700 Subject: [PATCH 039/148] ARM: OMAP2+: omap_device: remove obsolete pm_lats and early_device code Remove now-obsolete code from arch/arm/mach-omap2/omap_device.c. This mostly consists of removing the first attempt at device PM latency handling. This was never really used, has been replaced by the common dev_pm_qos code, and needs to go away as part of the DT conversion. Also, the early platform_device creation code has been removed, as it appears to be unused. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/am35xx-emac.c | 2 +- arch/arm/mach-omap2/devices.c | 25 +- arch/arm/mach-omap2/display.c | 2 +- arch/arm/mach-omap2/dma.c | 2 +- arch/arm/mach-omap2/drm.c | 3 +- arch/arm/mach-omap2/gpio.c | 3 +- arch/arm/mach-omap2/gpmc.c | 2 +- arch/arm/mach-omap2/hdq1w.c | 2 +- arch/arm/mach-omap2/hsmmc.c | 2 +- arch/arm/mach-omap2/hwspinlock.c | 3 +- arch/arm/mach-omap2/i2c.c | 3 +- arch/arm/mach-omap2/mcbsp.c | 2 +- arch/arm/mach-omap2/msdi.c | 2 +- arch/arm/mach-omap2/omap-iommu.c | 3 +- arch/arm/mach-omap2/omap_device.c | 537 ++++-------------------------- arch/arm/mach-omap2/omap_device.h | 79 +---- arch/arm/mach-omap2/pm.c | 4 +- arch/arm/mach-omap2/pmu.c | 3 +- arch/arm/mach-omap2/serial.c | 3 +- arch/arm/mach-omap2/sr_device.c | 3 +- arch/arm/mach-omap2/timer.c | 3 +- arch/arm/mach-omap2/usb-host.c | 16 +- arch/arm/mach-omap2/usb-musb.c | 2 +- arch/arm/mach-omap2/wd_timer.c | 3 +- 24 files changed, 99 insertions(+), 610 deletions(-) diff --git a/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c index af11dcdb7e2c..a00d39107a21 100644 --- a/arch/arm/mach-omap2/am35xx-emac.c +++ b/arch/arm/mach-omap2/am35xx-emac.c @@ -63,7 +63,7 @@ static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh, struct platform_device *pdev; pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len, - NULL, 0, false); + false); if (IS_ERR(pdev)) { WARN(1, "Can't build omap_device for %s:%s.\n", oh->class->name, oh->name); diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 626f3ea3142f..d8a0cc3b9d2c 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -61,8 +61,7 @@ static int __init omap3_l3_init(void) if (!oh) pr_err("could not look up %s\n", oh_name); - pdev = omap_device_build("omap_l3_smx", 0, oh, NULL, 0, - NULL, 0, 0); + pdev = omap_device_build("omap_l3_smx", 0, oh, NULL, 0); WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name); @@ -96,8 +95,7 @@ static int __init omap4_l3_init(void) pr_err("could not look up %s\n", oh_name); } - pdev = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL, - 0, NULL, 0, 0); + pdev = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL, 0); WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name); @@ -273,7 +271,7 @@ int __init omap4_keyboard_init(struct omap4_keypad_platform_data keypad_data = sdp4430_keypad_data; pdev = omap_device_build(name, id, oh, keypad_data, - sizeof(struct omap4_keypad_platform_data), NULL, 0, 0); + sizeof(struct omap4_keypad_platform_data)); if (IS_ERR(pdev)) { WARN(1, "Can't build omap_device for %s:%s.\n", @@ -297,7 +295,7 @@ static inline void __init omap_init_mbox(void) return; } - pdev = omap_device_build("omap-mailbox", -1, oh, NULL, 0, NULL, 0, 0); + pdev = omap_device_build("omap-mailbox", -1, oh, NULL, 0); WARN(IS_ERR(pdev), "%s: could not build device, err %ld\n", __func__, PTR_ERR(pdev)); } @@ -337,7 +335,7 @@ static void __init omap_init_mcpdm(void) return; } - pdev = omap_device_build("omap-mcpdm", -1, oh, NULL, 0, NULL, 0, 0); + pdev = omap_device_build("omap-mcpdm", -1, oh, NULL, 0); WARN(IS_ERR(pdev), "Can't build omap_device for omap-mcpdm.\n"); } #else @@ -358,7 +356,7 @@ static void __init omap_init_dmic(void) return; } - pdev = omap_device_build("omap-dmic", -1, oh, NULL, 0, NULL, 0, 0); + pdev = omap_device_build("omap-dmic", -1, oh, NULL, 0); WARN(IS_ERR(pdev), "Can't build omap_device for omap-dmic.\n"); } #else @@ -384,8 +382,7 @@ static void __init omap_init_hdmi_audio(void) return; } - pdev = omap_device_build("omap-hdmi-audio-dai", - -1, oh, NULL, 0, NULL, 0, 0); + pdev = omap_device_build("omap-hdmi-audio-dai", -1, oh, NULL, 0, 0); WARN(IS_ERR(pdev), "Can't build omap_device for omap-hdmi-audio-dai.\n"); @@ -429,8 +426,7 @@ static int __init omap_mcspi_init(struct omap_hwmod *oh, void *unused) } spi_num++; - pdev = omap_device_build(name, spi_num, oh, pdata, - sizeof(*pdata), NULL, 0, 0); + pdev = omap_device_build(name, spi_num, oh, pdata, sizeof(*pdata)); WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s\n", name, oh->name); kfree(pdata); @@ -460,7 +456,7 @@ static void omap_init_rng(void) if (!oh) return; - pdev = omap_device_build("omap_rng", -1, oh, NULL, 0, NULL, 0, 0); + pdev = omap_device_build("omap_rng", -1, oh, NULL, 0); WARN(IS_ERR(pdev), "Can't build omap_device for omap_rng\n"); } @@ -689,8 +685,7 @@ static void __init omap_init_ocp2scp(void) pdata->dev_cnt = dev_cnt; - pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata), NULL, - 0, false); + pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata)); if (IS_ERR(pdev)) { pr_err("Could not build omap_device for %s %s\n", name, oh_name); diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index cc75aaf6e764..ff37be1f6f93 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -226,7 +226,7 @@ static struct platform_device *create_dss_pdev(const char *pdev_name, dev_set_name(&pdev->dev, "%s", pdev->name); ohs[0] = oh; - od = omap_device_alloc(pdev, ohs, 1, NULL, 0); + od = omap_device_alloc(pdev, ohs, 1); if (IS_ERR(od)) { pr_err("Could not alloc omap_device for %s\n", pdev_name); r = -ENOMEM; diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c index 612b98249873..491c5c8837fa 100644 --- a/arch/arm/mach-omap2/dma.c +++ b/arch/arm/mach-omap2/dma.c @@ -248,7 +248,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) p->errata = configure_dma_errata(); - pdev = omap_device_build(name, 0, oh, p, sizeof(*p), NULL, 0, 0); + pdev = omap_device_build(name, 0, oh, p, sizeof(*p)); kfree(p); if (IS_ERR(pdev)) { pr_err("%s: Can't build omap_device for %s:%s.\n", diff --git a/arch/arm/mach-omap2/drm.c b/arch/arm/mach-omap2/drm.c index 2a2cfa88ddbf..4d8d1a52ffe7 100644 --- a/arch/arm/mach-omap2/drm.c +++ b/arch/arm/mach-omap2/drm.c @@ -51,8 +51,7 @@ static int __init omap_init_drm(void) oh = omap_hwmod_lookup("dmm"); if (oh) { - pdev = omap_device_build(oh->name, -1, oh, NULL, 0, NULL, 0, - false); + pdev = omap_device_build(oh->name, -1, oh, NULL, 0); WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", oh->name); } diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c index 399acabc3d0b..482ade1923b0 100644 --- a/arch/arm/mach-omap2/gpio.c +++ b/arch/arm/mach-omap2/gpio.c @@ -131,8 +131,7 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) pwrdm = omap_hwmod_get_pwrdm(oh); pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm); - pdev = omap_device_build(name, id - 1, oh, pdata, - sizeof(*pdata), NULL, 0, false); + pdev = omap_device_build(name, id - 1, oh, pdata, sizeof(*pdata)); kfree(pdata); if (IS_ERR(pdev)) { diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 8033cb747c86..bc0783364ad3 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1220,7 +1220,7 @@ static int __init omap_gpmc_init(void) return -ENODEV; } - pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0, NULL, 0, 0); + pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0); WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name); return IS_ERR(pdev) ? PTR_ERR(pdev) : 0; diff --git a/arch/arm/mach-omap2/hdq1w.c b/arch/arm/mach-omap2/hdq1w.c index ab7bf181a105..b7aa8ba2ccb2 100644 --- a/arch/arm/mach-omap2/hdq1w.c +++ b/arch/arm/mach-omap2/hdq1w.c @@ -87,7 +87,7 @@ static int __init omap_init_hdq(void) if (!oh) return 0; - pdev = omap_device_build(devname, id, oh, NULL, 0, NULL, 0, 0); + pdev = omap_device_build(devname, id, oh, NULL, 0); WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s.\n", devname, oh->name); diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 4a964338992a..2ef1f8714fcf 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -522,7 +522,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, } dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); - od = omap_device_alloc(pdev, ohs, 1, NULL, 0); + od = omap_device_alloc(pdev, ohs, 1); if (IS_ERR(od)) { pr_err("Could not allocate od for %s\n", name); goto put_pdev; diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c index 1df9b5feda16..c3688903f3d4 100644 --- a/arch/arm/mach-omap2/hwspinlock.c +++ b/arch/arm/mach-omap2/hwspinlock.c @@ -46,8 +46,7 @@ static int __init hwspinlocks_init(void) return -EINVAL; pdev = omap_device_build(dev_name, 0, oh, &omap_hwspinlock_pdata, - sizeof(struct hwspinlock_pdata), - NULL, 0, false); + sizeof(struct hwspinlock_pdata)); if (IS_ERR(pdev)) { pr_err("Can't build omap_device for %s:%s\n", dev_name, oh_name); diff --git a/arch/arm/mach-omap2/i2c.c b/arch/arm/mach-omap2/i2c.c index b9074dde3b9c..c11a23fa9665 100644 --- a/arch/arm/mach-omap2/i2c.c +++ b/arch/arm/mach-omap2/i2c.c @@ -178,8 +178,7 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata, if (cpu_is_omap34xx()) pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; pdev = omap_device_build(name, bus_id, oh, pdata, - sizeof(struct omap_i2c_bus_platform_data), - NULL, 0, 0); + sizeof(struct omap_i2c_bus_platform_data)); WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", name); return PTR_RET(pdev); diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index df49f2a49461..453580410ae0 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -101,7 +101,7 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused) count++; } pdev = omap_device_build_ss(name, id, oh_device, count, pdata, - sizeof(*pdata), NULL, 0, false); + sizeof(*pdata)); kfree(pdata); if (IS_ERR(pdev)) { pr_err("%s: Can't build omap_device for %s:%s.\n", __func__, diff --git a/arch/arm/mach-omap2/msdi.c b/arch/arm/mach-omap2/msdi.c index aafdd4ca9f4f..c52d8b4a3e91 100644 --- a/arch/arm/mach-omap2/msdi.c +++ b/arch/arm/mach-omap2/msdi.c @@ -150,7 +150,7 @@ void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data) return; } pdev = omap_device_build(dev_name, id, oh, mmc_data[0], - sizeof(struct omap_mmc_platform_data), NULL, 0, 0); + sizeof(struct omap_mmc_platform_data)); if (IS_ERR(pdev)) WARN(1, "Can'd build omap_device for %s:%s.\n", dev_name, oh->name); diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index 6da4f7ae9d7f..f7f38c7fd5ff 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -41,8 +41,7 @@ static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused) pdata->deassert_reset = omap_device_deassert_hardreset; } - pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata), - NULL, 0, 0); + pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata)); kfree(pdata); diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index e065daa537c0..6ee3ad3dd95a 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -17,68 +17,15 @@ * to control power management and interconnect properties of their * devices. * - * In the medium- to long-term, this code should either be - * a) implemented via arch-specific pointers in platform_data - * or - * b) implemented as a proper omap_bus/omap_device in Linux, no more - * platform_data func pointers + * In the medium- to long-term, this code should be implemented as a + * proper omap_bus/omap_device in Linux, no more platform_data func + * pointers * * - * Guidelines for usage by driver authors: - * - * 1. These functions are intended to be used by device drivers via - * function pointers in struct platform_data. As an example, - * omap_device_enable() should be passed to the driver as - * - * struct foo_driver_platform_data { - * ... - * int (*device_enable)(struct platform_device *pdev); - * ... - * } - * - * Note that the generic "device_enable" name is used, rather than - * "omap_device_enable". This is so other architectures can pass in their - * own enable/disable functions here. - * - * This should be populated during device setup: - * - * ... - * pdata->device_enable = omap_device_enable; - * ... - * - * 2. Drivers should first check to ensure the function pointer is not null - * before calling it, as in: - * - * if (pdata->device_enable) - * pdata->device_enable(pdev); - * - * This allows other architectures that don't use similar device_enable()/ - * device_shutdown() functions to execute normally. - * - * ... - * - * Suggested usage by device drivers: - * - * During device initialization: - * device_enable() - * - * During device idle: - * (save remaining device context if necessary) - * device_idle(); - * - * During device resume: - * device_enable(); - * (restore context if necessary) - * - * During device shutdown: - * device_shutdown() - * (device must be reinitialized at this point to use it again) - * */ #undef DEBUG #include -#include #include #include #include @@ -92,155 +39,8 @@ #include "omap_device.h" #include "omap_hwmod.h" -/* These parameters are passed to _omap_device_{de,}activate() */ -#define USE_WAKEUP_LAT 0 -#define IGNORE_WAKEUP_LAT 1 - -static int omap_early_device_register(struct platform_device *pdev); - -static struct omap_device_pm_latency omap_default_latency[] = { - { - .deactivate_func = omap_device_idle_hwmods, - .activate_func = omap_device_enable_hwmods, - .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, - } -}; - /* Private functions */ -/** - * _omap_device_activate - increase device readiness - * @od: struct omap_device * - * @ignore_lat: increase to latency target (0) or full readiness (1)? - * - * Increase readiness of omap_device @od (thus decreasing device - * wakeup latency, but consuming more power). If @ignore_lat is - * IGNORE_WAKEUP_LAT, make the omap_device fully active. Otherwise, - * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup - * latency is greater than the requested maximum wakeup latency, step - * backwards in the omap_device_pm_latency table to ensure the - * device's maximum wakeup latency is less than or equal to the - * requested maximum wakeup latency. Returns 0. - */ -static int _omap_device_activate(struct omap_device *od, u8 ignore_lat) -{ - struct timespec a, b, c; - - dev_dbg(&od->pdev->dev, "omap_device: activating\n"); - - while (od->pm_lat_level > 0) { - struct omap_device_pm_latency *odpl; - unsigned long long act_lat = 0; - - od->pm_lat_level--; - - odpl = od->pm_lats + od->pm_lat_level; - - if (!ignore_lat && - (od->dev_wakeup_lat <= od->_dev_wakeup_lat_limit)) - break; - - read_persistent_clock(&a); - - /* XXX check return code */ - odpl->activate_func(od); - - read_persistent_clock(&b); - - c = timespec_sub(b, a); - act_lat = timespec_to_ns(&c); - - dev_dbg(&od->pdev->dev, - "omap_device: pm_lat %d: activate: elapsed time %llu nsec\n", - od->pm_lat_level, act_lat); - - if (act_lat > odpl->activate_lat) { - odpl->activate_lat_worst = act_lat; - if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) { - odpl->activate_lat = act_lat; - dev_dbg(&od->pdev->dev, - "new worst case activate latency %d: %llu\n", - od->pm_lat_level, act_lat); - } else - dev_warn(&od->pdev->dev, - "activate latency %d higher than expected. (%llu > %d)\n", - od->pm_lat_level, act_lat, - odpl->activate_lat); - } - - od->dev_wakeup_lat -= odpl->activate_lat; - } - - return 0; -} - -/** - * _omap_device_deactivate - decrease device readiness - * @od: struct omap_device * - * @ignore_lat: decrease to latency target (0) or full inactivity (1)? - * - * Decrease readiness of omap_device @od (thus increasing device - * wakeup latency, but conserving power). If @ignore_lat is - * IGNORE_WAKEUP_LAT, make the omap_device fully inactive. Otherwise, - * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup - * latency is less than the requested maximum wakeup latency, step - * forwards in the omap_device_pm_latency table to ensure the device's - * maximum wakeup latency is less than or equal to the requested - * maximum wakeup latency. Returns 0. - */ -static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat) -{ - struct timespec a, b, c; - - dev_dbg(&od->pdev->dev, "omap_device: deactivating\n"); - - while (od->pm_lat_level < od->pm_lats_cnt) { - struct omap_device_pm_latency *odpl; - unsigned long long deact_lat = 0; - - odpl = od->pm_lats + od->pm_lat_level; - - if (!ignore_lat && - ((od->dev_wakeup_lat + odpl->activate_lat) > - od->_dev_wakeup_lat_limit)) - break; - - read_persistent_clock(&a); - - /* XXX check return code */ - odpl->deactivate_func(od); - - read_persistent_clock(&b); - - c = timespec_sub(b, a); - deact_lat = timespec_to_ns(&c); - - dev_dbg(&od->pdev->dev, - "omap_device: pm_lat %d: deactivate: elapsed time %llu nsec\n", - od->pm_lat_level, deact_lat); - - if (deact_lat > odpl->deactivate_lat) { - odpl->deactivate_lat_worst = deact_lat; - if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) { - odpl->deactivate_lat = deact_lat; - dev_dbg(&od->pdev->dev, - "new worst case deactivate latency %d: %llu\n", - od->pm_lat_level, deact_lat); - } else - dev_warn(&od->pdev->dev, - "deactivate latency %d higher than expected. (%llu > %d)\n", - od->pm_lat_level, deact_lat, - odpl->deactivate_lat); - } - - od->dev_wakeup_lat += odpl->activate_lat; - - od->pm_lat_level++; - } - - return 0; -} - static void _add_clkdev(struct omap_device *od, const char *clk_alias, const char *clk_name) { @@ -315,9 +115,6 @@ static void _add_hwmod_clocks_clkdev(struct omap_device *od, * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata - * @pm_lats: pointer to a omap_device_pm_latency array for this device - * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats - * @is_early_device: should the device be registered as an early device or not * * Function for building an omap_device already registered from device-tree * @@ -356,7 +153,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev) hwmods[i] = oh; } - od = omap_device_alloc(pdev, hwmods, oh_cnt, NULL, 0); + od = omap_device_alloc(pdev, hwmods, oh_cnt); if (!od) { dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n", oh_name); @@ -407,6 +204,39 @@ static int _omap_device_notifier_call(struct notifier_block *nb, return NOTIFY_DONE; } +/** + * _omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods + * @od: struct omap_device *od + * + * Enable all underlying hwmods. Returns 0. + */ +static int _omap_device_enable_hwmods(struct omap_device *od) +{ + int i; + + for (i = 0; i < od->hwmods_cnt; i++) + omap_hwmod_enable(od->hwmods[i]); + + /* XXX pass along return value here? */ + return 0; +} + +/** + * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods + * @od: struct omap_device *od + * + * Idle all underlying hwmods. Returns 0. + */ +static int _omap_device_idle_hwmods(struct omap_device *od) +{ + int i; + + for (i = 0; i < od->hwmods_cnt; i++) + omap_hwmod_idle(od->hwmods[i]); + + /* XXX pass along return value here? */ + return 0; +} /* Public functions for use by core code */ @@ -526,18 +356,14 @@ static int _od_fill_dma_resources(struct omap_device *od, * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata - * @pm_lats: pointer to a omap_device_pm_latency array for this device - * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats * * Convenience function for allocating an omap_device structure and filling - * hwmods, resources and pm_latency attributes. + * hwmods, and resources. * * Returns an struct omap_device pointer or ERR_PTR() on error; */ struct omap_device *omap_device_alloc(struct platform_device *pdev, - struct omap_hwmod **ohs, int oh_cnt, - struct omap_device_pm_latency *pm_lats, - int pm_lats_cnt) + struct omap_hwmod **ohs, int oh_cnt) { int ret = -ENOMEM; struct omap_device *od; @@ -626,18 +452,6 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev, goto oda_exit3; have_everything: - if (!pm_lats) { - pm_lats = omap_default_latency; - pm_lats_cnt = ARRAY_SIZE(omap_default_latency); - } - - od->pm_lats_cnt = pm_lats_cnt; - od->pm_lats = kmemdup(pm_lats, - sizeof(struct omap_device_pm_latency) * pm_lats_cnt, - GFP_KERNEL); - if (!od->pm_lats) - goto oda_exit3; - pdev->archdata.od = od; for (i = 0; i < oh_cnt; i++) { @@ -663,7 +477,6 @@ void omap_device_delete(struct omap_device *od) return; od->pdev->archdata.od = NULL; - kfree(od->pm_lats); kfree(od->hwmods); kfree(od); } @@ -675,9 +488,6 @@ void omap_device_delete(struct omap_device *od) * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata - * @pm_lats: pointer to a omap_device_pm_latency array for this device - * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats - * @is_early_device: should the device be registered as an early device or not * * Convenience function for building and registering a single * omap_device record, which in turn builds and registers a @@ -685,11 +495,10 @@ void omap_device_delete(struct omap_device *od) * information. Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise, * passes along the return value of omap_device_build_ss(). */ -struct platform_device __init *omap_device_build(const char *pdev_name, int pdev_id, - struct omap_hwmod *oh, void *pdata, - int pdata_len, - struct omap_device_pm_latency *pm_lats, - int pm_lats_cnt, int is_early_device) +struct platform_device __init *omap_device_build(const char *pdev_name, + int pdev_id, + struct omap_hwmod *oh, + void *pdata, int pdata_len) { struct omap_hwmod *ohs[] = { oh }; @@ -697,8 +506,7 @@ struct platform_device __init *omap_device_build(const char *pdev_name, int pdev return ERR_PTR(-EINVAL); return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata, - pdata_len, pm_lats, pm_lats_cnt, - is_early_device); + pdata_len); } /** @@ -708,9 +516,6 @@ struct platform_device __init *omap_device_build(const char *pdev_name, int pdev * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata - * @pm_lats: pointer to a omap_device_pm_latency array for this device - * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats - * @is_early_device: should the device be registered as an early device or not * * Convenience function for building and registering an omap_device * subsystem record. Subsystem records consist of multiple @@ -718,11 +523,11 @@ struct platform_device __init *omap_device_build(const char *pdev_name, int pdev * platform_device record. Returns an ERR_PTR() on error, or passes * along the return value of omap_device_register(). */ -struct platform_device __init *omap_device_build_ss(const char *pdev_name, int pdev_id, - struct omap_hwmod **ohs, int oh_cnt, - void *pdata, int pdata_len, - struct omap_device_pm_latency *pm_lats, - int pm_lats_cnt, int is_early_device) +struct platform_device __init *omap_device_build_ss(const char *pdev_name, + int pdev_id, + struct omap_hwmod **ohs, + int oh_cnt, void *pdata, + int pdata_len) { int ret = -ENOMEM; struct platform_device *pdev; @@ -746,7 +551,7 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, int p else dev_set_name(&pdev->dev, "%s", pdev->name); - od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt); + od = omap_device_alloc(pdev, ohs, oh_cnt); if (IS_ERR(od)) goto odbs_exit1; @@ -754,10 +559,7 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, int p if (ret) goto odbs_exit2; - if (is_early_device) - ret = omap_early_device_register(pdev); - else - ret = omap_device_register(pdev); + ret = omap_device_register(pdev); if (ret) goto odbs_exit2; @@ -774,24 +576,6 @@ odbs_exit: return ERR_PTR(ret); } -/** - * omap_early_device_register - register an omap_device as an early platform - * device. - * @od: struct omap_device * to register - * - * Register the omap_device structure. This currently just calls - * platform_early_add_device() on the underlying platform_device. - * Returns 0 by default. - */ -static int __init omap_early_device_register(struct platform_device *pdev) -{ - struct platform_device *devices[1]; - - devices[0] = pdev; - early_platform_add_devices(devices, 1); - return 0; -} - #ifdef CONFIG_PM_RUNTIME static int _od_runtime_suspend(struct device *dev) { @@ -902,10 +686,9 @@ int omap_device_register(struct platform_device *pdev) * to be accessible and ready to operate. This generally involves * enabling clocks, setting SYSCONFIG registers; and in the future may * involve remuxing pins. Device drivers should call this function - * (through platform_data function pointers) where they would normally - * enable clocks, etc. Returns -EINVAL if called when the omap_device - * is already enabled, or passes along the return value of - * _omap_device_activate(). + * indirectly via pm_runtime_get*(). Returns -EINVAL if called when + * the omap_device is already enabled, or passes along the return + * value of _omap_device_enable_hwmods(). */ int omap_device_enable(struct platform_device *pdev) { @@ -921,14 +704,8 @@ int omap_device_enable(struct platform_device *pdev) return -EINVAL; } - /* Enable everything if we're enabling this device from scratch */ - if (od->_state == OMAP_DEVICE_STATE_UNKNOWN) - od->pm_lat_level = od->pm_lats_cnt; + ret = _omap_device_enable_hwmods(od); - ret = _omap_device_activate(od, IGNORE_WAKEUP_LAT); - - od->dev_wakeup_lat = 0; - od->_dev_wakeup_lat_limit = UINT_MAX; od->_state = OMAP_DEVICE_STATE_ENABLED; return ret; @@ -938,14 +715,10 @@ int omap_device_enable(struct platform_device *pdev) * omap_device_idle - idle an omap_device * @od: struct omap_device * to idle * - * Idle omap_device @od by calling as many .deactivate_func() entries - * in the omap_device's pm_lats table as is possible without exceeding - * the device's maximum wakeup latency limit, pm_lat_limit. Device - * drivers should call this function (through platform_data function - * pointers) where they would normally disable clocks after operations - * complete, etc.. Returns -EINVAL if the omap_device is not + * Idle omap_device @od. Device drivers call this function indirectly + * via pm_runtime_put*(). Returns -EINVAL if the omap_device is not * currently enabled, or passes along the return value of - * _omap_device_deactivate(). + * _omap_device_idle_hwmods(). */ int omap_device_idle(struct platform_device *pdev) { @@ -961,49 +734,13 @@ int omap_device_idle(struct platform_device *pdev) return -EINVAL; } - ret = _omap_device_deactivate(od, USE_WAKEUP_LAT); + ret = _omap_device_idle_hwmods(od); od->_state = OMAP_DEVICE_STATE_IDLE; return ret; } -/** - * omap_device_shutdown - shut down an omap_device - * @od: struct omap_device * to shut down - * - * Shut down omap_device @od by calling all .deactivate_func() entries - * in the omap_device's pm_lats table and then shutting down all of - * the underlying omap_hwmods. Used when a device is being "removed" - * or a device driver is being unloaded. Returns -EINVAL if the - * omap_device is not currently enabled or idle, or passes along the - * return value of _omap_device_deactivate(). - */ -int omap_device_shutdown(struct platform_device *pdev) -{ - int ret, i; - struct omap_device *od; - - od = to_omap_device(pdev); - - if (od->_state != OMAP_DEVICE_STATE_ENABLED && - od->_state != OMAP_DEVICE_STATE_IDLE) { - dev_warn(&pdev->dev, - "omap_device: %s() called from invalid state %d\n", - __func__, od->_state); - return -EINVAL; - } - - ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT); - - for (i = 0; i < od->hwmods_cnt; i++) - omap_hwmod_shutdown(od->hwmods[i]); - - od->_state = OMAP_DEVICE_STATE_SHUTDOWN; - - return ret; -} - /** * omap_device_assert_hardreset - set a device's hardreset line * @pdev: struct platform_device * to reset @@ -1059,86 +796,6 @@ int omap_device_deassert_hardreset(struct platform_device *pdev, return ret; } -/** - * omap_device_align_pm_lat - activate/deactivate device to match wakeup lat lim - * @od: struct omap_device * - * - * When a device's maximum wakeup latency limit changes, call some of - * the .activate_func or .deactivate_func function pointers in the - * omap_device's pm_lats array to ensure that the device's maximum - * wakeup latency is less than or equal to the new latency limit. - * Intended to be called by OMAP PM code whenever a device's maximum - * wakeup latency limit changes (e.g., via - * omap_pm_set_dev_wakeup_lat()). Returns 0 if nothing needs to be - * done (e.g., if the omap_device is not currently idle, or if the - * wakeup latency is already current with the new limit) or passes - * along the return value of _omap_device_deactivate() or - * _omap_device_activate(). - */ -int omap_device_align_pm_lat(struct platform_device *pdev, - u32 new_wakeup_lat_limit) -{ - int ret = -EINVAL; - struct omap_device *od; - - od = to_omap_device(pdev); - - if (new_wakeup_lat_limit == od->dev_wakeup_lat) - return 0; - - od->_dev_wakeup_lat_limit = new_wakeup_lat_limit; - - if (od->_state != OMAP_DEVICE_STATE_IDLE) - return 0; - else if (new_wakeup_lat_limit > od->dev_wakeup_lat) - ret = _omap_device_deactivate(od, USE_WAKEUP_LAT); - else if (new_wakeup_lat_limit < od->dev_wakeup_lat) - ret = _omap_device_activate(od, USE_WAKEUP_LAT); - - return ret; -} - -/** - * omap_device_get_pwrdm - return the powerdomain * associated with @od - * @od: struct omap_device * - * - * Return the powerdomain associated with the first underlying - * omap_hwmod for this omap_device. Intended for use by core OMAP PM - * code. Returns NULL on error or a struct powerdomain * upon - * success. - */ -struct powerdomain *omap_device_get_pwrdm(struct omap_device *od) -{ - /* - * XXX Assumes that all omap_hwmod powerdomains are identical. - * This may not necessarily be true. There should be a sanity - * check in here to WARN() if any difference appears. - */ - if (!od->hwmods_cnt) - return NULL; - - return omap_hwmod_get_pwrdm(od->hwmods[0]); -} - -/** - * omap_device_get_mpu_rt_va - return the MPU's virtual addr for the hwmod base - * @od: struct omap_device * - * - * Return the MPU's virtual address for the base of the hwmod, from - * the ioremap() that the hwmod code does. Only valid if there is one - * hwmod associated with this device. Returns NULL if there are zero - * or more than one hwmods associated with this omap_device; - * otherwise, passes along the return value from - * omap_hwmod_get_mpu_rt_va(). - */ -void __iomem *omap_device_get_rt_va(struct omap_device *od) -{ - if (od->hwmods_cnt != 1) - return NULL; - - return omap_hwmod_get_mpu_rt_va(od->hwmods[0]); -} - /** * omap_device_get_by_hwmod_name() - convert a hwmod name to * device pointer. @@ -1173,82 +830,6 @@ struct device *omap_device_get_by_hwmod_name(const char *oh_name) return &oh->od->pdev->dev; } -EXPORT_SYMBOL(omap_device_get_by_hwmod_name); - -/* - * Public functions intended for use in omap_device_pm_latency - * .activate_func and .deactivate_func function pointers - */ - -/** - * omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods - * @od: struct omap_device *od - * - * Enable all underlying hwmods. Returns 0. - */ -int omap_device_enable_hwmods(struct omap_device *od) -{ - int i; - - for (i = 0; i < od->hwmods_cnt; i++) - omap_hwmod_enable(od->hwmods[i]); - - /* XXX pass along return value here? */ - return 0; -} - -/** - * omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods - * @od: struct omap_device *od - * - * Idle all underlying hwmods. Returns 0. - */ -int omap_device_idle_hwmods(struct omap_device *od) -{ - int i; - - for (i = 0; i < od->hwmods_cnt; i++) - omap_hwmod_idle(od->hwmods[i]); - - /* XXX pass along return value here? */ - return 0; -} - -/** - * omap_device_disable_clocks - disable all main and interface clocks - * @od: struct omap_device *od - * - * Disable the main functional clock and interface clock for all of the - * omap_hwmods associated with the omap_device. Returns 0. - */ -int omap_device_disable_clocks(struct omap_device *od) -{ - int i; - - for (i = 0; i < od->hwmods_cnt; i++) - omap_hwmod_disable_clocks(od->hwmods[i]); - - /* XXX pass along return value here? */ - return 0; -} - -/** - * omap_device_enable_clocks - enable all main and interface clocks - * @od: struct omap_device *od - * - * Enable the main functional clock and interface clock for all of the - * omap_hwmods associated with the omap_device. Returns 0. - */ -int omap_device_enable_clocks(struct omap_device *od) -{ - int i; - - for (i = 0; i < od->hwmods_cnt; i++) - omap_hwmod_enable_clocks(od->hwmods[i]); - - /* XXX pass along return value here? */ - return 0; -} static struct notifier_block platform_nb = { .notifier_call = _omap_device_notifier_call, diff --git a/arch/arm/mach-omap2/omap_device.h b/arch/arm/mach-omap2/omap_device.h index 0933c599bf89..044c31d50e5b 100644 --- a/arch/arm/mach-omap2/omap_device.h +++ b/arch/arm/mach-omap2/omap_device.h @@ -13,20 +13,12 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Eventually this type of functionality should either be - * a) implemented via arch-specific pointers in platform_device - * or - * b) implemented as a proper omap_bus/omap_device in Linux, no more - * platform_device + * This type of functionality should be implemented as a proper + * omap_bus/omap_device in Linux. * * omap_device differs from omap_hwmod in that it includes external * (e.g., board- and system-level) integration details. omap_hwmod * stores hardware data that is invariant for a given OMAP chip. - * - * To do: - * - GPIO integration - * - regulator integration - * */ #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_DEVICE_H #define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_DEVICE_H @@ -45,19 +37,14 @@ extern struct dev_pm_domain omap_device_pm_domain; #define OMAP_DEVICE_STATE_SHUTDOWN 3 /* omap_device.flags values */ -#define OMAP_DEVICE_SUSPENDED BIT(0) -#define OMAP_DEVICE_NO_IDLE_ON_SUSPEND BIT(1) +#define OMAP_DEVICE_SUSPENDED BIT(0) +#define OMAP_DEVICE_NO_IDLE_ON_SUSPEND BIT(1) /** * struct omap_device - omap_device wrapper for platform_devices * @pdev: platform_device * @hwmods: (one .. many per omap_device) * @hwmods_cnt: ARRAY_SIZE() of @hwmods - * @pm_lats: ptr to an omap_device_pm_latency table - * @pm_lats_cnt: ARRAY_SIZE() of what is passed to @pm_lats - * @pm_lat_level: array index of the last odpl entry executed - -1 if never - * @dev_wakeup_lat: dev wakeup latency in nanoseconds - * @_dev_wakeup_lat_limit: dev wakeup latency limit in nsec - set by OMAP PM * @_state: one of OMAP_DEVICE_STATE_* (see above) * @flags: device flags * @_driver_status: one of BUS_NOTIFY_*_DRIVER from @@ -71,12 +58,7 @@ extern struct dev_pm_domain omap_device_pm_domain; struct omap_device { struct platform_device *pdev; struct omap_hwmod **hwmods; - struct omap_device_pm_latency *pm_lats; - u32 dev_wakeup_lat; - u32 _dev_wakeup_lat_limit; unsigned long _driver_status; - u8 pm_lats_cnt; - s8 pm_lat_level; u8 hwmods_cnt; u8 _state; u8 flags; @@ -86,36 +68,25 @@ struct omap_device { int omap_device_enable(struct platform_device *pdev); int omap_device_idle(struct platform_device *pdev); -int omap_device_shutdown(struct platform_device *pdev); /* Core code interface */ struct platform_device *omap_device_build(const char *pdev_name, int pdev_id, - struct omap_hwmod *oh, void *pdata, - int pdata_len, - struct omap_device_pm_latency *pm_lats, - int pm_lats_cnt, int is_early_device); + struct omap_hwmod *oh, void *pdata, + int pdata_len); struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id, struct omap_hwmod **oh, int oh_cnt, - void *pdata, int pdata_len, - struct omap_device_pm_latency *pm_lats, - int pm_lats_cnt, int is_early_device); + void *pdata, int pdata_len); struct omap_device *omap_device_alloc(struct platform_device *pdev, - struct omap_hwmod **ohs, int oh_cnt, - struct omap_device_pm_latency *pm_lats, - int pm_lats_cnt); + struct omap_hwmod **ohs, int oh_cnt); void omap_device_delete(struct omap_device *od); int omap_device_register(struct platform_device *pdev); -void __iomem *omap_device_get_rt_va(struct omap_device *od); struct device *omap_device_get_by_hwmod_name(const char *oh_name); /* OMAP PM interface */ -int omap_device_align_pm_lat(struct platform_device *pdev, - u32 new_wakeup_lat_limit); -struct powerdomain *omap_device_get_pwrdm(struct omap_device *od); int omap_device_get_context_loss_count(struct platform_device *pdev); /* Other */ @@ -124,40 +95,6 @@ int omap_device_assert_hardreset(struct platform_device *pdev, const char *name); int omap_device_deassert_hardreset(struct platform_device *pdev, const char *name); -int omap_device_idle_hwmods(struct omap_device *od); -int omap_device_enable_hwmods(struct omap_device *od); - -int omap_device_disable_clocks(struct omap_device *od); -int omap_device_enable_clocks(struct omap_device *od); - -/* - * Entries should be kept in latency order ascending - * - * deact_lat is the maximum number of microseconds required to complete - * deactivate_func() at the device's slowest OPP. - * - * act_lat is the maximum number of microseconds required to complete - * activate_func() at the device's slowest OPP. - * - * This will result in some suboptimal power management decisions at fast - * OPPs, but avoids having to recompute all device power management decisions - * if the system shifts from a fast OPP to a slow OPP (in order to meet - * latency requirements). - * - * XXX should deactivate_func/activate_func() take platform_device pointers - * rather than omap_device pointers? - */ -struct omap_device_pm_latency { - u32 deactivate_lat; - u32 deactivate_lat_worst; - int (*deactivate_func)(struct omap_device *od); - u32 activate_lat; - u32 activate_lat_worst; - int (*activate_func)(struct omap_device *od); - u32 flags; -}; - -#define OMAP_DEVICE_LATENCY_AUTO_ADJUST BIT(1) /* Get omap_device pointer from platform_device pointer */ static inline struct omap_device *to_omap_device(struct platform_device *pdev) diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index f4b3143a8b1d..9627547ee72a 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -32,8 +32,6 @@ #include "pm.h" #include "twl-common.h" -static struct omap_device_pm_latency *pm_lats; - /* * omap_pm_suspend: points to a function that does the SoC-specific * suspend work @@ -82,7 +80,7 @@ static int __init _init_omap_device(char *name) __func__, name)) return -ENODEV; - pdev = omap_device_build(oh->name, 0, oh, NULL, 0, pm_lats, 0, false); + pdev = omap_device_build(oh->name, 0, oh, NULL, 0); if (WARN(IS_ERR(pdev), "%s: could not build omap_device for %s\n", __func__, name)) return -ENODEV; diff --git a/arch/arm/mach-omap2/pmu.c b/arch/arm/mach-omap2/pmu.c index eb78ae7a3464..0ef4d6aa758e 100644 --- a/arch/arm/mach-omap2/pmu.c +++ b/arch/arm/mach-omap2/pmu.c @@ -48,8 +48,7 @@ static int __init omap2_init_pmu(unsigned oh_num, char *oh_names[]) } } - omap_pmu_dev = omap_device_build_ss(dev_name, -1, oh, oh_num, NULL, 0, - NULL, 0, 0); + omap_pmu_dev = omap_device_build_ss(dev_name, -1, oh, oh_num, NULL, 0); WARN(IS_ERR(omap_pmu_dev), "Can't build omap_device for %s.\n", dev_name); diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 04fdbc4c499b..d01c373cbbef 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -316,8 +316,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, if (WARN_ON(!oh)) return; - pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size, - NULL, 0, false); + pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size); if (IS_ERR(pdev)) { WARN(1, "Could not build omap_device for %s: %s.\n", name, oh->name); diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c index b9753fe27232..bb829e065400 100644 --- a/arch/arm/mach-omap2/sr_device.c +++ b/arch/arm/mach-omap2/sr_device.c @@ -152,8 +152,7 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user) sr_data->enable_on_init = sr_enable_on_init; - pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data), - NULL, 0, 0); + pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data), 0); if (IS_ERR(pdev)) pr_warning("%s: Could not build omap_device for %s: %s.\n\n", __func__, name, oh->name); diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index b8ad6e632bb8..63e5fb017fd8 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -702,8 +702,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) pdata->timer_errata = omap_dm_timer_get_errata(); pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; - pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), - NULL, 0, 0); + pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata)); if (IS_ERR(pdev)) { pr_err("%s: Can't build omap_device for %s: %s.\n", diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 2e44e8a22884..99f04deb4c7f 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -42,14 +42,6 @@ static struct usbtll_omap_platform_data usbtll_data; static struct ehci_hcd_omap_platform_data ehci_data; static struct ohci_hcd_omap_platform_data ohci_data; -static struct omap_device_pm_latency omap_uhhtll_latency[] = { - { - .deactivate_func = omap_device_idle_hwmods, - .activate_func = omap_device_enable_hwmods, - .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, - }, -}; - /* MUX settings for EHCI pins */ /* * setup_ehci_io_mux - initialize IO pad mux for USBHOST @@ -530,9 +522,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) } pdev = omap_device_build(OMAP_USBTLL_DEVICE, bus_id, tll_hwm, - &usbtll_data, sizeof(usbtll_data), - omap_uhhtll_latency, - ARRAY_SIZE(omap_uhhtll_latency), false); + &usbtll_data, sizeof(usbtll_data)); if (IS_ERR(pdev)) { pr_err("Could not build hwmod device %s\n", USBHS_TLL_HWMODNAME); @@ -540,9 +530,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) } pdev = omap_device_build(OMAP_USBHS_DEVICE, bus_id, uhh_hwm, - &usbhs_data, sizeof(usbhs_data), - omap_uhhtll_latency, - ARRAY_SIZE(omap_uhhtll_latency), false); + &usbhs_data, sizeof(usbhs_data)); if (IS_ERR(pdev)) { pr_err("Could not build hwmod devices %s\n", USBHS_UHH_HWMODNAME); diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index 7b33b375fe77..8c4de2708cf2 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -102,7 +102,7 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data) return; pdev = omap_device_build(name, bus_id, oh, &musb_plat, - sizeof(musb_plat), NULL, 0, false); + sizeof(musb_plat)); if (IS_ERR(pdev)) { pr_err("Could not build omap_device for %s %s\n", name, oh_name); diff --git a/arch/arm/mach-omap2/wd_timer.c b/arch/arm/mach-omap2/wd_timer.c index 7c2b4ed38f02..910243f54a05 100644 --- a/arch/arm/mach-omap2/wd_timer.c +++ b/arch/arm/mach-omap2/wd_timer.c @@ -124,8 +124,7 @@ static int __init omap_init_wdt(void) pdata.read_reset_sources = prm_read_reset_sources; pdev = omap_device_build(dev_name, id, oh, &pdata, - sizeof(struct omap_wd_timer_platform_data), - NULL, 0, 0); + sizeof(struct omap_wd_timer_platform_data)); WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s.\n", dev_name, oh->name); return 0; From 17b7e7d33530e2bbd3bdc90f4db09b91cfdde2bb Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:48:54 -0700 Subject: [PATCH 040/148] ARM: OMAP4: clock/hwmod data: start to remove some IP block control "clocks" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove some leaf "clocks" that are actually IP block idle control points, since these should now be handled by the hwmod code. There are still a few types of MODULEMODE clocks that need to be cleaned up: - those still in use by driver or integration code - those in DEFINE_CLK_OMAP_MUX_GATE() blocks; the gate portion of these should be removed A similar process may also be possible on OMAP2/3. Signed-off-by: Paul Walmsley Cc: Benoît Cousson Cc: Mike Turquette --- arch/arm/mach-omap2/cclock44xx_data.c | 291 +-------------------- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 58 ++-- 2 files changed, 34 insertions(+), 315 deletions(-) diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c index a2cc046b47f4..4c3f5a32694c 100644 --- a/arch/arm/mach-omap2/cclock44xx_data.c +++ b/arch/arm/mach-omap2/cclock44xx_data.c @@ -16,6 +16,11 @@ * XXX Some of the ES1 clocks have been removed/changed; once support * is added for discriminating clocks by ES level, these should be added back * in. + * + * XXX All of the CLK_OMAP_MUX_GATE entries with MODULEMODE registers should + * be split into separate mux and gate nodes, then the gates should be removed + * (handled by hwmod). Also all of the other remaining MODULEMODE entries + * should be removed once the drivers are updated to use pm_runtime. */ #include @@ -749,10 +754,6 @@ DEFINE_CLK_GATE(aes2_fck, "l3_div_ck", &l3_div_ck, 0x0, OMAP4430_CM_L4SEC_AES2_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(aess_fck, "aess_fclk", &aess_fclk, 0x0, - OMAP4430_CM1_ABE_AESS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - DEFINE_CLK_GATE(bandgap_fclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT, 0x0, NULL); @@ -774,11 +775,6 @@ DEFINE_CLK_GATE(bandgap_ts_fclk, "div_ts_ck", &div_ts_ck, 0x0, OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(des3des_fck, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4SEC_DES3DES_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - static const char *dmic_sync_mux_ck_parents[] = { "abe_24m_fclk", "syc_clk_div_ck", "func_24m_clk", }; @@ -809,10 +805,6 @@ DEFINE_CLK_OMAP_MUX_GATE(dmic_fck, "abe_clkdm", func_dmic_abe_gfclk_sel, OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, dmic_fck_parents, dmic_fck_ops); -DEFINE_CLK_GATE(dsp_fck, "dpll_iva_m4x2_ck", &dpll_iva_m4x2_ck, 0x0, - OMAP4430_CM_TESLA_TESLA_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(dss_sys_clk, "syc_clk_div_ck", &syc_clk_div_ck, 0x0, OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT, 0x0, NULL); @@ -833,78 +825,34 @@ DEFINE_CLK_GATE(dss_fck, "l3_div_ck", &l3_div_ck, 0x0, OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(efuse_ctrl_cust_fck, "sys_clkin_ck", &sys_clkin_ck, 0x0, - OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(emif1_fck, "ddrphy_ck", &ddrphy_ck, 0x0, - OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(emif2_fck, "ddrphy_ck", &ddrphy_ck, 0x0, - OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_DIVIDER(fdif_fck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0, OMAP4430_CM_CAM_FDIF_CLKCTRL, OMAP4430_CLKSEL_FCLK_SHIFT, OMAP4430_CLKSEL_FCLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); -DEFINE_CLK_GATE(fpka_fck, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(gpio1_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_WKUP_GPIO1_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(gpio1_ick, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, 0x0, - OMAP4430_CM_WKUP_GPIO1_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(gpio2_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO2_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(gpio2_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4PER_GPIO2_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(gpio3_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO3_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(gpio3_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4PER_GPIO3_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(gpio4_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO4_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(gpio4_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4PER_GPIO4_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(gpio5_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO5_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(gpio5_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4PER_GPIO5_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(gpio6_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0, OMAP4430_CM_L4PER_GPIO6_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(gpio6_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4PER_GPIO6_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(gpmc_ick, "l3_div_ck", &l3_div_ck, 0x0, - OMAP4430_CM_L3_2_GPMC_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT, - 0x0, NULL); - static const struct clksel sgx_clk_mux_sel[] = { { .parent = &dpll_core_m7x2_ck, .rates = div_1_0_rates }, { .parent = &dpll_per_m7x2_ck, .rates = div_1_1_rates }, @@ -923,87 +871,15 @@ DEFINE_CLK_OMAP_MUX_GATE(gpu_fck, "l3_gfx_clkdm", sgx_clk_mux_sel, OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, gpu_fck_parents, dmic_fck_ops); -DEFINE_CLK_GATE(hdq1w_fck, "func_12m_fclk", &func_12m_fclk, 0x0, - OMAP4430_CM_L4PER_HDQ1W_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_DIVIDER(hsi_fck, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, 0x0, OMAP4430_CM_L3INIT_HSI_CLKCTRL, OMAP4430_CLKSEL_24_25_SHIFT, OMAP4430_CLKSEL_24_25_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL); -DEFINE_CLK_GATE(i2c1_fck, "func_96m_fclk", &func_96m_fclk, 0x0, - OMAP4430_CM_L4PER_I2C1_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(i2c2_fck, "func_96m_fclk", &func_96m_fclk, 0x0, - OMAP4430_CM_L4PER_I2C2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(i2c3_fck, "func_96m_fclk", &func_96m_fclk, 0x0, - OMAP4430_CM_L4PER_I2C3_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(i2c4_fck, "func_96m_fclk", &func_96m_fclk, 0x0, - OMAP4430_CM_L4PER_I2C4_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(ipu_fck, "ducati_clk_mux_ck", &ducati_clk_mux_ck, 0x0, - OMAP4430_CM_DUCATI_DUCATI_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(iss_ctrlclk, "func_96m_fclk", &func_96m_fclk, 0x0, OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(iss_fck, "ducati_clk_mux_ck", &ducati_clk_mux_ck, 0x0, - OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(iva_fck, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, 0x0, - OMAP4430_CM_IVAHD_IVAHD_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(kbd_fck, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -static struct clk l3_instr_ick; - -static const char *l3_instr_ick_parent_names[] = { - "l3_div_ck", -}; - -static const struct clk_ops l3_instr_ick_ops = { - .enable = &omap2_dflt_clk_enable, - .disable = &omap2_dflt_clk_disable, - .is_enabled = &omap2_dflt_clk_is_enabled, - .init = &omap2_init_clk_clkdm, -}; - -static struct clk_hw_omap l3_instr_ick_hw = { - .hw = { - .clk = &l3_instr_ick, - }, - .enable_reg = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL, - .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT, - .clkdm_name = "l3_instr_clkdm", -}; - -DEFINE_STRUCT_CLK(l3_instr_ick, l3_instr_ick_parent_names, l3_instr_ick_ops); - -static struct clk l3_main_3_ick; -static struct clk_hw_omap l3_main_3_ick_hw = { - .hw = { - .clk = &l3_main_3_ick, - }, - .enable_reg = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL, - .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT, - .clkdm_name = "l3_instr_clkdm", -}; - -DEFINE_STRUCT_CLK(l3_main_3_ick, l3_instr_ick_parent_names, l3_instr_ick_ops); - DEFINE_CLK_MUX(mcasp_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, OMAP4430_CM1_ABE_MCASP_CLKCTRL, OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT, @@ -1127,26 +1003,6 @@ DEFINE_CLK_OMAP_MUX_GATE(mcbsp4_fck, "l4_per_clkdm", per_mcbsp4_gfclk_sel, OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, mcbsp4_fck_parents, dmic_fck_ops); -DEFINE_CLK_GATE(mcpdm_fck, "pad_clks_ck", &pad_clks_ck, 0x0, - OMAP4430_CM1_ABE_PDM_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(mcspi1_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_MCSPI1_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(mcspi2_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_MCSPI2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(mcspi3_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_MCSPI3_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(mcspi4_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_MCSPI4_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - static const struct clksel hsmmc1_fclk_sel[] = { { .parent = &func_64m_fclk, .rates = div_1_0_rates }, { .parent = &func_96m_fclk, .rates = div_1_1_rates }, @@ -1171,51 +1027,10 @@ DEFINE_CLK_OMAP_MUX_GATE(mmc2_fck, "l3_init_clkdm", hsmmc1_fclk_sel, OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, mmc1_fck_parents, dmic_fck_ops); -DEFINE_CLK_GATE(mmc3_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_MMCSD3_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(mmc4_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_MMCSD4_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(mmc5_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_MMCSD5_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, - OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(ocp2scp_usb_phy_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, - OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL); - -static struct clk ocp_wp_noc_ick; - -static struct clk_hw_omap ocp_wp_noc_ick_hw = { - .hw = { - .clk = &ocp_wp_noc_ick, - }, - .enable_reg = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL, - .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT, - .clkdm_name = "l3_instr_clkdm", -}; - -DEFINE_STRUCT_CLK(ocp_wp_noc_ick, l3_instr_ick_parent_names, l3_instr_ick_ops); - -DEFINE_CLK_GATE(rng_ick, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4SEC_RNG_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT, - 0x0, NULL); - DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0, OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(sl2if_ick, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, 0x0, - OMAP4430_CM_IVAHD_SL2_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT, - 0x0, NULL); - DEFINE_CLK_GATE(slimbus1_fclk_1, "func_24m_clk", &func_24m_clk, 0x0, OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, OMAP4430_OPTFCLKEN_FCLK1_SHIFT, 0x0, NULL); @@ -1232,10 +1047,6 @@ DEFINE_CLK_GATE(slimbus1_slimbus_clk, "slimbus_clk", &slimbus_clk, 0x0, OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(slimbus1_fck, "ocp_abe_iclk", &ocp_abe_iclk, 0x0, - OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(slimbus2_fclk_1, "per_abe_24m_fclk", &per_abe_24m_fclk, 0x0, OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT, 0x0, NULL); @@ -1249,10 +1060,6 @@ DEFINE_CLK_GATE(slimbus2_slimbus_clk, "pad_slimbus_core_clks_ck", OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(slimbus2_fck, "l4_div_ck", &l4_div_ck, 0x0, - OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - DEFINE_CLK_GATE(smartreflex_core_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, 0x0, OMAP4430_CM_ALWON_SR_CORE_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); @@ -1364,22 +1171,6 @@ DEFINE_CLK_OMAP_MUX_GATE(timer9_fck, "l4_per_clkdm", dmt1_clk_mux_sel, OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); -DEFINE_CLK_GATE(uart1_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_UART1_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(uart2_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_UART2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(uart3_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_UART3_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - -DEFINE_CLK_GATE(uart4_fck, "func_48m_fclk", &func_48m_fclk, 0x0, - OMAP4430_CM_L4PER_UART4_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); - static struct clk usb_host_fs_fck; static const char *usb_host_fs_fck_parent_names[] = { @@ -1512,18 +1303,6 @@ DEFINE_CLK_GATE(usim_fclk, "usim_ck", &usim_ck, 0x0, OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_OPTFCLKEN_FCLK_SHIFT, 0x0, NULL); -DEFINE_CLK_GATE(usim_fck, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(wd_timer2_fck, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM_WKUP_WDT2_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - -DEFINE_CLK_GATE(wd_timer3_fck, "sys_32k_ck", &sys_32k_ck, 0x0, - OMAP4430_CM1_ABE_WDT3_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT, - 0x0, NULL); - /* Remaining optional clocks */ static const char *pmd_stm_clock_mux_ck_parents[] = { "sys_clkin_ck", "dpll_core_m6x2_ck", "tie_low_clock_ck", @@ -1774,52 +1553,27 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "syc_clk_div_ck", &syc_clk_div_ck, CK_443X), CLK(NULL, "aes1_fck", &aes1_fck, CK_443X), CLK(NULL, "aes2_fck", &aes2_fck, CK_443X), - CLK(NULL, "aess_fck", &aess_fck, CK_443X), CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X), CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X), CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk, CK_446X), - CLK(NULL, "des3des_fck", &des3des_fck, CK_443X), CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X), CLK(NULL, "dmic_fck", &dmic_fck, CK_443X), - CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), CLK(NULL, "dss_sys_clk", &dss_sys_clk, CK_443X), CLK(NULL, "dss_tv_clk", &dss_tv_clk, CK_443X), CLK(NULL, "dss_dss_clk", &dss_dss_clk, CK_443X), CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk, CK_443X), CLK(NULL, "dss_fck", &dss_fck, CK_443X), CLK("omapdss_dss", "ick", &dss_fck, CK_443X), - CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_443X), - CLK(NULL, "emif1_fck", &emif1_fck, CK_443X), - CLK(NULL, "emif2_fck", &emif2_fck, CK_443X), CLK(NULL, "fdif_fck", &fdif_fck, CK_443X), - CLK(NULL, "fpka_fck", &fpka_fck, CK_443X), CLK(NULL, "gpio1_dbclk", &gpio1_dbclk, CK_443X), - CLK(NULL, "gpio1_ick", &gpio1_ick, CK_443X), CLK(NULL, "gpio2_dbclk", &gpio2_dbclk, CK_443X), - CLK(NULL, "gpio2_ick", &gpio2_ick, CK_443X), CLK(NULL, "gpio3_dbclk", &gpio3_dbclk, CK_443X), - CLK(NULL, "gpio3_ick", &gpio3_ick, CK_443X), CLK(NULL, "gpio4_dbclk", &gpio4_dbclk, CK_443X), - CLK(NULL, "gpio4_ick", &gpio4_ick, CK_443X), CLK(NULL, "gpio5_dbclk", &gpio5_dbclk, CK_443X), - CLK(NULL, "gpio5_ick", &gpio5_ick, CK_443X), CLK(NULL, "gpio6_dbclk", &gpio6_dbclk, CK_443X), - CLK(NULL, "gpio6_ick", &gpio6_ick, CK_443X), - CLK(NULL, "gpmc_ick", &gpmc_ick, CK_443X), CLK(NULL, "gpu_fck", &gpu_fck, CK_443X), - CLK(NULL, "hdq1w_fck", &hdq1w_fck, CK_443X), CLK(NULL, "hsi_fck", &hsi_fck, CK_443X), - CLK(NULL, "i2c1_fck", &i2c1_fck, CK_443X), - CLK(NULL, "i2c2_fck", &i2c2_fck, CK_443X), - CLK(NULL, "i2c3_fck", &i2c3_fck, CK_443X), - CLK(NULL, "i2c4_fck", &i2c4_fck, CK_443X), - CLK(NULL, "ipu_fck", &ipu_fck, CK_443X), CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X), - CLK(NULL, "iss_fck", &iss_fck, CK_443X), - CLK(NULL, "iva_fck", &iva_fck, CK_443X), - CLK(NULL, "kbd_fck", &kbd_fck, CK_443X), - CLK(NULL, "l3_instr_ick", &l3_instr_ick, CK_443X), - CLK(NULL, "l3_main_3_ick", &l3_main_3_ick, CK_443X), CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck, CK_443X), CLK(NULL, "mcasp_fck", &mcasp_fck, CK_443X), CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck, CK_443X), @@ -1830,32 +1584,16 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "mcbsp3_fck", &mcbsp3_fck, CK_443X), CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck, CK_443X), CLK(NULL, "mcbsp4_fck", &mcbsp4_fck, CK_443X), - CLK(NULL, "mcpdm_fck", &mcpdm_fck, CK_443X), - CLK(NULL, "mcspi1_fck", &mcspi1_fck, CK_443X), - CLK(NULL, "mcspi2_fck", &mcspi2_fck, CK_443X), - CLK(NULL, "mcspi3_fck", &mcspi3_fck, CK_443X), - CLK(NULL, "mcspi4_fck", &mcspi4_fck, CK_443X), CLK(NULL, "mmc1_fck", &mmc1_fck, CK_443X), CLK(NULL, "mmc2_fck", &mmc2_fck, CK_443X), - CLK(NULL, "mmc3_fck", &mmc3_fck, CK_443X), - CLK(NULL, "mmc4_fck", &mmc4_fck, CK_443X), - CLK(NULL, "mmc5_fck", &mmc5_fck, CK_443X), - CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_443X), - CLK(NULL, "ocp2scp_usb_phy_ick", &ocp2scp_usb_phy_ick, CK_443X), - CLK(NULL, "ocp_wp_noc_ick", &ocp_wp_noc_ick, CK_443X), - CLK(NULL, "rng_ick", &rng_ick, CK_443X), - CLK("omap_rng", "ick", &rng_ick, CK_443X), CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_443X), - CLK(NULL, "sl2if_ick", &sl2if_ick, CK_443X), CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_443X), CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_443X), CLK(NULL, "slimbus1_fclk_2", &slimbus1_fclk_2, CK_443X), CLK(NULL, "slimbus1_slimbus_clk", &slimbus1_slimbus_clk, CK_443X), - CLK(NULL, "slimbus1_fck", &slimbus1_fck, CK_443X), CLK(NULL, "slimbus2_fclk_1", &slimbus2_fclk_1, CK_443X), CLK(NULL, "slimbus2_fclk_0", &slimbus2_fclk_0, CK_443X), CLK(NULL, "slimbus2_slimbus_clk", &slimbus2_slimbus_clk, CK_443X), - CLK(NULL, "slimbus2_fck", &slimbus2_fck, CK_443X), CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck, CK_443X), CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck, CK_443X), CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck, CK_443X), @@ -1870,10 +1608,6 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "timer7_fck", &timer7_fck, CK_443X), CLK(NULL, "timer8_fck", &timer8_fck, CK_443X), CLK(NULL, "timer9_fck", &timer9_fck, CK_443X), - CLK(NULL, "uart1_fck", &uart1_fck, CK_443X), - CLK(NULL, "uart2_fck", &uart2_fck, CK_443X), - CLK(NULL, "uart3_fck", &uart3_fck, CK_443X), - CLK(NULL, "uart4_fck", &uart4_fck, CK_443X), CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X), CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck, CK_443X), CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X), @@ -1901,9 +1635,6 @@ static struct omap_clk omap44xx_clks[] = { CLK("usbhs_tll", "usbtll_ick", &usb_tll_hs_ick, CK_443X), CLK(NULL, "usim_ck", &usim_ck, CK_443X), CLK(NULL, "usim_fclk", &usim_fclk, CK_443X), - CLK(NULL, "usim_fck", &usim_fck, CK_443X), - CLK(NULL, "wd_timer2_fck", &wd_timer2_fck, CK_443X), - CLK(NULL, "wd_timer3_fck", &wd_timer3_fck, CK_443X), CLK(NULL, "pmd_stm_clock_mux_ck", &pmd_stm_clock_mux_ck, CK_443X), CLK(NULL, "pmd_trace_clk_mux_ck", &pmd_trace_clk_mux_ck, CK_443X), CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck, CK_443X), @@ -1980,15 +1711,6 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "cpufreq_ck", &dpll_mpu_ck, CK_443X), }; -static const char *enable_init_clks[] = { - "emif1_fck", - "emif2_fck", - "gpmc_ick", - "l3_instr_ick", - "l3_main_3_ick", - "ocp_wp_noc_ick", -}; - int __init omap4xxx_clk_init(void) { u32 cpu_clkflg; @@ -2019,9 +1741,6 @@ int __init omap4xxx_clk_init(void) omap2_clk_disable_autoidle_all(); - omap2_clk_enable_init_clocks(enable_init_clks, - ARRAY_SIZE(enable_init_clks)); - /* * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power * state when turning the ABE clock domain. Workaround this by diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 793f54ac7d14..def97aa9a040 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1161,7 +1161,7 @@ static struct omap_hwmod omap44xx_gpio1_hwmod = { .class = &omap44xx_gpio_hwmod_class, .clkdm_name = "l4_wkup_clkdm", .mpu_irqs = omap44xx_gpio1_irqs, - .main_clk = "gpio1_ick", + .main_clk = "l4_wkup_clk_mux_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_WKUP_GPIO1_CLKCTRL_OFFSET, @@ -1190,7 +1190,7 @@ static struct omap_hwmod omap44xx_gpio2_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio2_irqs, - .main_clk = "gpio2_ick", + .main_clk = "l4_div_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET, @@ -1219,7 +1219,7 @@ static struct omap_hwmod omap44xx_gpio3_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio3_irqs, - .main_clk = "gpio3_ick", + .main_clk = "l4_div_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET, @@ -1248,7 +1248,7 @@ static struct omap_hwmod omap44xx_gpio4_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio4_irqs, - .main_clk = "gpio4_ick", + .main_clk = "l4_div_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET, @@ -1277,7 +1277,7 @@ static struct omap_hwmod omap44xx_gpio5_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio5_irqs, - .main_clk = "gpio5_ick", + .main_clk = "l4_div_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET, @@ -1306,7 +1306,7 @@ static struct omap_hwmod omap44xx_gpio6_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap44xx_gpio6_irqs, - .main_clk = "gpio6_ick", + .main_clk = "l4_div_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET, @@ -1446,7 +1446,7 @@ static struct omap_hwmod omap44xx_hdq1w_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_INIT_NO_RESET, /* XXX temporary */ .mpu_irqs = omap44xx_hdq1w_irqs, - .main_clk = "hdq1w_fck", + .main_clk = "func_12m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET, @@ -1550,7 +1550,7 @@ static struct omap_hwmod omap44xx_i2c1_hwmod = { .flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_i2c1_irqs, .sdma_reqs = omap44xx_i2c1_sdma_reqs, - .main_clk = "i2c1_fck", + .main_clk = "func_96m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET, @@ -1580,7 +1580,7 @@ static struct omap_hwmod omap44xx_i2c2_hwmod = { .flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_i2c2_irqs, .sdma_reqs = omap44xx_i2c2_sdma_reqs, - .main_clk = "i2c2_fck", + .main_clk = "func_96m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET, @@ -1610,7 +1610,7 @@ static struct omap_hwmod omap44xx_i2c3_hwmod = { .flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_i2c3_irqs, .sdma_reqs = omap44xx_i2c3_sdma_reqs, - .main_clk = "i2c3_fck", + .main_clk = "func_96m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET, @@ -1640,7 +1640,7 @@ static struct omap_hwmod omap44xx_i2c4_hwmod = { .flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_i2c4_irqs, .sdma_reqs = omap44xx_i2c4_sdma_reqs, - .main_clk = "i2c4_fck", + .main_clk = "func_96m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET, @@ -1743,7 +1743,7 @@ static struct omap_hwmod omap44xx_iss_hwmod = { .clkdm_name = "iss_clkdm", .mpu_irqs = omap44xx_iss_irqs, .sdma_reqs = omap44xx_iss_sdma_reqs, - .main_clk = "iss_fck", + .main_clk = "ducati_clk_mux_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET, @@ -1785,7 +1785,7 @@ static struct omap_hwmod omap44xx_iva_hwmod = { .mpu_irqs = omap44xx_iva_irqs, .rst_lines = omap44xx_iva_resets, .rst_lines_cnt = ARRAY_SIZE(omap44xx_iva_resets), - .main_clk = "iva_fck", + .main_clk = "dpll_iva_m5x2_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET, @@ -1829,7 +1829,7 @@ static struct omap_hwmod omap44xx_kbd_hwmod = { .class = &omap44xx_kbd_hwmod_class, .clkdm_name = "l4_wkup_clkdm", .mpu_irqs = omap44xx_kbd_irqs, - .main_clk = "kbd_fck", + .main_clk = "sys_32k_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_WKUP_KEYBOARD_CLKCTRL_OFFSET, @@ -2140,7 +2140,7 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = { .flags = HWMOD_EXT_OPT_MAIN_CLK | HWMOD_SWSUP_SIDLE, .mpu_irqs = omap44xx_mcpdm_irqs, .sdma_reqs = omap44xx_mcpdm_sdma_reqs, - .main_clk = "mcpdm_fck", + .main_clk = "pad_clks_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET, @@ -2201,7 +2201,7 @@ static struct omap_hwmod omap44xx_mcspi1_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcspi1_irqs, .sdma_reqs = omap44xx_mcspi1_sdma_reqs, - .main_clk = "mcspi1_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET, @@ -2237,7 +2237,7 @@ static struct omap_hwmod omap44xx_mcspi2_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcspi2_irqs, .sdma_reqs = omap44xx_mcspi2_sdma_reqs, - .main_clk = "mcspi2_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET, @@ -2273,7 +2273,7 @@ static struct omap_hwmod omap44xx_mcspi3_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcspi3_irqs, .sdma_reqs = omap44xx_mcspi3_sdma_reqs, - .main_clk = "mcspi3_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET, @@ -2307,7 +2307,7 @@ static struct omap_hwmod omap44xx_mcspi4_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcspi4_irqs, .sdma_reqs = omap44xx_mcspi4_sdma_reqs, - .main_clk = "mcspi4_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET, @@ -2420,7 +2420,7 @@ static struct omap_hwmod omap44xx_mmc3_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mmc3_irqs, .sdma_reqs = omap44xx_mmc3_sdma_reqs, - .main_clk = "mmc3_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET, @@ -2448,7 +2448,7 @@ static struct omap_hwmod omap44xx_mmc4_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mmc4_irqs, .sdma_reqs = omap44xx_mmc4_sdma_reqs, - .main_clk = "mmc4_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET, @@ -2476,7 +2476,7 @@ static struct omap_hwmod omap44xx_mmc5_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mmc5_irqs, .sdma_reqs = omap44xx_mmc5_sdma_reqs, - .main_clk = "mmc5_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET, @@ -2725,7 +2725,7 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = { .name = "ocp2scp_usb_phy", .class = &omap44xx_ocp2scp_hwmod_class, .clkdm_name = "l3_init_clkdm", - .main_clk = "ocp2scp_usb_phy_phy_48m", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET, @@ -3433,7 +3433,7 @@ static struct omap_hwmod omap44xx_uart1_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_uart1_irqs, .sdma_reqs = omap44xx_uart1_sdma_reqs, - .main_clk = "uart1_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET, @@ -3461,7 +3461,7 @@ static struct omap_hwmod omap44xx_uart2_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_uart2_irqs, .sdma_reqs = omap44xx_uart2_sdma_reqs, - .main_clk = "uart2_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET, @@ -3490,7 +3490,7 @@ static struct omap_hwmod omap44xx_uart3_hwmod = { .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET, .mpu_irqs = omap44xx_uart3_irqs, .sdma_reqs = omap44xx_uart3_sdma_reqs, - .main_clk = "uart3_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET, @@ -3518,7 +3518,7 @@ static struct omap_hwmod omap44xx_uart4_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_uart4_irqs, .sdma_reqs = omap44xx_uart4_sdma_reqs, - .main_clk = "uart4_fck", + .main_clk = "func_48m_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET, @@ -3797,7 +3797,7 @@ static struct omap_hwmod omap44xx_wd_timer2_hwmod = { .class = &omap44xx_wd_timer_hwmod_class, .clkdm_name = "l4_wkup_clkdm", .mpu_irqs = omap44xx_wd_timer2_irqs, - .main_clk = "wd_timer2_fck", + .main_clk = "sys_32k_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_WKUP_WDT2_CLKCTRL_OFFSET, @@ -3818,7 +3818,7 @@ static struct omap_hwmod omap44xx_wd_timer3_hwmod = { .class = &omap44xx_wd_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_wd_timer3_irqs, - .main_clk = "wd_timer3_fck", + .main_clk = "sys_32k_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET, From ee877acd98ea608041e13e75277f0d2f8df76527 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:48:55 -0700 Subject: [PATCH 041/148] ARM: OMAP4: clock/hwmod data: remove MODULEMODE entries in mux + gate combos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert all DEFINE_OMAP_MUX_GATE() combinations that list MODULEMODE registers in their gate arguments to DEFINE_OMAP_MUX(), dropping the MODULEMODE data. This is possible because the MODULEMODE bits control IP blocks, not clocks; and the hwmod code takes care of IP block control. Rename these clocks to reflect the original multiplexer name as specified in the comments. And convert the hwmod data to use the multiplexer clock name. Signed-off-by: Paul Walmsley Cc: Benoît Cousson Cc: Mike Turquette --- arch/arm/mach-omap2/cclock44xx_data.c | 283 ++++++++------------- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 41 ++- 2 files changed, 132 insertions(+), 192 deletions(-) diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c index 4c3f5a32694c..cebe2b31943e 100644 --- a/arch/arm/mach-omap2/cclock44xx_data.c +++ b/arch/arm/mach-omap2/cclock44xx_data.c @@ -17,10 +17,9 @@ * is added for discriminating clocks by ES level, these should be added back * in. * - * XXX All of the CLK_OMAP_MUX_GATE entries with MODULEMODE registers should - * be split into separate mux and gate nodes, then the gates should be removed - * (handled by hwmod). Also all of the other remaining MODULEMODE entries - * should be removed once the drivers are updated to use pm_runtime. + * XXX All of the remaining MODULEMODE clock nodes should be removed + * once the drivers are updated to use pm_runtime or to use the appropriate + * upstream clock node for rate/parent selection. */ #include @@ -320,7 +319,7 @@ DEFINE_CLK_DIVIDER(dpll_abe_m2_ck, "dpll_abe_ck", &dpll_abe_ck, 0x0, OMAP4430_CM_DIV_M2_DPLL_ABE, OMAP4430_DPLL_CLKOUT_DIV_SHIFT, OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL); -static const struct clk_ops dmic_fck_ops = { +static const struct clk_ops dpll_hsd_ops = { .enable = &omap2_dflt_clk_enable, .disable = &omap2_dflt_clk_disable, .is_enabled = &omap2_dflt_clk_is_enabled, @@ -330,6 +329,12 @@ static const struct clk_ops dmic_fck_ops = { .init = &omap2_init_clk_clkdm, }; +static const struct clk_ops func_dmic_abe_gfclk_ops = { + .recalc_rate = &omap2_clksel_recalc, + .get_parent = &omap2_clksel_find_parent_index, + .set_parent = &omap2_clksel_set_parent, +}; + static const char *dpll_core_m3x2_ck_parents[] = { "dpll_core_x2_ck", }; @@ -345,7 +350,7 @@ DEFINE_CLK_OMAP_MUX_GATE(dpll_core_m3x2_ck, NULL, dpll_core_m3x2_div, OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, OMAP4430_CM_DIV_M3_DPLL_CORE, OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL, - dpll_core_m3x2_ck_parents, dmic_fck_ops); + dpll_core_m3x2_ck_parents, dpll_hsd_ops); DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m7x2_ck, "dpll_core_x2_ck", &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M7_DPLL_CORE, @@ -552,7 +557,7 @@ DEFINE_CLK_OMAP_MUX_GATE(dpll_per_m3x2_ck, NULL, dpll_per_m3x2_div, OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, OMAP4430_CM_DIV_M3_DPLL_PER, OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL, - dpll_per_m3x2_ck_parents, dmic_fck_ops); + dpll_per_m3x2_ck_parents, dpll_hsd_ops); DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m4x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck, 0x0, OMAP4430_CM_DIV_M4_DPLL_PER, @@ -791,19 +796,13 @@ static const struct clksel func_dmic_abe_gfclk_sel[] = { { .parent = NULL }, }; -static const char *dmic_fck_parents[] = { +static const char *func_dmic_abe_gfclk_parents[] = { "dmic_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -/* Merged func_dmic_abe_gfclk into dmic */ -static struct clk dmic_fck; - -DEFINE_CLK_OMAP_MUX_GATE(dmic_fck, "abe_clkdm", func_dmic_abe_gfclk_sel, - OMAP4430_CM1_ABE_DMIC_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, - OMAP4430_CM1_ABE_DMIC_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - dmic_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(func_dmic_abe_gfclk, "abe_clkdm", func_dmic_abe_gfclk_sel, + OMAP4430_CM1_ABE_DMIC_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK, + func_dmic_abe_gfclk_parents, func_dmic_abe_gfclk_ops); DEFINE_CLK_GATE(dss_sys_clk, "syc_clk_div_ck", &syc_clk_div_ck, 0x0, OMAP4430_CM_DSS_DSS_CLKCTRL, @@ -859,17 +858,13 @@ static const struct clksel sgx_clk_mux_sel[] = { { .parent = NULL }, }; -static const char *gpu_fck_parents[] = { +static const char *sgx_clk_mux_parents[] = { "dpll_core_m7x2_ck", "dpll_per_m7x2_ck", }; -/* Merged sgx_clk_mux into gpu */ -DEFINE_CLK_OMAP_MUX_GATE(gpu_fck, "l3_gfx_clkdm", sgx_clk_mux_sel, - OMAP4430_CM_GFX_GFX_CLKCTRL, - OMAP4430_CLKSEL_SGX_FCLK_MASK, - OMAP4430_CM_GFX_GFX_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - gpu_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(sgx_clk_mux, "l3_gfx_clkdm", sgx_clk_mux_sel, + OMAP4430_CM_GFX_GFX_CLKCTRL, OMAP4430_CLKSEL_SGX_FCLK_MASK, + sgx_clk_mux_parents, func_dmic_abe_gfclk_ops); DEFINE_CLK_DIVIDER(hsi_fck, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, 0x0, OMAP4430_CM_L3INIT_HSI_CLKCTRL, OMAP4430_CLKSEL_24_25_SHIFT, @@ -892,17 +887,13 @@ static const struct clksel func_mcasp_abe_gfclk_sel[] = { { .parent = NULL }, }; -static const char *mcasp_fck_parents[] = { +static const char *func_mcasp_abe_gfclk_parents[] = { "mcasp_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -/* Merged func_mcasp_abe_gfclk into mcasp */ -DEFINE_CLK_OMAP_MUX_GATE(mcasp_fck, "abe_clkdm", func_mcasp_abe_gfclk_sel, - OMAP4430_CM1_ABE_MCASP_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, - OMAP4430_CM1_ABE_MCASP_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - mcasp_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(func_mcasp_abe_gfclk, "abe_clkdm", func_mcasp_abe_gfclk_sel, + OMAP4430_CM1_ABE_MCASP_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK, + func_mcasp_abe_gfclk_parents, func_dmic_abe_gfclk_ops); DEFINE_CLK_MUX(mcbsp1_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, @@ -916,17 +907,14 @@ static const struct clksel func_mcbsp1_gfclk_sel[] = { { .parent = NULL }, }; -static const char *mcbsp1_fck_parents[] = { +static const char *func_mcbsp1_gfclk_parents[] = { "mcbsp1_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -/* Merged func_mcbsp1_gfclk into mcbsp1 */ -DEFINE_CLK_OMAP_MUX_GATE(mcbsp1_fck, "abe_clkdm", func_mcbsp1_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, - OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - mcbsp1_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(func_mcbsp1_gfclk, "abe_clkdm", func_mcbsp1_gfclk_sel, + OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp1_gfclk_parents, + func_dmic_abe_gfclk_ops); DEFINE_CLK_MUX(mcbsp2_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, @@ -940,17 +928,14 @@ static const struct clksel func_mcbsp2_gfclk_sel[] = { { .parent = NULL }, }; -static const char *mcbsp2_fck_parents[] = { +static const char *func_mcbsp2_gfclk_parents[] = { "mcbsp2_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -/* Merged func_mcbsp2_gfclk into mcbsp2 */ -DEFINE_CLK_OMAP_MUX_GATE(mcbsp2_fck, "abe_clkdm", func_mcbsp2_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, - OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - mcbsp2_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(func_mcbsp2_gfclk, "abe_clkdm", func_mcbsp2_gfclk_sel, + OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp2_gfclk_parents, + func_dmic_abe_gfclk_ops); DEFINE_CLK_MUX(mcbsp3_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0, OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, @@ -964,17 +949,14 @@ static const struct clksel func_mcbsp3_gfclk_sel[] = { { .parent = NULL }, }; -static const char *mcbsp3_fck_parents[] = { +static const char *func_mcbsp3_gfclk_parents[] = { "mcbsp3_sync_mux_ck", "pad_clks_ck", "slimbus_clk", }; -/* Merged func_mcbsp3_gfclk into mcbsp3 */ -DEFINE_CLK_OMAP_MUX_GATE(mcbsp3_fck, "abe_clkdm", func_mcbsp3_gfclk_sel, - OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_MASK, - OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - mcbsp3_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(func_mcbsp3_gfclk, "abe_clkdm", func_mcbsp3_gfclk_sel, + OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp3_gfclk_parents, + func_dmic_abe_gfclk_ops); static const char *mcbsp4_sync_mux_ck_parents[] = { "func_96m_fclk", "per_abe_nc_fclk", @@ -991,17 +973,14 @@ static const struct clksel per_mcbsp4_gfclk_sel[] = { { .parent = NULL }, }; -static const char *mcbsp4_fck_parents[] = { +static const char *per_mcbsp4_gfclk_parents[] = { "mcbsp4_sync_mux_ck", "pad_clks_ck", }; -/* Merged per_mcbsp4_gfclk into mcbsp4 */ -DEFINE_CLK_OMAP_MUX_GATE(mcbsp4_fck, "l4_per_clkdm", per_mcbsp4_gfclk_sel, - OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, - OMAP4430_CLKSEL_SOURCE_24_24_MASK, - OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - mcbsp4_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(per_mcbsp4_gfclk, "l4_per_clkdm", per_mcbsp4_gfclk_sel, + OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, + OMAP4430_CLKSEL_SOURCE_24_24_MASK, per_mcbsp4_gfclk_parents, + func_dmic_abe_gfclk_ops); static const struct clksel hsmmc1_fclk_sel[] = { { .parent = &func_64m_fclk, .rates = div_1_0_rates }, @@ -1009,23 +988,17 @@ static const struct clksel hsmmc1_fclk_sel[] = { { .parent = NULL }, }; -static const char *mmc1_fck_parents[] = { +static const char *hsmmc1_fclk_parents[] = { "func_64m_fclk", "func_96m_fclk", }; -/* Merged hsmmc1_fclk into mmc1 */ -DEFINE_CLK_OMAP_MUX_GATE(mmc1_fck, "l3_init_clkdm", hsmmc1_fclk_sel, - OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK, - OMAP4430_CM_L3INIT_MMC1_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - mmc1_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(hsmmc1_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, + OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK, + hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); -/* Merged hsmmc2_fclk into mmc2 */ -DEFINE_CLK_OMAP_MUX_GATE(mmc2_fck, "l3_init_clkdm", hsmmc1_fclk_sel, - OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK, - OMAP4430_CM_L3INIT_MMC2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - mmc1_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel, + OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK, + hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops); DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0, OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL, @@ -1078,52 +1051,35 @@ static const struct clksel dmt1_clk_mux_sel[] = { { .parent = NULL }, }; -/* Merged dmt1_clk_mux into timer1 */ -DEFINE_CLK_OMAP_MUX_GATE(timer1_fck, "l4_wkup_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK, - OMAP4430_CM_WKUP_TIMER1_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(dmt1_clk_mux, "l4_wkup_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK, + abe_dpll_bypass_clk_mux_ck_parents, + func_dmic_abe_gfclk_ops); -/* Merged cm2_dm10_mux into timer10 */ -DEFINE_CLK_OMAP_MUX_GATE(timer10_fck, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, - OMAP4430_CLKSEL_MASK, - OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(cm2_dm10_mux, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, OMAP4430_CLKSEL_MASK, + abe_dpll_bypass_clk_mux_ck_parents, + func_dmic_abe_gfclk_ops); -/* Merged cm2_dm11_mux into timer11 */ -DEFINE_CLK_OMAP_MUX_GATE(timer11_fck, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, - OMAP4430_CLKSEL_MASK, - OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(cm2_dm11_mux, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, OMAP4430_CLKSEL_MASK, + abe_dpll_bypass_clk_mux_ck_parents, + func_dmic_abe_gfclk_ops); -/* Merged cm2_dm2_mux into timer2 */ -DEFINE_CLK_OMAP_MUX_GATE(timer2_fck, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, - OMAP4430_CLKSEL_MASK, - OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(cm2_dm2_mux, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, OMAP4430_CLKSEL_MASK, + abe_dpll_bypass_clk_mux_ck_parents, + func_dmic_abe_gfclk_ops); -/* Merged cm2_dm3_mux into timer3 */ -DEFINE_CLK_OMAP_MUX_GATE(timer3_fck, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, - OMAP4430_CLKSEL_MASK, - OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(cm2_dm3_mux, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, OMAP4430_CLKSEL_MASK, + abe_dpll_bypass_clk_mux_ck_parents, + func_dmic_abe_gfclk_ops); -/* Merged cm2_dm4_mux into timer4 */ -DEFINE_CLK_OMAP_MUX_GATE(timer4_fck, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, - OMAP4430_CLKSEL_MASK, - OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(cm2_dm4_mux, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, OMAP4430_CLKSEL_MASK, + abe_dpll_bypass_clk_mux_ck_parents, + func_dmic_abe_gfclk_ops); static const struct clksel timer5_sync_mux_sel[] = { { .parent = &syc_clk_div_ck, .rates = div_1_0_rates }, @@ -1131,45 +1087,30 @@ static const struct clksel timer5_sync_mux_sel[] = { { .parent = NULL }, }; -static const char *timer5_fck_parents[] = { +static const char *timer5_sync_mux_parents[] = { "syc_clk_div_ck", "sys_32k_ck", }; -/* Merged timer5_sync_mux into timer5 */ -DEFINE_CLK_OMAP_MUX_GATE(timer5_fck, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK, - OMAP4430_CM1_ABE_TIMER5_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - timer5_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(timer5_sync_mux, "abe_clkdm", timer5_sync_mux_sel, + OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK, + timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); -/* Merged timer6_sync_mux into timer6 */ -DEFINE_CLK_OMAP_MUX_GATE(timer6_fck, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK, - OMAP4430_CM1_ABE_TIMER6_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - timer5_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(timer6_sync_mux, "abe_clkdm", timer5_sync_mux_sel, + OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK, + timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); -/* Merged timer7_sync_mux into timer7 */ -DEFINE_CLK_OMAP_MUX_GATE(timer7_fck, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK, - OMAP4430_CM1_ABE_TIMER7_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - timer5_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(timer7_sync_mux, "abe_clkdm", timer5_sync_mux_sel, + OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK, + timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); -/* Merged timer8_sync_mux into timer8 */ -DEFINE_CLK_OMAP_MUX_GATE(timer8_fck, "abe_clkdm", timer5_sync_mux_sel, - OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK, - OMAP4430_CM1_ABE_TIMER8_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - timer5_fck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(timer8_sync_mux, "abe_clkdm", timer5_sync_mux_sel, + OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK, + timer5_sync_mux_parents, func_dmic_abe_gfclk_ops); -/* Merged cm2_dm9_mux into timer9 */ -DEFINE_CLK_OMAP_MUX_GATE(timer9_fck, "l4_per_clkdm", dmt1_clk_mux_sel, - OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, - OMAP4430_CLKSEL_MASK, - OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, - OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL, - abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops); +DEFINE_CLK_OMAP_MUX(cm2_dm9_mux, "l4_per_clkdm", dmt1_clk_mux_sel, + OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, OMAP4430_CLKSEL_MASK, + abe_dpll_bypass_clk_mux_ck_parents, + func_dmic_abe_gfclk_ops); static struct clk usb_host_fs_fck; @@ -1557,7 +1498,7 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X), CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk, CK_446X), CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X), - CLK(NULL, "dmic_fck", &dmic_fck, CK_443X), + CLK(NULL, "func_dmic_abe_gfclk", &func_dmic_abe_gfclk, CK_443X), CLK(NULL, "dss_sys_clk", &dss_sys_clk, CK_443X), CLK(NULL, "dss_tv_clk", &dss_tv_clk, CK_443X), CLK(NULL, "dss_dss_clk", &dss_dss_clk, CK_443X), @@ -1571,21 +1512,21 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "gpio4_dbclk", &gpio4_dbclk, CK_443X), CLK(NULL, "gpio5_dbclk", &gpio5_dbclk, CK_443X), CLK(NULL, "gpio6_dbclk", &gpio6_dbclk, CK_443X), - CLK(NULL, "gpu_fck", &gpu_fck, CK_443X), + CLK(NULL, "sgx_clk_mux", &sgx_clk_mux, CK_443X), CLK(NULL, "hsi_fck", &hsi_fck, CK_443X), CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X), CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck, CK_443X), - CLK(NULL, "mcasp_fck", &mcasp_fck, CK_443X), + CLK(NULL, "func_mcasp_abe_gfclk", &func_mcasp_abe_gfclk, CK_443X), CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck, CK_443X), - CLK(NULL, "mcbsp1_fck", &mcbsp1_fck, CK_443X), + CLK(NULL, "func_mcbsp1_gfclk", &func_mcbsp1_gfclk, CK_443X), CLK(NULL, "mcbsp2_sync_mux_ck", &mcbsp2_sync_mux_ck, CK_443X), - CLK(NULL, "mcbsp2_fck", &mcbsp2_fck, CK_443X), + CLK(NULL, "func_mcbsp2_gfclk", &func_mcbsp2_gfclk, CK_443X), CLK(NULL, "mcbsp3_sync_mux_ck", &mcbsp3_sync_mux_ck, CK_443X), - CLK(NULL, "mcbsp3_fck", &mcbsp3_fck, CK_443X), + CLK(NULL, "func_mcbsp3_gfclk", &func_mcbsp3_gfclk, CK_443X), CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck, CK_443X), - CLK(NULL, "mcbsp4_fck", &mcbsp4_fck, CK_443X), - CLK(NULL, "mmc1_fck", &mmc1_fck, CK_443X), - CLK(NULL, "mmc2_fck", &mmc2_fck, CK_443X), + CLK(NULL, "per_mcbsp4_gfclk", &per_mcbsp4_gfclk, CK_443X), + CLK(NULL, "hsmmc1_fclk", &hsmmc1_fclk, CK_443X), + CLK(NULL, "hsmmc2_fclk", &hsmmc2_fclk, CK_443X), CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_443X), CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_443X), CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_443X), @@ -1597,17 +1538,17 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck, CK_443X), CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck, CK_443X), CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck, CK_443X), - CLK(NULL, "timer1_fck", &timer1_fck, CK_443X), - CLK(NULL, "timer10_fck", &timer10_fck, CK_443X), - CLK(NULL, "timer11_fck", &timer11_fck, CK_443X), - CLK(NULL, "timer2_fck", &timer2_fck, CK_443X), - CLK(NULL, "timer3_fck", &timer3_fck, CK_443X), - CLK(NULL, "timer4_fck", &timer4_fck, CK_443X), - CLK(NULL, "timer5_fck", &timer5_fck, CK_443X), - CLK(NULL, "timer6_fck", &timer6_fck, CK_443X), - CLK(NULL, "timer7_fck", &timer7_fck, CK_443X), - CLK(NULL, "timer8_fck", &timer8_fck, CK_443X), - CLK(NULL, "timer9_fck", &timer9_fck, CK_443X), + CLK(NULL, "dmt1_clk_mux", &dmt1_clk_mux, CK_443X), + CLK(NULL, "cm2_dm10_mux", &cm2_dm10_mux, CK_443X), + CLK(NULL, "cm2_dm11_mux", &cm2_dm11_mux, CK_443X), + CLK(NULL, "cm2_dm2_mux", &cm2_dm2_mux, CK_443X), + CLK(NULL, "cm2_dm3_mux", &cm2_dm3_mux, CK_443X), + CLK(NULL, "cm2_dm4_mux", &cm2_dm4_mux, CK_443X), + CLK(NULL, "timer5_sync_mux", &timer5_sync_mux, CK_443X), + CLK(NULL, "timer6_sync_mux", &timer6_sync_mux, CK_443X), + CLK(NULL, "timer7_sync_mux", &timer7_sync_mux, CK_443X), + CLK(NULL, "timer8_sync_mux", &timer8_sync_mux, CK_443X), + CLK(NULL, "cm2_dm9_mux", &cm2_dm9_mux, CK_443X), CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X), CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck, CK_443X), CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X), diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index def97aa9a040..a1849a883702 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -616,7 +616,7 @@ static struct omap_hwmod omap44xx_dmic_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_dmic_irqs, .sdma_reqs = omap44xx_dmic_sdma_reqs, - .main_clk = "dmic_fck", + .main_clk = "func_dmic_abe_gfclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET, @@ -1405,7 +1405,7 @@ static struct omap_hwmod omap44xx_gpu_hwmod = { .class = &omap44xx_gpu_hwmod_class, .clkdm_name = "l3_gfx_clkdm", .mpu_irqs = omap44xx_gpu_irqs, - .main_clk = "gpu_fck", + .main_clk = "sgx_clk_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_GFX_GFX_CLKCTRL_OFFSET, @@ -1920,7 +1920,7 @@ static struct omap_hwmod omap44xx_mcasp_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_mcasp_irqs, .sdma_reqs = omap44xx_mcasp_sdma_reqs, - .main_clk = "mcasp_fck", + .main_clk = "func_mcasp_abe_gfclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET, @@ -1972,7 +1972,7 @@ static struct omap_hwmod omap44xx_mcbsp1_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_mcbsp1_irqs, .sdma_reqs = omap44xx_mcbsp1_sdma_reqs, - .main_clk = "mcbsp1_fck", + .main_clk = "func_mcbsp1_gfclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET, @@ -2007,7 +2007,7 @@ static struct omap_hwmod omap44xx_mcbsp2_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_mcbsp2_irqs, .sdma_reqs = omap44xx_mcbsp2_sdma_reqs, - .main_clk = "mcbsp2_fck", + .main_clk = "func_mcbsp2_gfclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET, @@ -2042,7 +2042,7 @@ static struct omap_hwmod omap44xx_mcbsp3_hwmod = { .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_mcbsp3_irqs, .sdma_reqs = omap44xx_mcbsp3_sdma_reqs, - .main_clk = "mcbsp3_fck", + .main_clk = "func_mcbsp3_gfclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET, @@ -2077,7 +2077,7 @@ static struct omap_hwmod omap44xx_mcbsp4_hwmod = { .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_mcbsp4_irqs, .sdma_reqs = omap44xx_mcbsp4_sdma_reqs, - .main_clk = "mcbsp4_fck", + .main_clk = "per_mcbsp4_gfclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET, @@ -2363,7 +2363,7 @@ static struct omap_hwmod omap44xx_mmc1_hwmod = { .clkdm_name = "l3_init_clkdm", .mpu_irqs = omap44xx_mmc1_irqs, .sdma_reqs = omap44xx_mmc1_sdma_reqs, - .main_clk = "mmc1_fck", + .main_clk = "hsmmc1_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET, @@ -2392,7 +2392,7 @@ static struct omap_hwmod omap44xx_mmc2_hwmod = { .clkdm_name = "l3_init_clkdm", .mpu_irqs = omap44xx_mmc2_irqs, .sdma_reqs = omap44xx_mmc2_sdma_reqs, - .main_clk = "mmc2_fck", + .main_clk = "hsmmc2_fclk", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET, @@ -3162,7 +3162,7 @@ static struct omap_hwmod omap44xx_timer1_hwmod = { .clkdm_name = "l4_wkup_clkdm", .flags = HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_timer1_irqs, - .main_clk = "timer1_fck", + .main_clk = "dmt1_clk_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_WKUP_TIMER1_CLKCTRL_OFFSET, @@ -3185,7 +3185,7 @@ static struct omap_hwmod omap44xx_timer2_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_timer2_irqs, - .main_clk = "timer2_fck", + .main_clk = "cm2_dm2_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET, @@ -3206,7 +3206,7 @@ static struct omap_hwmod omap44xx_timer3_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_timer3_irqs, - .main_clk = "timer3_fck", + .main_clk = "cm2_dm3_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET, @@ -3227,7 +3227,7 @@ static struct omap_hwmod omap44xx_timer4_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_timer4_irqs, - .main_clk = "timer4_fck", + .main_clk = "cm2_dm4_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET, @@ -3248,7 +3248,7 @@ static struct omap_hwmod omap44xx_timer5_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_timer5_irqs, - .main_clk = "timer5_fck", + .main_clk = "timer5_sync_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET, @@ -3270,8 +3270,7 @@ static struct omap_hwmod omap44xx_timer6_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_timer6_irqs, - - .main_clk = "timer6_fck", + .main_clk = "timer6_sync_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET, @@ -3293,7 +3292,7 @@ static struct omap_hwmod omap44xx_timer7_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_timer7_irqs, - .main_clk = "timer7_fck", + .main_clk = "timer7_sync_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET, @@ -3315,7 +3314,7 @@ static struct omap_hwmod omap44xx_timer8_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "abe_clkdm", .mpu_irqs = omap44xx_timer8_irqs, - .main_clk = "timer8_fck", + .main_clk = "timer8_sync_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET, @@ -3337,7 +3336,7 @@ static struct omap_hwmod omap44xx_timer9_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_timer9_irqs, - .main_clk = "timer9_fck", + .main_clk = "cm2_dm9_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET, @@ -3360,7 +3359,7 @@ static struct omap_hwmod omap44xx_timer10_hwmod = { .clkdm_name = "l4_per_clkdm", .flags = HWMOD_SET_DEFAULT_CLOCKACT, .mpu_irqs = omap44xx_timer10_irqs, - .main_clk = "timer10_fck", + .main_clk = "cm2_dm10_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET, @@ -3382,7 +3381,7 @@ static struct omap_hwmod omap44xx_timer11_hwmod = { .class = &omap44xx_timer_hwmod_class, .clkdm_name = "l4_per_clkdm", .mpu_irqs = omap44xx_timer11_irqs, - .main_clk = "timer11_fck", + .main_clk = "cm2_dm11_mux", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET, From dd1e4223544412c0f0a39da70462f9f8374ef98d Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:48:55 -0700 Subject: [PATCH 042/148] ARM: OMAP2xxx: clock data: clean up unused null clocks Remove some clocks that don't appear to be used by anything and which are not associated with any hardware registers. Signed-off-by: Paul Walmsley Cc: Rajendra Nayak --- arch/arm/mach-omap2/cclock2420_data.c | 16 +--------------- arch/arm/mach-omap2/cclock2430_data.c | 16 +--------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-omap2/cclock2420_data.c b/arch/arm/mach-omap2/cclock2420_data.c index ab7e952d2070..0f0a97c1fcc0 100644 --- a/arch/arm/mach-omap2/cclock2420_data.c +++ b/arch/arm/mach-omap2/cclock2420_data.c @@ -622,15 +622,10 @@ static struct clk_hw_omap gpios_fck_hw = { DEFINE_STRUCT_CLK(gpios_fck, gpios_fck_parent_names, aes_ick_ops); -static struct clk wu_l4_ick; - -DEFINE_STRUCT_CLK_HW_OMAP(wu_l4_ick, "wkup_clkdm"); -DEFINE_STRUCT_CLK(wu_l4_ick, dpll_ck_parent_names, core_ck_ops); - static struct clk gpios_ick; static const char *gpios_ick_parent_names[] = { - "wu_l4_ick", + "sys_ck", }; static struct clk_hw_omap gpios_ick_hw = { @@ -1682,13 +1677,6 @@ static struct clk_hw_omap wdt1_ick_hw = { DEFINE_STRUCT_CLK(wdt1_ick, gpios_ick_parent_names, aes_ick_ops); -static struct clk wdt1_osc_ck; - -static const struct clk_ops wdt1_osc_ck_ops = {}; - -DEFINE_STRUCT_CLK_HW_OMAP(wdt1_osc_ck, NULL); -DEFINE_STRUCT_CLK(wdt1_osc_ck, sys_ck_parent_names, wdt1_osc_ck_ops); - static struct clk wdt3_fck; static struct clk_hw_omap wdt3_fck_hw = { @@ -1767,7 +1755,6 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "func_96m_ck", &func_96m_ck, CK_242X), CLK(NULL, "func_48m_ck", &func_48m_ck, CK_242X), CLK(NULL, "func_12m_ck", &func_12m_ck, CK_242X), - CLK(NULL, "ck_wdt1_osc", &wdt1_osc_ck, CK_242X), CLK(NULL, "sys_clkout_src", &sys_clkout_src, CK_242X), CLK(NULL, "sys_clkout", &sys_clkout, CK_242X), CLK(NULL, "sys_clkout2_src", &sys_clkout2_src, CK_242X), @@ -1797,7 +1784,6 @@ static struct omap_clk omap2420_clks[] = { /* L4 domain clocks */ CLK(NULL, "l4_ck", &l4_ck, CK_242X), CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_242X), - CLK(NULL, "wu_l4_ick", &wu_l4_ick, CK_242X), /* virtual meta-group clock */ CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_242X), /* general l4 interface ck, multi-parent functional clk */ diff --git a/arch/arm/mach-omap2/cclock2430_data.c b/arch/arm/mach-omap2/cclock2430_data.c index eb3dab68d536..aed8f74ca076 100644 --- a/arch/arm/mach-omap2/cclock2430_data.c +++ b/arch/arm/mach-omap2/cclock2430_data.c @@ -601,15 +601,10 @@ static struct clk_hw_omap gpios_fck_hw = { DEFINE_STRUCT_CLK(gpios_fck, gpio5_fck_parent_names, aes_ick_ops); -static struct clk wu_l4_ick; - -DEFINE_STRUCT_CLK_HW_OMAP(wu_l4_ick, "wkup_clkdm"); -DEFINE_STRUCT_CLK(wu_l4_ick, dpll_ck_parent_names, core_ck_ops); - static struct clk gpios_ick; static const char *gpios_ick_parent_names[] = { - "wu_l4_ick", + "sys_ck", }; static struct clk_hw_omap gpios_ick_hw = { @@ -1811,13 +1806,6 @@ static struct clk_hw_omap wdt1_ick_hw = { DEFINE_STRUCT_CLK(wdt1_ick, gpios_ick_parent_names, aes_ick_ops); -static struct clk wdt1_osc_ck; - -static const struct clk_ops wdt1_osc_ck_ops = {}; - -DEFINE_STRUCT_CLK_HW_OMAP(wdt1_osc_ck, NULL); -DEFINE_STRUCT_CLK(wdt1_osc_ck, sys_ck_parent_names, wdt1_osc_ck_ops); - static struct clk wdt4_fck; static struct clk_hw_omap wdt4_fck_hw = { @@ -1869,7 +1857,6 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "func_96m_ck", &func_96m_ck, CK_243X), CLK(NULL, "func_48m_ck", &func_48m_ck, CK_243X), CLK(NULL, "func_12m_ck", &func_12m_ck, CK_243X), - CLK(NULL, "ck_wdt1_osc", &wdt1_osc_ck, CK_243X), CLK(NULL, "sys_clkout_src", &sys_clkout_src, CK_243X), CLK(NULL, "sys_clkout", &sys_clkout, CK_243X), CLK(NULL, "emul_ck", &emul_ck, CK_243X), @@ -1898,7 +1885,6 @@ static struct omap_clk omap2430_clks[] = { /* L4 domain clocks */ CLK(NULL, "l4_ck", &l4_ck, CK_243X), CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_243X), - CLK(NULL, "wu_l4_ick", &wu_l4_ick, CK_243X), /* virtual meta-group clock */ CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_243X), /* general l4 interface ck, multi-parent functional clk */ From 8e1ff676ef5fd4d8be4947ffd039f2699a4b1079 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:12 -0700 Subject: [PATCH 043/148] ARM: OMAP2xxx: powerdomain: core powerdomain missing logic retention states Add the possible logic retention states for the 24xx CORE powerdomain. Subsequent patches use this data to avoid returning incorrect data, by skipping reads from register bitfields that don't actually exist. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomains2xxx_data.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-omap2/powerdomains2xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_data.c index ba520d4f7c7b..01abc1e77789 100644 --- a/arch/arm/mach-omap2/powerdomains2xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains2xxx_data.c @@ -60,6 +60,7 @@ static struct powerdomain core_24xx_pwrdm = { .name = "core_pwrdm", .prcm_offs = CORE_MOD, .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts_logic_ret = PWRSTS_RET, .banks = 3, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */ From fd6b42a5614077b04ce8f34fbbcf16864723f5df Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:12 -0700 Subject: [PATCH 044/148] ARM: OMAP3xxx: CPUIdle: simplify the PER next-state code The OMAP3xxx CPUIdle driver contains some code to place a lower bound on the PER powerdomain's power state. Convert this code to a data-driven implementation to remove branches and to improve readability. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/cpuidle34xx.c | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 22590dbe8f14..cba69455647a 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -36,40 +36,53 @@ /* Mach specific information to be recorded in the C-state driver_data */ struct omap3_idle_statedata { - u32 mpu_state; - u32 core_state; + u8 mpu_state; + u8 core_state; + u8 per_min_state; }; static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; +/* + * Prevent PER OFF if CORE is not in RETention or OFF as this would + * disable PER wakeups completely. + */ static struct omap3_idle_statedata omap3_idle_data[] = { { .mpu_state = PWRDM_POWER_ON, .core_state = PWRDM_POWER_ON, + /* In C1 do not allow PER state lower than CORE state */ + .per_min_state = PWRDM_POWER_ON, }, { .mpu_state = PWRDM_POWER_ON, .core_state = PWRDM_POWER_ON, + .per_min_state = PWRDM_POWER_RET, }, { .mpu_state = PWRDM_POWER_RET, .core_state = PWRDM_POWER_ON, + .per_min_state = PWRDM_POWER_RET, }, { .mpu_state = PWRDM_POWER_OFF, .core_state = PWRDM_POWER_ON, + .per_min_state = PWRDM_POWER_RET, }, { .mpu_state = PWRDM_POWER_RET, .core_state = PWRDM_POWER_RET, + .per_min_state = PWRDM_POWER_OFF, }, { .mpu_state = PWRDM_POWER_OFF, .core_state = PWRDM_POWER_RET, + .per_min_state = PWRDM_POWER_OFF, }, { .mpu_state = PWRDM_POWER_OFF, .core_state = PWRDM_POWER_OFF, + .per_min_state = PWRDM_POWER_OFF, }, }; @@ -209,10 +222,9 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - int new_state_idx; - u32 core_next_state, per_next_state = 0, per_saved_state = 0; + int new_state_idx, ret; + u8 per_next_state, per_saved_state; struct omap3_idle_statedata *cx; - int ret; /* * Use only C1 if CAM is active. @@ -233,25 +245,13 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, /* Program PER state */ cx = &omap3_idle_data[new_state_idx]; - core_next_state = cx->core_state; - per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); - if (new_state_idx == 0) { - /* In C1 do not allow PER state lower than CORE state */ - if (per_next_state < core_next_state) - per_next_state = core_next_state; - } else { - /* - * Prevent PER OFF if CORE is not in RETention or OFF as this - * would disable PER wakeups completely. - */ - if ((per_next_state == PWRDM_POWER_OFF) && - (core_next_state > PWRDM_POWER_RET)) - per_next_state = PWRDM_POWER_RET; - } - /* Are we changing PER target state? */ - if (per_next_state != per_saved_state) + per_next_state = pwrdm_read_next_pwrst(per_pd); + per_saved_state = per_next_state; + if (per_next_state < cx->per_min_state) { + per_next_state = cx->per_min_state; pwrdm_set_next_pwrst(per_pd, per_next_state); + } ret = omap3_enter_idle(dev, drv, new_state_idx); From fa2002223e12c6b1bc96381b70c376afe4e01d80 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:48:56 -0700 Subject: [PATCH 045/148] ARM: OMAP2+: hwmod: add support for blocking WFI when a device is active Apparently, on some OMAPs, the MPU can't be allowed to enter WFI while certain peripherals are active. It's not clear why, and it's likely that there is simply some other bug in the driver or integration code. But since the likelihood that anyone will have the time to track these problems down in the future seems quite small, we'll provide a flag, HWMOD_BLOCK_WFI, to mark these issues in the hwmod data. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 8 ++++++++ arch/arm/mach-omap2/omap_hwmod.h | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 4653efb87a27..6804d474a47d 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -139,6 +139,8 @@ #include #include +#include + #include "clock.h" #include "omap_hwmod.h" @@ -2134,6 +2136,8 @@ static int _enable(struct omap_hwmod *oh) _enable_clocks(oh); if (soc_ops.enable_module) soc_ops.enable_module(oh); + if (oh->flags & HWMOD_BLOCK_WFI) + disable_hlt(); if (soc_ops.update_context_lost) soc_ops.update_context_lost(oh); @@ -2195,6 +2199,8 @@ static int _idle(struct omap_hwmod *oh) _idle_sysc(oh); _del_initiator_dep(oh, mpu_oh); + if (oh->flags & HWMOD_BLOCK_WFI) + enable_hlt(); if (soc_ops.disable_module) soc_ops.disable_module(oh); @@ -2303,6 +2309,8 @@ static int _shutdown(struct omap_hwmod *oh) if (oh->_state == _HWMOD_STATE_ENABLED) { _del_initiator_dep(oh, mpu_oh); /* XXX what about the other system initiators here? dma, dsp */ + if (oh->flags & HWMOD_BLOCK_WFI) + enable_hlt(); if (soc_ops.disable_module) soc_ops.disable_module(oh); _disable_clocks(oh); diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index 3ae852a522f9..80c00e706d69 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -451,6 +451,14 @@ struct omap_hwmod_omap4_prcm { * enabled. This prevents the hwmod code from being able to * enable and reset the IP block early. XXX Eventually it should * be possible to query the clock framework for this information. + * HWMOD_BLOCK_WFI: Some OMAP peripherals apparently don't work + * correctly if the MPU is allowed to go idle while the + * peripherals are active. This is apparently true for the I2C on + * OMAP2420, and also the EMAC on AM3517/3505. It's unlikely that + * this is really true -- we're probably not configuring something + * correctly, or this is being abused to deal with some PM latency + * issues -- but we're currently suffering from a shortage of + * folks who are able to track these issues down properly. */ #define HWMOD_SWSUP_SIDLE (1 << 0) #define HWMOD_SWSUP_MSTANDBY (1 << 1) @@ -462,6 +470,7 @@ struct omap_hwmod_omap4_prcm { #define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7) #define HWMOD_16BIT_REG (1 << 8) #define HWMOD_EXT_OPT_MAIN_CLK (1 << 9) +#define HWMOD_BLOCK_WFI (1 << 10) /* * omap_hwmod._int_flags definitions From aff2f7d90fc6553aa309db2a635d8e5d70d84916 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:48:56 -0700 Subject: [PATCH 046/148] ARM: OMAP2420: hwmod data/PM: use hwmod to block WFI when I2C active Use the HWMOD_BLOCK_WFI flag in the hwmod data to prevent the MPU from entering WFI when the I2C devices are active. No idea why this is needed; this could certainly bear further investigation if anyone is interested. The objective here is to remove some custom code from the OMAP24xx PM code. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/omap_hwmod_2420_data.c | 7 ++++++- arch/arm/mach-omap2/pm24xx.c | 13 ------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index b5efe58c0be0..6a764af6c6d3 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -121,7 +121,12 @@ static struct omap_hwmod omap2420_i2c1_hwmod = { }, .class = &i2c_class, .dev_attr = &i2c_dev_attr, - .flags = HWMOD_16BIT_REG, + /* + * From mach-omap2/pm24xx.c: "Putting MPU into the WFI state + * while a transfer is active seems to cause the I2C block to + * timeout. Why? Good question." + */ + .flags = (HWMOD_16BIT_REG | HWMOD_BLOCK_WFI), }; /* I2C2 */ diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index c333fa6dffa8..909ef53ba2ea 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -140,14 +140,6 @@ no_sleep: return 0; } -static int omap2_i2c_active(void) -{ - u32 l; - - l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); - return l & (OMAP2420_EN_I2C2_MASK | OMAP2420_EN_I2C1_MASK); -} - static int sti_console_enabled; static int omap2_allow_mpu_retention(void) @@ -172,11 +164,6 @@ static int omap2_allow_mpu_retention(void) static void omap2_enter_mpu_retention(void) { - /* Putting MPU into the WFI state while a transfer is active - * seems to cause the I2C block to timeout. Why? Good question. */ - if (omap2_i2c_active()) - return; - /* The peripherals seem not to be able to wake up the MPU when * it is in retention mode. */ if (omap2_allow_mpu_retention()) { From 4dd2bd3736d1c40a9bcc12bd6d9a9fd30e99aa7a Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Fri, 11 Jan 2013 15:26:55 +0200 Subject: [PATCH 047/148] ARM: tegra: Add CPU nodes to Tegra20 device tree Add CPU node for Tegra20. Signed-off-by: Hiroshi Doyu Reviewed-by: Lorenzo Pieralisi Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra20.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index b8effa1cbda7..3398df6b4d2f 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -410,6 +410,23 @@ status = "disabled"; }; + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <1>; + }; + }; + pmu { compatible = "arm,cortex-a9-pmu"; interrupts = <0 56 0x04 From 7d19a34a89b8c5401bfa56c96fe05c644ecaeafe Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Fri, 11 Jan 2013 15:11:54 +0200 Subject: [PATCH 048/148] ARM: tegra: Add CPU nodes to Tegra30 device tree Add CPU node for Tegra30. Signed-off-by: Hiroshi Doyu Reviewed-by: Lorenzo Pieralisi Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra30.dtsi | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 529fdb82dfdb..d7f5b54e61de 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -446,6 +446,35 @@ status = "disabled"; }; + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <1>; + }; + + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <2>; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <3>; + }; + }; + pmu { compatible = "arm,cortex-a9-pmu"; interrupts = <0 144 0x04 From a8a6930157e0e4a2d57abefee487fc4ceba4d53e Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 15 Jan 2013 10:13:12 +0200 Subject: [PATCH 049/148] ARM: tegra: Use DT /cpu node to detect number of CPU core SCU based detection only works with Cortex-A9 MP and it doesn't support ones with multiple clusters. The only way to detect number of CPU core correctly is with DT /cpu node. Tegra SoCs decided to use DT detection as the only way and to not use SCU based detection at all. Even if DT /cpu node based detection fails, it continues with a single core Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/platsmp.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 1b926df99c4b..79fa7857d68d 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -143,23 +143,8 @@ done: return status; } -/* - * Initialise the CPU possible map early - this describes the CPUs - * which may be present or become present in the system. - */ static void __init tegra_smp_init_cpus(void) { - unsigned int i, ncores = scu_get_core_count(scu_base); - - if (ncores > nr_cpu_ids) { - pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", - ncores, nr_cpu_ids); - ncores = nr_cpu_ids; - } - - for (i = 0; i < ncores; i++) - set_cpu_possible(i, true); - set_smp_cross_call(gic_raise_softirq); } From e9d6b3358ac35901ccc6a4a5a317670fa469db25 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 22 Jan 2013 07:52:01 +0200 Subject: [PATCH 050/148] ARM: Add API to detect SCU base address from CP15 Add API to detect SCU base address from CP15. Signed-off-by: Hiroshi Doyu Acked-by: Russell King Signed-off-by: Stephen Warren --- arch/arm/include/asm/smp_scu.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h index 4eb6d005ffaa..006f02681cd8 100644 --- a/arch/arm/include/asm/smp_scu.h +++ b/arch/arm/include/asm/smp_scu.h @@ -6,6 +6,23 @@ #define SCU_PM_POWEROFF 3 #ifndef __ASSEMBLER__ + +#include + +static inline bool scu_a9_has_base(void) +{ + return read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9; +} + +static inline unsigned long scu_a9_get_base(void) +{ + unsigned long pa; + + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (pa)); + + return pa; +} + unsigned int scu_get_core_count(void __iomem *); void scu_enable(void __iomem *); int scu_power_mode(void __iomem *, unsigned int); From 909444ab20629ebc4478642b660a391700aa7e33 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 22 Jan 2013 07:52:02 +0200 Subject: [PATCH 051/148] ARM: tegra: Skip scu_enable(scu_base) if not Cortex A9 Skip scu_enable(scu_base) if CPU is not Cortex A9 with SCU. Signed-off-by: Hiroshi Doyu Acked-by: Russell King Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/platsmp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 79fa7857d68d..8127d766fcfa 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -36,8 +36,6 @@ extern void tegra_secondary_startup(void); -static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); - #define EVP_CPU_RESET_VECTOR \ (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) @@ -151,7 +149,8 @@ static void __init tegra_smp_init_cpus(void) static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) { tegra_cpu_reset_handler_init(); - scu_enable(scu_base); + if (scu_a9_has_base()) + scu_enable(IO_ADDRESS(scu_a9_get_base())); } struct smp_operations tegra_smp_ops __initdata = { From 80d9375617f7544f7475e7f07003a08930559d43 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 23 Jan 2013 13:56:19 +0530 Subject: [PATCH 052/148] ARM: OMAP: Make use of available scu_a9_get_base() interface Drop the define and make use of scu_a9_get_base() which reads the physical address of SCU from CP15 register. Signed-off-by: Santosh Shilimkar Signed-off-by: Stephen Warren --- arch/arm/mach-omap2/omap-smp.c | 2 +- arch/arm/mach-omap2/omap44xx.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index cd42d921940d..e683d0dcef6b 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -215,7 +215,7 @@ static void __init omap4_smp_init_cpus(void) * Currently we can't call ioremap here because * SoC detection won't work until after init_early. */ - scu_base = OMAP2_L4_IO_ADDRESS(OMAP44XX_SCU_BASE); + scu_base = OMAP2_L4_IO_ADDRESS(scu_a9_get_base()); BUG_ON(!scu_base); ncores = scu_get_core_count(scu_base); } else if (cpu_id == CPU_CORTEX_A15) { diff --git a/arch/arm/mach-omap2/omap44xx.h b/arch/arm/mach-omap2/omap44xx.h index 43b927b2e2e8..8a515bb74639 100644 --- a/arch/arm/mach-omap2/omap44xx.h +++ b/arch/arm/mach-omap2/omap44xx.h @@ -40,7 +40,6 @@ #define OMAP44XX_GIC_DIST_BASE 0x48241000 #define OMAP44XX_GIC_CPU_BASE 0x48240100 #define OMAP44XX_IRQ_GIC_START 32 -#define OMAP44XX_SCU_BASE 0x48240000 #define OMAP44XX_LOCAL_TWD_BASE 0x48240600 #define OMAP44XX_L2CACHE_BASE 0x48242000 #define OMAP44XX_WKUPGEN_BASE 0x48281000 From c7736edf1b1734455c186deec53a0aa7f8fa87ea Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:19 +0530 Subject: [PATCH 053/148] ARM: tegra: add function to read chipid Add function to read chip id from APB MISC registers. This function will also get called from clock driver to flush write operations on apb bus. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/fuse.c | 8 +++++++- include/linux/tegra-soc.h | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 include/linux/tegra-soc.h diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 8121742711fe..f7db0782a6b6 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "fuse.h" #include "iomap.h" @@ -105,6 +106,11 @@ static void tegra_get_process_id(void) tegra_core_process_id = (reg >> 12) & 3; } +u32 tegra_read_chipid(void) +{ + return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); +} + void tegra_init_fuse(void) { u32 id; @@ -119,7 +125,7 @@ void tegra_init_fuse(void) reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; - id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); + id = tegra_read_chipid(); tegra_chip_id = (id >> 8) & 0xff; switch (tegra_chip_id) { diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h new file mode 100644 index 000000000000..95f611d78f3a --- /dev/null +++ b/include/linux/tegra-soc.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __LINUX_TEGRA_SOC_H_ +#define __LINUX_TEGRA_SOC_H_ + +u32 tegra_read_chipid(void); + +#endif /* __LINUX_TEGRA_SOC_H_ */ From 89572c77cdffdf24f8fec50d3e38db6a18c04dbe Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:21 +0530 Subject: [PATCH 054/148] ARM: tegra: move tegra_cpu_car.h to linux/clk/tegra.h tegra_cpu_car_ops struct is going to be accessed from drivers/clk/tegra. Move the tegra_cpu_car_ops to include/linux/clk/tegra.h. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/clock.c | 2 +- arch/arm/mach-tegra/cpuidle-tegra30.c | 2 +- arch/arm/mach-tegra/hotplug.c | 2 +- arch/arm/mach-tegra/platsmp.c | 2 +- arch/arm/mach-tegra/pm.c | 2 +- arch/arm/mach-tegra/tegra20_clocks.c | 2 +- arch/arm/mach-tegra/tegra20_clocks_data.c | 2 +- arch/arm/mach-tegra/tegra30_clocks.c | 2 +- arch/arm/mach-tegra/tegra30_clocks_data.c | 2 +- .../mach-tegra/tegra_cpu_car.h => include/linux/clk/tegra.h | 6 +++--- 10 files changed, 12 insertions(+), 12 deletions(-) rename arch/arm/mach-tegra/tegra_cpu_car.h => include/linux/clk/tegra.h (96%) diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 867bf8bf5561..8c0ff061f8cf 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -26,10 +26,10 @@ #include #include #include +#include #include "board.h" #include "clock.h" -#include "tegra_cpu_car.h" /* Global data of Tegra CPU CAR ops */ struct tegra_cpu_car_ops *tegra_cpu_car_ops; diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 82530bd9b8c2..8b50cf4ddd6f 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,6 @@ #include "pm.h" #include "sleep.h" -#include "tegra_cpu_car.h" #ifdef CONFIG_PM_SLEEP static int tegra30_idle_lp2(struct cpuidle_device *dev, diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index 6a27de4001ee..a599f6e36dea 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -10,12 +10,12 @@ */ #include #include +#include #include #include #include "sleep.h" -#include "tegra_cpu_car.h" static void (*tegra_hotplug_shutdown)(void); diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 68670304d9bc..3ec7fc487857 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,6 @@ #include "fuse.h" #include "flowctrl.h" #include "reset.h" -#include "tegra_cpu_car.h" #include "common.h" #include "iomap.h" diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 498d70b33775..abfe9b93cc0c 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,6 @@ #include "reset.h" #include "flowctrl.h" #include "sleep.h" -#include "tegra_cpu_car.h" #define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c index 4eb6bc81a87b..1a80ff65e5fc 100644 --- a/arch/arm/mach-tegra/tegra20_clocks.c +++ b/arch/arm/mach-tegra/tegra20_clocks.c @@ -26,12 +26,12 @@ #include #include #include +#include #include "clock.h" #include "fuse.h" #include "iomap.h" #include "tegra2_emc.h" -#include "tegra_cpu_car.h" #define RST_DEVICES 0x004 #define RST_DEVICES_SET 0x300 diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c index a23a0734e352..022cdaef7ca5 100644 --- a/arch/arm/mach-tegra/tegra20_clocks_data.c +++ b/arch/arm/mach-tegra/tegra20_clocks_data.c @@ -26,12 +26,12 @@ #include #include #include +#include #include "clock.h" #include "fuse.h" #include "tegra2_emc.h" #include "tegra20_clocks.h" -#include "tegra_cpu_car.h" /* Clock definitions */ diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index d7147779f8ea..4330787fe5cb 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -36,7 +37,6 @@ #include "clock.h" #include "fuse.h" #include "iomap.h" -#include "tegra_cpu_car.h" #define USE_PLL_LOCK_BITS 0 diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c index 741d264d5ecb..9bfaa490cff6 100644 --- a/arch/arm/mach-tegra/tegra30_clocks_data.c +++ b/arch/arm/mach-tegra/tegra30_clocks_data.c @@ -28,11 +28,11 @@ #include #include #include +#include #include "clock.h" #include "fuse.h" #include "tegra30_clocks.h" -#include "tegra_cpu_car.h" #define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ _parent_names, _parents, _parent) \ diff --git a/arch/arm/mach-tegra/tegra_cpu_car.h b/include/linux/clk/tegra.h similarity index 96% rename from arch/arm/mach-tegra/tegra_cpu_car.h rename to include/linux/clk/tegra.h index 9764d31032b7..0977f2a24757 100644 --- a/arch/arm/mach-tegra/tegra_cpu_car.h +++ b/include/linux/clk/tegra.h @@ -14,8 +14,8 @@ * along with this program. If not, see . */ -#ifndef __MACH_TEGRA_CPU_CAR_H -#define __MACH_TEGRA_CPU_CAR_H +#ifndef __LINUX_CLK_TEGRA_H_ +#define __LINUX_CLK_TEGRA_H_ /* * Tegra CPU clock and reset control ops @@ -121,4 +121,4 @@ static inline void tegra_cpu_clock_resume(void) void tegra20_cpu_car_ops_init(void); void tegra30_cpu_car_ops_init(void); -#endif /* __MACH_TEGRA_CPU_CAR_H */ +#endif /* __LINUX_CLK_TEGRA_H_ */ From 270f8ce3122b12f4224f7c72806ebf05e23835a6 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 11 Jan 2013 13:16:22 +0530 Subject: [PATCH 055/148] ARM: tegra: define Tegra20 CAR binding The Tegra20 CAR (Clock And Reset) Controller controls most aspects of most clocks within Tegra20. The device tree binding models this as a single monolithic clock provider, which exports many clocks. This reduces the number of nodes needed in device tree to represent these clocks. This binding is only useful for Tegra20; the set of clocks that exists on Tegra30 is sufficiently different to merit its own binding. Signed-off-by: Stephen Warren Acked-by: Simon Glass [pgaikwad: Added mux clk ids and sorted CAR node] Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- .../bindings/clock/nvidia,tegra20-car.txt | 205 ++++++++++++++++++ arch/arm/boot/dts/tegra20.dtsi | 6 + 2 files changed, 211 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt new file mode 100644 index 000000000000..0921fac73528 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt @@ -0,0 +1,205 @@ +NVIDIA Tegra20 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra20-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the CAR. + + The first 96 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB + registers. These IDs often match those in the CAR's RST_DEVICES registers, + but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In + this case, those clocks are assigned IDs above 95 in order to highlight + this issue. Implementations that interpret these clock IDs as bit values + within the CLK_OUT_ENB or RST_DEVICES registers should be careful to + explicitly handle these special cases. + + The balance of the clocks controlled by the CAR are assigned IDs of 96 and + above. + + 0 cpu + 1 unassigned + 2 unassigned + 3 ac97 + 4 rtc + 5 tmr + 6 uart1 + 7 unassigned (register bit affects uart2 and vfir) + 8 gpio + 9 sdmmc2 + 10 unassigned (register bit affects spdif_in and spdif_out) + 11 i2s1 + 12 i2c1 + 13 ndflash + 14 sdmmc1 + 15 sdmmc4 + 16 twc + 17 pwm + 18 i2s2 + 19 epp + 20 unassigned (register bit affects vi and vi_sensor) + 21 2d + 22 usbd + 23 isp + 24 3d + 25 ide + 26 disp2 + 27 disp1 + 28 host1x + 29 vcp + 30 unassigned + 31 cache2 + + 32 mem + 33 ahbdma + 34 apbdma + 35 unassigned + 36 kbc + 37 stat_mon + 38 pmc + 39 fuse + 40 kfuse + 41 sbc1 + 42 snor + 43 spi1 + 44 sbc2 + 45 xio + 46 sbc3 + 47 dvc + 48 dsi + 49 unassigned (register bit affects tvo and cve) + 50 mipi + 51 hdmi + 52 csi + 53 tvdac + 54 i2c2 + 55 uart3 + 56 unassigned + 57 emc + 58 usb2 + 59 usb3 + 60 mpe + 61 vde + 62 bsea + 63 bsev + + 64 speedo + 65 uart4 + 66 uart5 + 67 i2c3 + 68 sbc4 + 69 sdmmc3 + 70 pcie + 71 owr + 72 afi + 73 csite + 74 unassigned + 75 avpucq + 76 la + 77 unassigned + 78 unassigned + 79 unassigned + 80 unassigned + 81 unassigned + 82 unassigned + 83 unassigned + 84 irama + 85 iramb + 86 iramc + 87 iramd + 88 cram2 + 89 audio_2x a/k/a audio_2x_sync_clk + 90 clk_d + 91 unassigned + 92 sus + 93 cdev1 + 94 cdev2 + 95 unassigned + + 96 uart2 + 97 vfir + 98 spdif_in + 99 spdif_out + 100 vi + 101 vi_sensor + 102 tvo + 103 cve + 104 osc + 105 clk_32k a/k/a clk_s + 106 clk_m + 107 sclk + 108 cclk + 109 hclk + 110 pclk + 111 blink + 112 pll_a + 113 pll_a_out0 + 114 pll_c + 115 pll_c_out1 + 116 pll_d + 117 pll_d_out0 + 118 pll_e + 119 pll_m + 120 pll_m_out1 + 121 pll_p + 122 pll_p_out1 + 123 pll_p_out2 + 124 pll_p_out3 + 125 pll_p_out4 + 126 pll_s + 127 pll_u + 128 pll_x + 129 cop a/k/a avp + 130 audio a/k/a audio_sync_clk + 131 pll_ref + 132 twd + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra20-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car 58>; /* usb2 */ + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index b8effa1cbda7..5b104f1d5003 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -123,6 +123,12 @@ 0 42 0x04>; }; + tegra_car: clock { + compatible = "nvidia,tegra20-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + apbdma: dma { compatible = "nvidia,tegra20-apbdma"; reg = <0x6000a000 0x1200>; From 9598566721fe7524cca575975ea7e8ea2e27a71b Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:23 +0530 Subject: [PATCH 056/148] ARM: tegra: define Tegra30 CAR binding The device tree binding models Tegra30 CAR (Clock And Reset) as a single monolithic clock provider. Signed-off-by: Prashant Gaikwad [swarren: fixed typo in binding doc] Signed-off-by: Stephen Warren --- .../bindings/clock/nvidia,tegra30-car.txt | 262 ++++++++++++++++++ arch/arm/boot/dts/tegra30.dtsi | 6 + 2 files changed, 268 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt new file mode 100644 index 000000000000..f3da3be5fcad --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt @@ -0,0 +1,262 @@ +NVIDIA Tegra30 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra30-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the CAR. + + The first 130 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB + registers. These IDs often match those in the CAR's RST_DEVICES registers, + but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In + this case, those clocks are assigned IDs above 160 in order to highlight + this issue. Implementations that interpret these clock IDs as bit values + within the CLK_OUT_ENB or RST_DEVICES registers should be careful to + explicitly handle these special cases. + + The balance of the clocks controlled by the CAR are assigned IDs of 160 and + above. + + 0 cpu + 1 unassigned + 2 unassigned + 3 unassigned + 4 rtc + 5 timer + 6 uarta + 7 unassigned (register bit affects uartb and vfir) + 8 gpio + 9 sdmmc2 + 10 unassigned (register bit affects spdif_in and spdif_out) + 11 i2s1 + 12 i2c1 + 13 ndflash + 14 sdmmc1 + 15 sdmmc4 + 16 unassigned + 17 pwm + 18 i2s2 + 19 epp + 20 unassigned (register bit affects vi and vi_sensor) + 21 2d + 22 usbd + 23 isp + 24 3d + 25 unassigned + 26 disp2 + 27 disp1 + 28 host1x + 29 vcp + 30 i2s0 + 31 cop_cache + + 32 mc + 33 ahbdma + 34 apbdma + 35 unassigned + 36 kbc + 37 statmon + 38 pmc + 39 unassigned (register bit affects fuse and fuse_burn) + 40 kfuse + 41 sbc1 + 42 nor + 43 unassigned + 44 sbc2 + 45 unassigned + 46 sbc3 + 47 i2c5 + 48 dsia + 49 unassigned (register bit affects cve and tvo) + 50 mipi + 51 hdmi + 52 csi + 53 tvdac + 54 i2c2 + 55 uartc + 56 unassigned + 57 emc + 58 usb2 + 59 usb3 + 60 mpe + 61 vde + 62 bsea + 63 bsev + + 64 speedo + 65 uartd + 66 uarte + 67 i2c3 + 68 sbc4 + 69 sdmmc3 + 70 pcie + 71 owr + 72 afi + 73 csite + 74 pciex + 75 avpucq + 76 la + 77 unassigned + 78 unassigned + 79 dtv + 80 ndspeed + 81 i2cslow + 82 dsib + 83 unassigned + 84 irama + 85 iramb + 86 iramc + 87 iramd + 88 cram2 + 89 unassigned + 90 audio_2x a/k/a audio_2x_sync_clk + 91 unassigned + 92 csus + 93 cdev2 + 94 cdev1 + 95 unassigned + + 96 cpu_g + 97 cpu_lp + 98 3d2 + 99 mselect + 100 tsensor + 101 i2s3 + 102 i2s4 + 103 i2c4 + 104 sbc5 + 105 sbc6 + 106 d_audio + 107 apbif + 108 dam0 + 109 dam1 + 110 dam2 + 111 hda2codec_2x + 112 atomics + 113 audio0_2x + 114 audio1_2x + 115 audio2_2x + 116 audio3_2x + 117 audio4_2x + 118 audio5_2x + 119 actmon + 120 extern1 + 121 extern2 + 122 extern3 + 123 sata_oob + 124 sata + 125 hda + 127 se + 128 hda2hdmi + 129 sata_cold + + 160 uartb + 161 vfir + 162 spdif_in + 163 spdif_out + 164 vi + 165 vi_sensor + 166 fuse + 167 fuse_burn + 168 cve + 169 tvo + + 170 clk_32k + 171 clk_m + 172 clk_m_div2 + 173 clk_m_div4 + 174 pll_ref + 175 pll_c + 176 pll_c_out1 + 177 pll_m + 178 pll_m_out1 + 179 pll_p + 180 pll_p_out1 + 181 pll_p_out2 + 182 pll_p_out3 + 183 pll_p_out4 + 184 pll_a + 185 pll_a_out0 + 186 pll_d + 187 pll_d_out0 + 188 pll_d2 + 189 pll_d2_out0 + 190 pll_u + 191 pll_x + 192 pll_x_out0 + 193 pll_e + 194 spdif_in_sync + 195 i2s0_sync + 196 i2s1_sync + 197 i2s2_sync + 198 i2s3_sync + 199 i2s4_sync + 200 vimclk + 201 audio0 + 202 audio1 + 203 audio2 + 204 audio3 + 205 audio4 + 206 audio5 + 207 clk_out_1 (extern1) + 208 clk_out_2 (extern2) + 209 clk_out_3 (extern3) + 210 sclk + 211 blink + 212 cclk_g + 213 cclk_lp + 214 twd + 215 cml0 + 216 cml1 + 217 hclk + 218 pclk + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra30-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car 58>; /* usb2 */ + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 529fdb82dfdb..6765646c2248 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -125,6 +125,12 @@ 0 122 0x04>; }; + tegra_car: clock { + compatible = "nvidia,tegra30-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + apbdma: dma { compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; reg = <0x6000a000 0x1400>; From 8f8f484bf355e546c62c47b8a8c8d19b28787798 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:20 +0530 Subject: [PATCH 057/148] clk: tegra: add Tegra specific clocks Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super. Signed-off-by: Prashant Gaikwad [swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re: storing pointers to stack variables, make a timeout loop more idiomatic, use _clk_pll_disable() not clk_disable_pll() from _program_pll() to avoid redundant lock operations, unified tegra_clk_periph() and tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock registration functions so they don't have the same name as the clock structs, return -EINVAL from clk_plle_enable when matching table rate not found, pass ops to _tegra_clk_register_pll rather than a bool.] Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/Makefile | 1 + drivers/clk/tegra/Makefile | 8 + drivers/clk/tegra/clk-audio-sync.c | 87 ++++ drivers/clk/tegra/clk-divider.c | 187 ++++++++ drivers/clk/tegra/clk-periph-gate.c | 179 ++++++++ drivers/clk/tegra/clk-periph.c | 180 ++++++++ drivers/clk/tegra/clk-pll-out.c | 123 ++++++ drivers/clk/tegra/clk-pll.c | 648 ++++++++++++++++++++++++++++ drivers/clk/tegra/clk-super.c | 154 +++++++ drivers/clk/tegra/clk.c | 69 +++ drivers/clk/tegra/clk.h | 490 +++++++++++++++++++++ 11 files changed, 2126 insertions(+) create mode 100644 drivers/clk/tegra/Makefile create mode 100644 drivers/clk/tegra/clk-audio-sync.c create mode 100644 drivers/clk/tegra/clk-divider.c create mode 100644 drivers/clk/tegra/clk-periph-gate.c create mode 100644 drivers/clk/tegra/clk-periph.c create mode 100644 drivers/clk/tegra/clk-pll-out.c create mode 100644 drivers/clk/tegra/clk-pll.c create mode 100644 drivers/clk/tegra/clk-super.c create mode 100644 drivers/clk/tegra/clk.c create mode 100644 drivers/clk/tegra/clk.h diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ee90e87e7675..f0b269a2058d 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o +obj-$(CONFIG_ARCH_TEGRA) += tegra/ # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile new file mode 100644 index 000000000000..68bd353a2108 --- /dev/null +++ b/drivers/clk/tegra/Makefile @@ -0,0 +1,8 @@ +obj-y += clk.o +obj-y += clk-audio-sync.o +obj-y += clk-divider.o +obj-y += clk-periph.o +obj-y += clk-periph-gate.o +obj-y += clk-pll.o +obj-y += clk-pll-out.o +obj-y += clk-super.o diff --git a/drivers/clk/tegra/clk-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c new file mode 100644 index 000000000000..c0f7843e80e6 --- /dev/null +++ b/drivers/clk/tegra/clk-audio-sync.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "clk.h" + +static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); + + return sync->rate; +} + +static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); + + if (rate > sync->max_rate) + return -EINVAL; + else + return rate; +} + +static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); + + sync->rate = rate; + return 0; +} + +const struct clk_ops tegra_clk_sync_source_ops = { + .round_rate = clk_sync_source_round_rate, + .set_rate = clk_sync_source_set_rate, + .recalc_rate = clk_sync_source_recalc_rate, +}; + +struct clk *tegra_clk_register_sync_source(const char *name, + unsigned long rate, unsigned long max_rate) +{ + struct tegra_clk_sync_source *sync; + struct clk_init_data init; + struct clk *clk; + + sync = kzalloc(sizeof(*sync), GFP_KERNEL); + if (!sync) { + pr_err("%s: could not allocate sync source clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + sync->rate = rate; + sync->max_rate = max_rate; + + init.ops = &tegra_clk_sync_source_ops; + init.name = name; + init.flags = CLK_IS_ROOT; + init.parent_names = NULL; + init.num_parents = 0; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + sync->hw.init = &init; + + clk = clk_register(NULL, &sync->hw); + if (IS_ERR(clk)) + kfree(sync); + + return clk; +} diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c new file mode 100644 index 000000000000..4d75b1f37e3a --- /dev/null +++ b/drivers/clk/tegra/clk-divider.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define pll_out_override(p) (BIT((p->shift - 6))) +#define div_mask(d) ((1 << (d->width)) - 1) +#define get_mul(d) (1 << d->frac_width) +#define get_max_div(d) div_mask(d) + +#define PERIPH_CLK_UART_DIV_ENB BIT(24) + +static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate, + unsigned long parent_rate) +{ + s64 divider_ux1 = parent_rate; + u8 flags = divider->flags; + int mul; + + if (!rate) + return 0; + + mul = get_mul(divider); + + if (!(flags & TEGRA_DIVIDER_INT)) + divider_ux1 *= mul; + + if (flags & TEGRA_DIVIDER_ROUND_UP) + divider_ux1 += rate - 1; + + do_div(divider_ux1, rate); + + if (flags & TEGRA_DIVIDER_INT) + divider_ux1 *= mul; + + divider_ux1 -= mul; + + if (divider_ux1 < 0) + return 0; + + if (divider_ux1 > get_max_div(divider)) + return -EINVAL; + + return divider_ux1; +} + +static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); + u32 reg; + int div, mul; + u64 rate = parent_rate; + + reg = readl_relaxed(divider->reg) >> divider->shift; + div = reg & div_mask(divider); + + mul = get_mul(divider); + div += mul; + + rate *= mul; + rate += div - 1; + do_div(rate, div); + + return rate; +} + +static long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); + int div, mul; + unsigned long output_rate = *prate; + + if (!rate) + return output_rate; + + div = get_div(divider, rate, output_rate); + if (div < 0) + return *prate; + + mul = get_mul(divider); + + return DIV_ROUND_UP(output_rate * mul, div + mul); +} + +static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); + int div; + unsigned long flags = 0; + u32 val; + + div = get_div(divider, rate, parent_rate); + if (div < 0) + return div; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + + val = readl_relaxed(divider->reg); + val &= ~(div_mask(divider) << divider->shift); + val |= div << divider->shift; + + if (divider->flags & TEGRA_DIVIDER_UART) { + if (div) + val |= PERIPH_CLK_UART_DIV_ENB; + else + val &= ~PERIPH_CLK_UART_DIV_ENB; + } + + if (divider->flags & TEGRA_DIVIDER_FIXED) + val |= pll_out_override(divider); + + writel_relaxed(val, divider->reg); + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} + +const struct clk_ops tegra_clk_frac_div_ops = { + .recalc_rate = clk_frac_div_recalc_rate, + .set_rate = clk_frac_div_set_rate, + .round_rate = clk_frac_div_round_rate, +}; + +struct clk *tegra_clk_register_divider(const char *name, + const char *parent_name, void __iomem *reg, + unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, + u8 frac_width, spinlock_t *lock) +{ + struct tegra_clk_frac_div *divider; + struct clk *clk; + struct clk_init_data init; + + divider = kzalloc(sizeof(*divider), GFP_KERNEL); + if (!divider) { + pr_err("%s: could not allocate fractional divider clk\n", + __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &tegra_clk_frac_div_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + divider->reg = reg; + divider->shift = shift; + divider->width = width; + divider->frac_width = frac_width; + divider->lock = lock; + divider->flags = clk_divider_flags; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + divider->hw.init = &init; + + clk = clk_register(NULL, ÷r->hw); + if (IS_ERR(clk)) + kfree(divider); + + return clk; +} diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c new file mode 100644 index 000000000000..6dd533251e7b --- /dev/null +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static DEFINE_SPINLOCK(periph_ref_lock); + +/* Macros to assist peripheral gate clock */ +#define read_enb(gate) \ + readl_relaxed(gate->clk_base + (gate->regs->enb_reg)) +#define write_enb_set(val, gate) \ + writel_relaxed(val, gate->clk_base + (gate->regs->enb_set_reg)) +#define write_enb_clr(val, gate) \ + writel_relaxed(val, gate->clk_base + (gate->regs->enb_clr_reg)) + +#define read_rst(gate) \ + readl_relaxed(gate->clk_base + (gate->regs->rst_reg)) +#define write_rst_set(val, gate) \ + writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg)) +#define write_rst_clr(val, gate) \ + writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg)) + +#define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32)) + +/* Peripheral gate clock ops */ +static int clk_periph_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); + int state = 1; + + if (!(read_enb(gate) & periph_clk_to_bit(gate))) + state = 0; + + if (!(gate->flags & TEGRA_PERIPH_NO_RESET)) + if (read_rst(gate) & periph_clk_to_bit(gate)) + state = 0; + + return state; +} + +static int clk_periph_enable(struct clk_hw *hw) +{ + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); + unsigned long flags = 0; + + spin_lock_irqsave(&periph_ref_lock, flags); + + gate->enable_refcnt[gate->clk_num]++; + if (gate->enable_refcnt[gate->clk_num] > 1) { + spin_unlock_irqrestore(&periph_ref_lock, flags); + return 0; + } + + write_enb_set(periph_clk_to_bit(gate), gate); + udelay(2); + + if (!(gate->flags & TEGRA_PERIPH_NO_RESET) && + !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) { + if (read_rst(gate) & periph_clk_to_bit(gate)) { + udelay(5); /* reset propogation delay */ + write_rst_clr(periph_clk_to_bit(gate), gate); + } + } + + spin_unlock_irqrestore(&periph_ref_lock, flags); + + return 0; +} + +static void clk_periph_disable(struct clk_hw *hw) +{ + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); + unsigned long flags = 0; + + spin_lock_irqsave(&periph_ref_lock, flags); + + gate->enable_refcnt[gate->clk_num]--; + if (gate->enable_refcnt[gate->clk_num] > 0) { + spin_unlock_irqrestore(&periph_ref_lock, flags); + return; + } + + /* + * If peripheral is in the APB bus then read the APB bus to + * flush the write operation in apb bus. This will avoid the + * peripheral access after disabling clock + */ + if (gate->flags & TEGRA_PERIPH_ON_APB) + tegra_read_chipid(); + + write_enb_clr(periph_clk_to_bit(gate), gate); + + spin_unlock_irqrestore(&periph_ref_lock, flags); +} + +void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert) +{ + if (gate->flags & TEGRA_PERIPH_NO_RESET) + return; + + if (assert) { + /* + * If peripheral is in the APB bus then read the APB bus to + * flush the write operation in apb bus. This will avoid the + * peripheral access after disabling clock + */ + if (gate->flags & TEGRA_PERIPH_ON_APB) + tegra_read_chipid(); + + write_rst_set(periph_clk_to_bit(gate), gate); + } else { + write_rst_clr(periph_clk_to_bit(gate), gate); + } +} + +const struct clk_ops tegra_clk_periph_gate_ops = { + .is_enabled = clk_periph_is_enabled, + .enable = clk_periph_enable, + .disable = clk_periph_disable, +}; + +struct clk *tegra_clk_register_periph_gate(const char *name, + const char *parent_name, u8 gate_flags, void __iomem *clk_base, + unsigned long flags, int clk_num, + struct tegra_clk_periph_regs *pregs, int *enable_refcnt) +{ + struct tegra_clk_periph_gate *gate; + struct clk *clk; + struct clk_init_data init; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + pr_err("%s: could not allocate periph gate clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + init.ops = &tegra_clk_periph_gate_ops; + + gate->magic = TEGRA_CLK_PERIPH_GATE_MAGIC; + gate->clk_base = clk_base; + gate->clk_num = clk_num; + gate->flags = gate_flags; + gate->enable_refcnt = enable_refcnt; + gate->regs = pregs; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + gate->hw.init = &init; + + clk = clk_register(NULL, &gate->hw); + if (IS_ERR(clk)) + kfree(gate); + + return clk; +} diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c new file mode 100644 index 000000000000..5978e81b175b --- /dev/null +++ b/drivers/clk/tegra/clk-periph.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "clk.h" + +static u8 clk_periph_get_parent(struct clk_hw *hw) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *mux_ops = periph->mux_ops; + struct clk_hw *mux_hw = &periph->mux.hw; + + mux_hw->clk = hw->clk; + + return mux_ops->get_parent(mux_hw); +} + +static int clk_periph_set_parent(struct clk_hw *hw, u8 index) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *mux_ops = periph->mux_ops; + struct clk_hw *mux_hw = &periph->mux.hw; + + mux_hw->clk = hw->clk; + + return mux_ops->set_parent(mux_hw, index); +} + +static unsigned long clk_periph_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *div_ops = periph->div_ops; + struct clk_hw *div_hw = &periph->divider.hw; + + div_hw->clk = hw->clk; + + return div_ops->recalc_rate(div_hw, parent_rate); +} + +static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *div_ops = periph->div_ops; + struct clk_hw *div_hw = &periph->divider.hw; + + div_hw->clk = hw->clk; + + return div_ops->round_rate(div_hw, rate, prate); +} + +static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *div_ops = periph->div_ops; + struct clk_hw *div_hw = &periph->divider.hw; + + div_hw->clk = hw->clk; + + return div_ops->set_rate(div_hw, rate, parent_rate); +} + +static int clk_periph_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *gate_ops = periph->gate_ops; + struct clk_hw *gate_hw = &periph->gate.hw; + + gate_hw->clk = hw->clk; + + return gate_ops->is_enabled(gate_hw); +} + +static int clk_periph_enable(struct clk_hw *hw) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *gate_ops = periph->gate_ops; + struct clk_hw *gate_hw = &periph->gate.hw; + + gate_hw->clk = hw->clk; + + return gate_ops->enable(gate_hw); +} + +static void clk_periph_disable(struct clk_hw *hw) +{ + struct tegra_clk_periph *periph = to_clk_periph(hw); + const struct clk_ops *gate_ops = periph->gate_ops; + struct clk_hw *gate_hw = &periph->gate.hw; + + gate_ops->disable(gate_hw); +} + +const struct clk_ops tegra_clk_periph_ops = { + .get_parent = clk_periph_get_parent, + .set_parent = clk_periph_set_parent, + .recalc_rate = clk_periph_recalc_rate, + .round_rate = clk_periph_round_rate, + .set_rate = clk_periph_set_rate, + .is_enabled = clk_periph_is_enabled, + .enable = clk_periph_enable, + .disable = clk_periph_disable, +}; + +const struct clk_ops tegra_clk_periph_nodiv_ops = { + .get_parent = clk_periph_get_parent, + .set_parent = clk_periph_set_parent, + .is_enabled = clk_periph_is_enabled, + .enable = clk_periph_enable, + .disable = clk_periph_disable, +}; + +static struct clk *_tegra_clk_register_periph(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, + void __iomem *clk_base, u32 offset, bool div) +{ + struct clk *clk; + struct clk_init_data init; + + init.name = name; + init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops; + init.flags = div ? 0 : CLK_SET_RATE_PARENT; + init.parent_names = parent_names; + init.num_parents = num_parents; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + periph->hw.init = &init; + periph->magic = TEGRA_CLK_PERIPH_MAGIC; + periph->mux.reg = clk_base + offset; + periph->divider.reg = div ? (clk_base + offset) : NULL; + periph->gate.clk_base = clk_base; + + clk = clk_register(NULL, &periph->hw); + if (IS_ERR(clk)) + return clk; + + periph->mux.hw.clk = clk; + periph->divider.hw.clk = div ? clk : NULL; + periph->gate.hw.clk = clk; + + return clk; +} + +struct clk *tegra_clk_register_periph(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, void __iomem *clk_base, + u32 offset) +{ + return _tegra_clk_register_periph(name, parent_names, num_parents, + periph, clk_base, offset, true); +} + +struct clk *tegra_clk_register_periph_nodiv(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, void __iomem *clk_base, + u32 offset) +{ + return _tegra_clk_register_periph(name, parent_names, num_parents, + periph, clk_base, offset, false); +} diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c new file mode 100644 index 000000000000..3598987a451d --- /dev/null +++ b/drivers/clk/tegra/clk-pll-out.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define pll_out_enb(p) (BIT(p->enb_bit_idx)) +#define pll_out_rst(p) (BIT(p->rst_bit_idx)) + +static int clk_pll_out_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); + u32 val = readl_relaxed(pll_out->reg); + int state; + + state = (val & pll_out_enb(pll_out)) ? 1 : 0; + if (!(val & (pll_out_rst(pll_out)))) + state = 0; + return state; +} + +static int clk_pll_out_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); + unsigned long flags = 0; + u32 val; + + if (pll_out->lock) + spin_lock_irqsave(pll_out->lock, flags); + + val = readl_relaxed(pll_out->reg); + + val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out)); + + writel_relaxed(val, pll_out->reg); + udelay(2); + + if (pll_out->lock) + spin_unlock_irqrestore(pll_out->lock, flags); + + return 0; +} + +static void clk_pll_out_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); + unsigned long flags = 0; + u32 val; + + if (pll_out->lock) + spin_lock_irqsave(pll_out->lock, flags); + + val = readl_relaxed(pll_out->reg); + + val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out)); + + writel_relaxed(val, pll_out->reg); + udelay(2); + + if (pll_out->lock) + spin_unlock_irqrestore(pll_out->lock, flags); +} + +const struct clk_ops tegra_clk_pll_out_ops = { + .is_enabled = clk_pll_out_is_enabled, + .enable = clk_pll_out_enable, + .disable = clk_pll_out_disable, +}; + +struct clk *tegra_clk_register_pll_out(const char *name, + const char *parent_name, void __iomem *reg, u8 enb_bit_idx, + u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags, + spinlock_t *lock) +{ + struct tegra_clk_pll_out *pll_out; + struct clk *clk; + struct clk_init_data init; + + pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL); + if (!pll_out) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &tegra_clk_pll_out_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + init.flags = flags; + + pll_out->reg = reg; + pll_out->enb_bit_idx = enb_bit_idx; + pll_out->rst_bit_idx = rst_bit_idx; + pll_out->flags = pll_out_flags; + pll_out->lock = lock; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + pll_out->hw.init = &init; + + clk = clk_register(NULL, &pll_out->hw); + if (IS_ERR(clk)) + kfree(pll_out); + + return clk; +} diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c new file mode 100644 index 000000000000..165f24734c1b --- /dev/null +++ b/drivers/clk/tegra/clk-pll.c @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_BASE_BYPASS BIT(31) +#define PLL_BASE_ENABLE BIT(30) +#define PLL_BASE_REF_ENABLE BIT(29) +#define PLL_BASE_OVERRIDE BIT(28) + +#define PLL_BASE_DIVP_SHIFT 20 +#define PLL_BASE_DIVP_WIDTH 3 +#define PLL_BASE_DIVN_SHIFT 8 +#define PLL_BASE_DIVN_WIDTH 10 +#define PLL_BASE_DIVM_SHIFT 0 +#define PLL_BASE_DIVM_WIDTH 5 +#define PLLU_POST_DIVP_MASK 0x1 + +#define PLL_MISC_DCCON_SHIFT 20 +#define PLL_MISC_CPCON_SHIFT 8 +#define PLL_MISC_CPCON_WIDTH 4 +#define PLL_MISC_CPCON_MASK ((1 << PLL_MISC_CPCON_WIDTH) - 1) +#define PLL_MISC_LFCON_SHIFT 4 +#define PLL_MISC_LFCON_WIDTH 4 +#define PLL_MISC_LFCON_MASK ((1 << PLL_MISC_LFCON_WIDTH) - 1) +#define PLL_MISC_VCOCON_SHIFT 0 +#define PLL_MISC_VCOCON_WIDTH 4 +#define PLL_MISC_VCOCON_MASK ((1 << PLL_MISC_VCOCON_WIDTH) - 1) + +#define OUT_OF_TABLE_CPCON 8 + +#define PMC_PLLP_WB0_OVERRIDE 0xf8 +#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12) +#define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11) + +#define PLL_POST_LOCK_DELAY 50 + +#define PLLDU_LFCON_SET_DIVN 600 + +#define PLLE_BASE_DIVCML_SHIFT 24 +#define PLLE_BASE_DIVCML_WIDTH 4 +#define PLLE_BASE_DIVP_SHIFT 16 +#define PLLE_BASE_DIVP_WIDTH 7 +#define PLLE_BASE_DIVN_SHIFT 8 +#define PLLE_BASE_DIVN_WIDTH 8 +#define PLLE_BASE_DIVM_SHIFT 0 +#define PLLE_BASE_DIVM_WIDTH 8 + +#define PLLE_MISC_SETUP_BASE_SHIFT 16 +#define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT) +#define PLLE_MISC_LOCK_ENABLE BIT(9) +#define PLLE_MISC_READY BIT(15) +#define PLLE_MISC_SETUP_EX_SHIFT 2 +#define PLLE_MISC_SETUP_EX_MASK (3 << PLLE_MISC_SETUP_EX_SHIFT) +#define PLLE_MISC_SETUP_MASK (PLLE_MISC_SETUP_BASE_MASK | \ + PLLE_MISC_SETUP_EX_MASK) +#define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT) + +#define PLLE_SS_CTRL 0x68 +#define PLLE_SS_DISABLE (7 << 10) + +#define PMC_SATA_PWRGT 0x1ac +#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) +#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) + +#define pll_readl(offset, p) readl_relaxed(p->clk_base + offset) +#define pll_readl_base(p) pll_readl(p->params->base_reg, p) +#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) + +#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset) +#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p) +#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p) + +#define mask(w) ((1 << (w)) - 1) +#define divm_mask(p) mask(p->divm_width) +#define divn_mask(p) mask(p->divn_width) +#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \ + mask(p->divp_width)) + +#define divm_max(p) (divm_mask(p)) +#define divn_max(p) (divn_mask(p)) +#define divp_max(p) (1 << (divp_mask(p))) + +static void clk_pll_enable_lock(struct tegra_clk_pll *pll) +{ + u32 val; + + if (!(pll->flags & TEGRA_PLL_USE_LOCK)) + return; + + val = pll_readl_misc(pll); + val |= BIT(pll->params->lock_enable_bit_idx); + pll_writel_misc(val, pll); +} + +static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll, + void __iomem *lock_addr, u32 lock_bit_idx) +{ + int i; + u32 val; + + if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { + udelay(pll->params->lock_delay); + return 0; + } + + for (i = 0; i < pll->params->lock_delay; i++) { + val = readl_relaxed(lock_addr); + if (val & BIT(lock_bit_idx)) { + udelay(PLL_POST_LOCK_DELAY); + return 0; + } + udelay(2); /* timeout = 2 * lock time */ + } + + pr_err("%s: Timed out waiting for pll %s lock\n", __func__, + __clk_get_name(pll->hw.clk)); + + return -1; +} + +static int clk_pll_is_enabled(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + if (pll->flags & TEGRA_PLLM) { + val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); + if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) + return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0; + } + + val = pll_readl_base(pll); + + return val & PLL_BASE_ENABLE ? 1 : 0; +} + +static int _clk_pll_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + clk_pll_enable_lock(pll); + + val = pll_readl_base(pll); + val &= ~PLL_BASE_BYPASS; + val |= PLL_BASE_ENABLE; + pll_writel_base(val, pll); + + if (pll->flags & TEGRA_PLLM) { + val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); + val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; + writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); + } + + clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg, + pll->params->lock_bit_idx); + + return 0; +} + +static void _clk_pll_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + val = pll_readl_base(pll); + val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); + pll_writel_base(val, pll); + + if (pll->flags & TEGRA_PLLM) { + val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); + val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; + writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); + } +} + +static int clk_pll_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + int ret; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + ret = _clk_pll_enable(hw); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static void clk_pll_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pll_disable(hw); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} + +static int _get_table_rate(struct clk_hw *hw, + struct tegra_clk_pll_freq_table *cfg, + unsigned long rate, unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct tegra_clk_pll_freq_table *sel; + + for (sel = pll->freq_table; sel->input_rate != 0; sel++) + if (sel->input_rate == parent_rate && + sel->output_rate == rate) + break; + + if (sel->input_rate == 0) + return -EINVAL; + + BUG_ON(sel->p < 1); + + cfg->input_rate = sel->input_rate; + cfg->output_rate = sel->output_rate; + cfg->m = sel->m; + cfg->n = sel->n; + cfg->p = sel->p; + cfg->cpcon = sel->cpcon; + + return 0; +} + +static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, + unsigned long rate, unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long cfreq; + u32 p_div = 0; + + switch (parent_rate) { + case 12000000: + case 26000000: + cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; + break; + case 13000000: + cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; + break; + case 16800000: + case 19200000: + cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; + break; + case 9600000: + case 28800000: + /* + * PLL_P_OUT1 rate is not listed in PLLA table + */ + cfreq = parent_rate/(parent_rate/1000000); + break; + default: + pr_err("%s Unexpected reference rate %lu\n", + __func__, parent_rate); + BUG(); + } + + /* Raise VCO to guarantee 0.5% accuracy */ + for (cfg->output_rate = rate; cfg->output_rate < 200 * cfreq; + cfg->output_rate <<= 1) + p_div++; + + cfg->p = 1 << p_div; + cfg->m = parent_rate / cfreq; + cfg->n = cfg->output_rate / cfreq; + cfg->cpcon = OUT_OF_TABLE_CPCON; + + if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) || + cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) { + pr_err("%s: Failed to set %s rate %lu\n", + __func__, __clk_get_name(hw->clk), rate); + return -EINVAL; + } + + return 0; +} + +static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, + unsigned long rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + u32 divp, val, old_base; + int state; + + divp = __ffs(cfg->p); + + if (pll->flags & TEGRA_PLLU) + divp ^= 1; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + old_base = val = pll_readl_base(pll); + val &= ~((divm_mask(pll) << pll->divm_shift) | + (divn_mask(pll) << pll->divn_shift) | + (divp_mask(pll) << pll->divp_shift)); + val |= ((cfg->m << pll->divm_shift) | + (cfg->n << pll->divn_shift) | + (divp << pll->divp_shift)); + if (val == old_base) { + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + return 0; + } + + state = clk_pll_is_enabled(hw); + + if (state) { + _clk_pll_disable(hw); + val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); + } + pll_writel_base(val, pll); + + if (pll->flags & TEGRA_PLL_HAS_CPCON) { + val = pll_readl_misc(pll); + val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT); + val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT; + if (pll->flags & TEGRA_PLL_SET_LFCON) { + val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT); + if (cfg->n >= PLLDU_LFCON_SET_DIVN) + val |= 0x1 << PLL_MISC_LFCON_SHIFT; + } else if (pll->flags & TEGRA_PLL_SET_DCCON) { + val &= ~(0x1 << PLL_MISC_DCCON_SHIFT); + if (rate >= (pll->params->vco_max >> 1)) + val |= 0x1 << PLL_MISC_DCCON_SHIFT; + } + pll_writel_misc(val, pll); + } + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + if (state) + clk_pll_enable(hw); + + return 0; +} + +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct tegra_clk_pll_freq_table cfg; + + if (pll->flags & TEGRA_PLL_FIXED) { + if (rate != pll->fixed_rate) { + pr_err("%s: Can not change %s fixed rate %lu to %lu\n", + __func__, __clk_get_name(hw->clk), + pll->fixed_rate, rate); + return -EINVAL; + } + return 0; + } + + if (_get_table_rate(hw, &cfg, rate, parent_rate) && + _calc_rate(hw, &cfg, rate, parent_rate)) + return -EINVAL; + + return _program_pll(hw, &cfg, rate); +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct tegra_clk_pll_freq_table cfg; + u64 output_rate = *prate; + + if (pll->flags & TEGRA_PLL_FIXED) + return pll->fixed_rate; + + /* PLLM is used for memory; we do not change rate */ + if (pll->flags & TEGRA_PLLM) + return __clk_get_rate(hw->clk); + + if (_get_table_rate(hw, &cfg, rate, *prate) && + _calc_rate(hw, &cfg, rate, *prate)) + return -EINVAL; + + output_rate *= cfg.n; + do_div(output_rate, cfg.m * cfg.p); + + return output_rate; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val = pll_readl_base(pll); + u32 divn = 0, divm = 0, divp = 0; + u64 rate = parent_rate; + + if (val & PLL_BASE_BYPASS) + return parent_rate; + + if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) { + struct tegra_clk_pll_freq_table sel; + if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) { + pr_err("Clock %s has unknown fixed frequency\n", + __clk_get_name(hw->clk)); + BUG(); + } + return pll->fixed_rate; + } + + divp = (val >> pll->divp_shift) & (divp_mask(pll)); + if (pll->flags & TEGRA_PLLU) + divp ^= 1; + + divn = (val >> pll->divn_shift) & (divn_mask(pll)); + divm = (val >> pll->divm_shift) & (divm_mask(pll)); + divm *= (1 << divp); + + rate *= divn; + do_div(rate, divm); + return rate; +} + +static int clk_plle_training(struct tegra_clk_pll *pll) +{ + u32 val; + unsigned long timeout; + + if (!pll->pmc) + return -ENOSYS; + + /* + * PLLE is already disabled, and setup cleared; + * create falling edge on PLLE IDDQ input. + */ + val = readl(pll->pmc + PMC_SATA_PWRGT); + val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; + writel(val, pll->pmc + PMC_SATA_PWRGT); + + val = readl(pll->pmc + PMC_SATA_PWRGT); + val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; + writel(val, pll->pmc + PMC_SATA_PWRGT); + + val = readl(pll->pmc + PMC_SATA_PWRGT); + val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; + writel(val, pll->pmc + PMC_SATA_PWRGT); + + val = pll_readl_misc(pll); + + timeout = jiffies + msecs_to_jiffies(100); + while (1) { + val = pll_readl_misc(pll); + if (val & PLLE_MISC_READY) + break; + if (time_after(jiffies, timeout)) { + pr_err("%s: timeout waiting for PLLE\n", __func__); + return -EBUSY; + } + udelay(300); + } + + return 0; +} + +static int clk_plle_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); + struct tegra_clk_pll_freq_table sel; + u32 val; + int err; + + if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + return -EINVAL; + + clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); + pll_writel_misc(val, pll); + + val = pll_readl_misc(pll); + if (!(val & PLLE_MISC_READY)) { + err = clk_plle_training(pll); + if (err) + return err; + } + + if (pll->flags & TEGRA_PLLE_CONFIGURE) { + /* configure dividers */ + val = pll_readl_base(pll); + val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); + val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); + val |= sel.m << pll->divm_shift; + val |= sel.n << pll->divn_shift; + val |= sel.p << pll->divp_shift; + val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; + pll_writel_base(val, pll); + } + + val = pll_readl_misc(pll); + val |= PLLE_MISC_SETUP_VALUE; + val |= PLLE_MISC_LOCK_ENABLE; + pll_writel_misc(val, pll); + + val = readl(pll->clk_base + PLLE_SS_CTRL); + val |= PLLE_SS_DISABLE; + writel(val, pll->clk_base + PLLE_SS_CTRL); + + val |= pll_readl_base(pll); + val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); + pll_writel_base(val, pll); + + clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg, + pll->params->lock_bit_idx); + return 0; +} + +static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val = pll_readl_base(pll); + u32 divn = 0, divm = 0, divp = 0; + u64 rate = parent_rate; + + divp = (val >> pll->divp_shift) & (divp_mask(pll)); + divn = (val >> pll->divn_shift) & (divn_mask(pll)); + divm = (val >> pll->divm_shift) & (divm_mask(pll)); + divm *= divp; + + rate *= divn; + do_div(rate, divm); + return rate; +} + +const struct clk_ops tegra_clk_pll_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_enable, + .disable = clk_pll_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, +}; + +const struct clk_ops tegra_clk_plle_ops = { + .recalc_rate = clk_plle_recalc_rate, + .is_enabled = clk_pll_is_enabled, + .disable = clk_pll_disable, + .enable = clk_plle_enable, +}; + +static struct clk *_tegra_clk_register_pll(const char *name, + const char *parent_name, void __iomem *clk_base, + void __iomem *pmc, unsigned long flags, + unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock, + const struct clk_ops *ops) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + pll->clk_base = clk_base; + pll->pmc = pmc; + + pll->freq_table = freq_table; + pll->params = pll_params; + pll->fixed_rate = fixed_rate; + pll->flags = pll_flags; + pll->lock = lock; + + pll->divp_shift = PLL_BASE_DIVP_SHIFT; + pll->divp_width = PLL_BASE_DIVP_WIDTH; + pll->divn_shift = PLL_BASE_DIVN_SHIFT; + pll->divn_width = PLL_BASE_DIVN_WIDTH; + pll->divm_shift = PLL_BASE_DIVM_SHIFT; + pll->divm_width = PLL_BASE_DIVM_WIDTH; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) +{ + return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, + flags, fixed_rate, pll_params, pll_flags, freq_table, + lock, &tegra_clk_pll_ops); +} + +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) +{ + return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, + flags, fixed_rate, pll_params, pll_flags, freq_table, + lock, &tegra_clk_plle_ops); +} diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c new file mode 100644 index 000000000000..7ad48a832334 --- /dev/null +++ b/drivers/clk/tegra/clk-super.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define SUPER_STATE_IDLE 0 +#define SUPER_STATE_RUN 1 +#define SUPER_STATE_IRQ 2 +#define SUPER_STATE_FIQ 3 + +#define SUPER_STATE_SHIFT 28 +#define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \ + BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \ + << SUPER_STATE_SHIFT) + +#define SUPER_LP_DIV2_BYPASS (1 << 16) + +#define super_state(s) (BIT(s) << SUPER_STATE_SHIFT) +#define super_state_to_src_shift(m, s) ((m->width * s)) +#define super_state_to_src_mask(m) (((1 << m->width) - 1)) + +static u8 clk_super_get_parent(struct clk_hw *hw) +{ + struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); + u32 val, state; + u8 source, shift; + + val = readl_relaxed(mux->reg); + + state = val & SUPER_STATE_MASK; + + BUG_ON((state != super_state(SUPER_STATE_RUN)) && + (state != super_state(SUPER_STATE_IDLE))); + shift = (state == super_state(SUPER_STATE_IDLE)) ? + super_state_to_src_shift(mux, SUPER_STATE_IDLE) : + super_state_to_src_shift(mux, SUPER_STATE_RUN); + + source = (val >> shift) & super_state_to_src_mask(mux); + + /* + * If LP_DIV2_BYPASS is not set and PLLX is current parent then + * PLLX/2 is the input source to CCLKLP. + */ + if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) && + (source == mux->pllx_index)) + source = mux->div2_index; + + return source; +} + +static int clk_super_set_parent(struct clk_hw *hw, u8 index) +{ + struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); + u32 val, state; + u8 parent_index, shift; + + val = readl_relaxed(mux->reg); + state = val & SUPER_STATE_MASK; + BUG_ON((state != super_state(SUPER_STATE_RUN)) && + (state != super_state(SUPER_STATE_IDLE))); + shift = (state == super_state(SUPER_STATE_IDLE)) ? + super_state_to_src_shift(mux, SUPER_STATE_IDLE) : + super_state_to_src_shift(mux, SUPER_STATE_RUN); + + /* + * For LP mode super-clock switch between PLLX direct + * and divided-by-2 outputs is allowed only when other + * than PLLX clock source is current parent. + */ + if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) || + (index == mux->pllx_index))) { + parent_index = clk_super_get_parent(hw); + if ((parent_index == mux->div2_index) || + (parent_index == mux->pllx_index)) + return -EINVAL; + + val ^= SUPER_LP_DIV2_BYPASS; + writel_relaxed(val, mux->reg); + udelay(2); + + if (index == mux->div2_index) + index = mux->pllx_index; + } + val &= ~((super_state_to_src_mask(mux)) << shift); + val |= (index & (super_state_to_src_mask(mux))) << shift; + + writel_relaxed(val, mux->reg); + udelay(2); + return 0; +} + +const struct clk_ops tegra_clk_super_ops = { + .get_parent = clk_super_get_parent, + .set_parent = clk_super_set_parent, +}; + +struct clk *tegra_clk_register_super_mux(const char *name, + const char **parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, u8 clk_super_flags, + u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock) +{ + struct tegra_clk_super_mux *super; + struct clk *clk; + struct clk_init_data init; + + super = kzalloc(sizeof(*super), GFP_KERNEL); + if (!super) { + pr_err("%s: could not allocate super clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &tegra_clk_super_ops; + init.flags = flags; + init.parent_names = parent_names; + init.num_parents = num_parents; + + super->reg = reg; + super->pllx_index = pllx_index; + super->div2_index = div2_index; + super->lock = lock; + super->width = width; + super->flags = clk_super_flags; + + /* Data in .init is copied by clk_register(), so stack variable OK */ + super->hw.init = &init; + + clk = clk_register(NULL, &super->hw); + if (IS_ERR(clk)) + kfree(super); + + return clk; +} diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c new file mode 100644 index 000000000000..cf023a937208 --- /dev/null +++ b/drivers/clk/tegra/clk.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "clk.h" + +void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, + struct clk *clks[], int clk_max) +{ + struct clk *clk; + + for (; dup_list->clk_id < clk_max; dup_list++) { + clk = clks[dup_list->clk_id]; + dup_list->lookup.clk = clk; + clkdev_add(&dup_list->lookup); + } +} + +void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, + struct clk *clks[], int clk_max) +{ + struct clk *clk; + + for (; tbl->clk_id < clk_max; tbl++) { + clk = clks[tbl->clk_id]; + if (IS_ERR_OR_NULL(clk)) + return; + + if (tbl->parent_id < clk_max) { + struct clk *parent = clks[tbl->parent_id]; + if (clk_set_parent(clk, parent)) { + pr_err("%s: Failed to set parent %s of %s\n", + __func__, __clk_get_name(parent), + __clk_get_name(clk)); + WARN_ON(1); + } + } + + if (tbl->rate) + if (clk_set_rate(clk, tbl->rate)) { + pr_err("%s: Failed to set rate %lu of %s\n", + __func__, tbl->rate, + __clk_get_name(clk)); + WARN_ON(1); + } + + if (tbl->state) + if (clk_prepare_enable(clk)) { + pr_err("%s: Failed to enable %s\n", __func__, + __clk_get_name(clk)); + WARN_ON(1); + } + } +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h new file mode 100644 index 000000000000..5fcfa51d6b17 --- /dev/null +++ b/drivers/clk/tegra/clk.h @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TEGRA_CLK_H +#define __TEGRA_CLK_H + +#include +#include + +/** + * struct tegra_clk_sync_source - external clock source from codec + * + * @hw: handle between common and hardware-specific interfaces + * @rate: input frequency from source + * @max_rate: max rate allowed + */ +struct tegra_clk_sync_source { + struct clk_hw hw; + unsigned long rate; + unsigned long max_rate; +}; + +#define to_clk_sync_source(_hw) \ + container_of(_hw, struct tegra_clk_sync_source, hw) + +extern const struct clk_ops tegra_clk_sync_source_ops; +struct clk *tegra_clk_register_sync_source(const char *name, + unsigned long fixed_rate, unsigned long max_rate); + +/** + * struct tegra_clk_frac_div - fractional divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing divider + * @flags: hardware-specific flags + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @frac_width: width of the fractional bit field + * @lock: register lock + * + * Flags: + * TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value. + * TEGRA_DIVIDER_FIXED - Fixed rate PLL dividers has addition override bit, this + * flag indicates that this divider is for fixed rate PLL. + * TEGRA_DIVIDER_INT - Some modules can not cope with the duty cycle when + * fraction bit is set. This flags indicates to calculate divider for which + * fracton bit will be zero. + * TEGRA_DIVIDER_UART - UART module divider has additional enable bit which is + * set when divider value is not 0. This flags indicates that the divider + * is for UART module. + */ +struct tegra_clk_frac_div { + struct clk_hw hw; + void __iomem *reg; + u8 flags; + u8 shift; + u8 width; + u8 frac_width; + spinlock_t *lock; +}; + +#define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw) + +#define TEGRA_DIVIDER_ROUND_UP BIT(0) +#define TEGRA_DIVIDER_FIXED BIT(1) +#define TEGRA_DIVIDER_INT BIT(2) +#define TEGRA_DIVIDER_UART BIT(3) + +extern const struct clk_ops tegra_clk_frac_div_ops; +struct clk *tegra_clk_register_divider(const char *name, + const char *parent_name, void __iomem *reg, + unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, + u8 frac_width, spinlock_t *lock); + +/* + * Tegra PLL: + * + * In general, there are 3 requirements for each PLL + * that SW needs to be comply with. + * (1) Input frequency range (REF). + * (2) Comparison frequency range (CF). CF = REF/DIVM. + * (3) VCO frequency range (VCO). VCO = CF * DIVN. + * + * The final PLL output frequency (FO) = VCO >> DIVP. + */ + +/** + * struct tegra_clk_pll_freq_table - PLL frequecy table + * + * @input_rate: input rate from source + * @output_rate: output rate from PLL for the input rate + * @n: feedback divider + * @m: input divider + * @p: post divider + * @cpcon: charge pump current + */ +struct tegra_clk_pll_freq_table { + unsigned long input_rate; + unsigned long output_rate; + u16 n; + u16 m; + u8 p; + u8 cpcon; +}; + +/** + * struct clk_pll_params - PLL parameters + * + * @input_min: Minimum input frequency + * @input_max: Maximum input frequency + * @cf_min: Minimum comparison frequency + * @cf_max: Maximum comparison frequency + * @vco_min: Minimum VCO frequency + * @vco_max: Maximum VCO frequency + * @base_reg: PLL base reg offset + * @misc_reg: PLL misc reg offset + * @lock_reg: PLL lock reg offset + * @lock_bit_idx: Bit index for PLL lock status + * @lock_enable_bit_idx: Bit index to enable PLL lock + * @lock_delay: Delay in us if PLL lock is not used + */ +struct tegra_clk_pll_params { + unsigned long input_min; + unsigned long input_max; + unsigned long cf_min; + unsigned long cf_max; + unsigned long vco_min; + unsigned long vco_max; + + u32 base_reg; + u32 misc_reg; + u32 lock_reg; + u32 lock_bit_idx; + u32 lock_enable_bit_idx; + int lock_delay; +}; + +/** + * struct tegra_clk_pll - Tegra PLL clock + * + * @hw: handle between common and hardware-specifix interfaces + * @clk_base: address of CAR controller + * @pmc: address of PMC, required to read override bits + * @freq_table: array of frequencies supported by PLL + * @params: PLL parameters + * @flags: PLL flags + * @fixed_rate: PLL rate if it is fixed + * @lock: register lock + * @divn_shift: shift to the feedback divider bit field + * @divn_width: width of the feedback divider bit field + * @divm_shift: shift to the input divider bit field + * @divm_width: width of the input divider bit field + * @divp_shift: shift to the post divider bit field + * @divp_width: width of the post divider bit field + * + * Flags: + * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for + * PLL locking. If not set it will use lock_delay value to wait. + * TEGRA_PLL_HAS_CPCON - This flag indicates that CPCON value needs + * to be programmed to change output frequency of the PLL. + * TEGRA_PLL_SET_LFCON - This flag indicates that LFCON value needs + * to be programmed to change output frequency of the PLL. + * TEGRA_PLL_SET_DCCON - This flag indicates that DCCON value needs + * to be programmed to change output frequency of the PLL. + * TEGRA_PLLU - PLLU has inverted post divider. This flags indicated + * that it is PLLU and invert post divider value. + * TEGRA_PLLM - PLLM has additional override settings in PMC. This + * flag indicates that it is PLLM and use override settings. + * TEGRA_PLL_FIXED - We are not supposed to change output frequency + * of some plls. + * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling. + */ +struct tegra_clk_pll { + struct clk_hw hw; + void __iomem *clk_base; + void __iomem *pmc; + u8 flags; + unsigned long fixed_rate; + spinlock_t *lock; + u8 divn_shift; + u8 divn_width; + u8 divm_shift; + u8 divm_width; + u8 divp_shift; + u8 divp_width; + struct tegra_clk_pll_freq_table *freq_table; + struct tegra_clk_pll_params *params; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw) + +#define TEGRA_PLL_USE_LOCK BIT(0) +#define TEGRA_PLL_HAS_CPCON BIT(1) +#define TEGRA_PLL_SET_LFCON BIT(2) +#define TEGRA_PLL_SET_DCCON BIT(3) +#define TEGRA_PLLU BIT(4) +#define TEGRA_PLLM BIT(5) +#define TEGRA_PLL_FIXED BIT(6) +#define TEGRA_PLLE_CONFIGURE BIT(7) + +extern const struct clk_ops tegra_clk_pll_ops; +extern const struct clk_ops tegra_clk_plle_ops; +struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, + void __iomem *clk_base, void __iomem *pmc, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); + +/** + * struct tegra_clk_pll_out - PLL divider down clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing the PLL divider + * @enb_bit_idx: bit to enable/disable PLL divider + * @rst_bit_idx: bit to reset PLL divider + * @lock: register lock + * @flags: hardware-specific flags + */ +struct tegra_clk_pll_out { + struct clk_hw hw; + void __iomem *reg; + u8 enb_bit_idx; + u8 rst_bit_idx; + spinlock_t *lock; + u8 flags; +}; + +#define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw) + +extern const struct clk_ops tegra_clk_pll_out_ops; +struct clk *tegra_clk_register_pll_out(const char *name, + const char *parent_name, void __iomem *reg, u8 enb_bit_idx, + u8 rst_bit_idx, unsigned long flags, u8 pll_div_flags, + spinlock_t *lock); + +/** + * struct tegra_clk_periph_regs - Registers controlling peripheral clock + * + * @enb_reg: read the enable status + * @enb_set_reg: write 1 to enable clock + * @enb_clr_reg: write 1 to disable clock + * @rst_reg: read the reset status + * @rst_set_reg: write 1 to assert the reset of peripheral + * @rst_clr_reg: write 1 to deassert the reset of peripheral + */ +struct tegra_clk_periph_regs { + u32 enb_reg; + u32 enb_set_reg; + u32 enb_clr_reg; + u32 rst_reg; + u32 rst_set_reg; + u32 rst_clr_reg; +}; + +/** + * struct tegra_clk_periph_gate - peripheral gate clock + * + * @magic: magic number to validate type + * @hw: handle between common and hardware-specific interfaces + * @clk_base: address of CAR controller + * @regs: Registers to control the peripheral + * @flags: hardware-specific flags + * @clk_num: Clock number + * @enable_refcnt: array to maintain reference count of the clock + * + * Flags: + * TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed + * for this module. + * TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module + * after clock enable and driver for the module is responsible for + * doing reset. + * TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the + * bus to flush the write operation in apb bus. This flag indicates + * that this peripheral is in apb bus. + */ +struct tegra_clk_periph_gate { + u32 magic; + struct clk_hw hw; + void __iomem *clk_base; + u8 flags; + int clk_num; + int *enable_refcnt; + struct tegra_clk_periph_regs *regs; +}; + +#define to_clk_periph_gate(_hw) \ + container_of(_hw, struct tegra_clk_periph_gate, hw) + +#define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309 + +#define TEGRA_PERIPH_NO_RESET BIT(0) +#define TEGRA_PERIPH_MANUAL_RESET BIT(1) +#define TEGRA_PERIPH_ON_APB BIT(2) + +void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert); +extern const struct clk_ops tegra_clk_periph_gate_ops; +struct clk *tegra_clk_register_periph_gate(const char *name, + const char *parent_name, u8 gate_flags, void __iomem *clk_base, + unsigned long flags, int clk_num, + struct tegra_clk_periph_regs *pregs, int *enable_refcnt); + +/** + * struct clk-periph - peripheral clock + * + * @magic: magic number to validate type + * @hw: handle between common and hardware-specific interfaces + * @mux: mux clock + * @divider: divider clock + * @gate: gate clock + * @mux_ops: mux clock ops + * @div_ops: divider clock ops + * @gate_ops: gate clock ops + */ +struct tegra_clk_periph { + u32 magic; + struct clk_hw hw; + struct clk_mux mux; + struct tegra_clk_frac_div divider; + struct tegra_clk_periph_gate gate; + + const struct clk_ops *mux_ops; + const struct clk_ops *div_ops; + const struct clk_ops *gate_ops; +}; + +#define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw) + +#define TEGRA_CLK_PERIPH_MAGIC 0x18221223 + +extern const struct clk_ops tegra_clk_periph_ops; +struct clk *tegra_clk_register_periph(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, void __iomem *clk_base, + u32 offset); +struct clk *tegra_clk_register_periph_nodiv(const char *name, + const char **parent_names, int num_parents, + struct tegra_clk_periph *periph, void __iomem *clk_base, + u32 offset); + +#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \ + _div_shift, _div_width, _div_frac_width, \ + _div_flags, _clk_num, _enb_refcnt, _regs, \ + _gate_flags) \ + { \ + .mux = { \ + .flags = _mux_flags, \ + .shift = _mux_shift, \ + .width = _mux_width, \ + }, \ + .divider = { \ + .flags = _div_flags, \ + .shift = _div_shift, \ + .width = _div_width, \ + .frac_width = _div_frac_width, \ + }, \ + .gate = { \ + .flags = _gate_flags, \ + .clk_num = _clk_num, \ + .enable_refcnt = _enb_refcnt, \ + .regs = _regs, \ + }, \ + .mux_ops = &clk_mux_ops, \ + .div_ops = &tegra_clk_frac_div_ops, \ + .gate_ops = &tegra_clk_periph_gate_ops, \ + } + +struct tegra_periph_init_data { + const char *name; + int clk_id; + const char **parent_names; + int num_parents; + struct tegra_clk_periph periph; + u32 offset; + const char *con_id; + const char *dev_id; +}; + +#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \ + _mux_shift, _mux_width, _mux_flags, _div_shift, \ + _div_width, _div_frac_width, _div_flags, _regs, \ + _clk_num, _enb_refcnt, _gate_flags, _clk_id) \ + { \ + .name = _name, \ + .clk_id = _clk_id, \ + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \ + _mux_flags, _div_shift, \ + _div_width, _div_frac_width, \ + _div_flags, _clk_num, \ + _enb_refcnt, _regs, \ + _gate_flags), \ + .offset = _offset, \ + .con_id = _con_id, \ + .dev_id = _dev_id, \ + } + +/** + * struct clk_super_mux - super clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling multiplexer + * @width: width of the multiplexer bit field + * @flags: hardware-specific flags + * @div2_index: bit controlling divide-by-2 + * @pllx_index: PLLX index in the parent list + * @lock: register lock + * + * Flags: + * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates + * that this is LP cluster clock. + */ +struct tegra_clk_super_mux { + struct clk_hw hw; + void __iomem *reg; + u8 width; + u8 flags; + u8 div2_index; + u8 pllx_index; + spinlock_t *lock; +}; + +#define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw) + +#define TEGRA_DIVIDER_2 BIT(0) + +extern const struct clk_ops tegra_clk_super_ops; +struct clk *tegra_clk_register_super_mux(const char *name, + const char **parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, u8 clk_super_flags, + u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock); + +/** + * struct clk_init_tabel - clock initialization table + * @clk_id: clock id as mentioned in device tree bindings + * @parent_id: parent clock id as mentioned in device tree bindings + * @rate: rate to set + * @state: enable/disable + */ +struct tegra_clk_init_table { + unsigned int clk_id; + unsigned int parent_id; + unsigned long rate; + int state; +}; + +/** + * struct clk_duplicate - duplicate clocks + * @clk_id: clock id as mentioned in device tree bindings + * @lookup: duplicate lookup entry for the clock + */ +struct tegra_clk_duplicate { + int clk_id; + struct clk_lookup lookup; +}; + +#define TEGRA_CLK_DUPLICATE(_clk_id, _dev, _con) \ + { \ + .clk_id = _clk_id, \ + .lookup = { \ + .dev_id = _dev, \ + .con_id = _con, \ + }, \ + } + +void tegra_init_from_table(struct tegra_clk_init_table *tbl, + struct clk *clks[], int clk_max); + +void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, + struct clk *clks[], int clk_max); + +#endif /* TEGRA_CLK_H */ From 37c26a906527b8a6a252614ca83d21ad318c4e84 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:24 +0530 Subject: [PATCH 058/148] clk: tegra: add clock support for Tegra20 Add Tegra20 clock support based on common clock framework. Signed-off-by: Prashant Gaikwad [swarren: s/1GHz/100MHz/ in call to tegra_clk_plle() to fix PCIe, implemented KBC clock, ensure all OF lookups return valid cookies i.e. an explicit error pointer or valid pointer not NULL, adapt to renames in earlier patches, fixed some checkpatch issues.] Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/Makefile | 2 + drivers/clk/tegra/clk-tegra20.c | 1273 +++++++++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 6 + 3 files changed, 1281 insertions(+) create mode 100644 drivers/clk/tegra/clk-tegra20.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 68bd353a2108..00484fd4e515 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -6,3 +6,5 @@ obj-y += clk-periph-gate.o obj-y += clk-pll.o obj-y += clk-pll-out.o obj-y += clk-super.o + +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c new file mode 100644 index 000000000000..4ae8287b0f81 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra20.c @@ -0,0 +1,1273 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define RST_DEVICES_L 0x004 +#define RST_DEVICES_H 0x008 +#define RST_DEVICES_U 0x00c +#define RST_DEVICES_SET_L 0x300 +#define RST_DEVICES_CLR_L 0x304 +#define RST_DEVICES_SET_H 0x308 +#define RST_DEVICES_CLR_H 0x30c +#define RST_DEVICES_SET_U 0x310 +#define RST_DEVICES_CLR_U 0x314 +#define RST_DEVICES_NUM 3 + +#define CLK_OUT_ENB_L 0x010 +#define CLK_OUT_ENB_H 0x014 +#define CLK_OUT_ENB_U 0x018 +#define CLK_OUT_ENB_SET_L 0x320 +#define CLK_OUT_ENB_CLR_L 0x324 +#define CLK_OUT_ENB_SET_H 0x328 +#define CLK_OUT_ENB_CLR_H 0x32c +#define CLK_OUT_ENB_SET_U 0x330 +#define CLK_OUT_ENB_CLR_U 0x334 +#define CLK_OUT_ENB_NUM 3 + +#define OSC_CTRL 0x50 +#define OSC_CTRL_OSC_FREQ_MASK (3<<30) +#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30) +#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30) +#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30) +#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30) +#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) + +#define OSC_CTRL_PLL_REF_DIV_MASK (3<<28) +#define OSC_CTRL_PLL_REF_DIV_1 (0<<28) +#define OSC_CTRL_PLL_REF_DIV_2 (1<<28) +#define OSC_CTRL_PLL_REF_DIV_4 (2<<28) + +#define OSC_FREQ_DET 0x58 +#define OSC_FREQ_DET_TRIG (1<<31) + +#define OSC_FREQ_DET_STATUS 0x5c +#define OSC_FREQ_DET_BUSY (1<<31) +#define OSC_FREQ_DET_CNT_MASK 0xFFFF + +#define PLLS_BASE 0xf0 +#define PLLS_MISC 0xf4 +#define PLLC_BASE 0x80 +#define PLLC_MISC 0x8c +#define PLLM_BASE 0x90 +#define PLLM_MISC 0x9c +#define PLLP_BASE 0xa0 +#define PLLP_MISC 0xac +#define PLLA_BASE 0xb0 +#define PLLA_MISC 0xbc +#define PLLU_BASE 0xc0 +#define PLLU_MISC 0xcc +#define PLLD_BASE 0xd0 +#define PLLD_MISC 0xdc +#define PLLX_BASE 0xe0 +#define PLLX_MISC 0xe4 +#define PLLE_BASE 0xe8 +#define PLLE_MISC 0xec + +#define PLL_BASE_LOCK 27 +#define PLLE_MISC_LOCK 11 + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLE_MISC_LOCK_ENABLE 9 + +#define PLLC_OUT 0x84 +#define PLLM_OUT 0x94 +#define PLLP_OUTA 0xa4 +#define PLLP_OUTB 0xa8 +#define PLLA_OUT 0xb4 + +#define CCLK_BURST_POLICY 0x20 +#define SUPER_CCLK_DIVIDER 0x24 +#define SCLK_BURST_POLICY 0x28 +#define SUPER_SCLK_DIVIDER 0x2c +#define CLK_SYSTEM_RATE 0x30 + +#define CLK_SOURCE_I2S1 0x100 +#define CLK_SOURCE_I2S2 0x104 +#define CLK_SOURCE_SPDIF_OUT 0x108 +#define CLK_SOURCE_SPDIF_IN 0x10c +#define CLK_SOURCE_PWM 0x110 +#define CLK_SOURCE_SPI 0x114 +#define CLK_SOURCE_SBC1 0x134 +#define CLK_SOURCE_SBC2 0x118 +#define CLK_SOURCE_SBC3 0x11c +#define CLK_SOURCE_SBC4 0x1b4 +#define CLK_SOURCE_XIO 0x120 +#define CLK_SOURCE_TWC 0x12c +#define CLK_SOURCE_IDE 0x144 +#define CLK_SOURCE_NDFLASH 0x160 +#define CLK_SOURCE_VFIR 0x168 +#define CLK_SOURCE_SDMMC1 0x150 +#define CLK_SOURCE_SDMMC2 0x154 +#define CLK_SOURCE_SDMMC3 0x1bc +#define CLK_SOURCE_SDMMC4 0x164 +#define CLK_SOURCE_CVE 0x140 +#define CLK_SOURCE_TVO 0x188 +#define CLK_SOURCE_TVDAC 0x194 +#define CLK_SOURCE_HDMI 0x18c +#define CLK_SOURCE_DISP1 0x138 +#define CLK_SOURCE_DISP2 0x13c +#define CLK_SOURCE_CSITE 0x1d4 +#define CLK_SOURCE_LA 0x1f8 +#define CLK_SOURCE_OWR 0x1cc +#define CLK_SOURCE_NOR 0x1d0 +#define CLK_SOURCE_MIPI 0x174 +#define CLK_SOURCE_I2C1 0x124 +#define CLK_SOURCE_I2C2 0x198 +#define CLK_SOURCE_I2C3 0x1b8 +#define CLK_SOURCE_DVC 0x128 +#define CLK_SOURCE_UARTA 0x178 +#define CLK_SOURCE_UARTB 0x17c +#define CLK_SOURCE_UARTC 0x1a0 +#define CLK_SOURCE_UARTD 0x1c0 +#define CLK_SOURCE_UARTE 0x1c4 +#define CLK_SOURCE_3D 0x158 +#define CLK_SOURCE_2D 0x15c +#define CLK_SOURCE_MPE 0x170 +#define CLK_SOURCE_EPP 0x16c +#define CLK_SOURCE_HOST1X 0x180 +#define CLK_SOURCE_VDE 0x1c8 +#define CLK_SOURCE_VI 0x148 +#define CLK_SOURCE_VI_SENSOR 0x1a8 +#define CLK_SOURCE_EMC 0x19c + +#define AUDIO_SYNC_CLK 0x38 + +#define PMC_CTRL 0x0 +#define PMC_CTRL_BLINK_ENB 7 +#define PMC_DPD_PADS_ORIDE 0x1c +#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 +#define PMC_BLINK_TIMER 0x40 + +/* Tegra CPU clock and reset control regs */ +#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 + +#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) +#define CPU_RESET(cpu) (0x1111ul << (cpu)) + +static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; + +static void __iomem *clk_base; +static void __iomem *pmc_base; + +static DEFINE_SPINLOCK(pll_div_lock); + +#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, \ + _regs, _clk_num, periph_clk_enb_refcnt, \ + _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +#define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_width, _clk_num, _regs, \ + _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +/* IDs assigned here must be in sync with DT bindings definition + * for Tegra20 clocks . + */ +enum tegra20_clk { + cpu, ac97 = 3, rtc, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, + ndflash, sdmmc1, sdmmc4, twc, pwm, i2s2, epp, gr2d = 21, usbd, isp, + gr3d, ide, disp2, disp1, host1x, vcp, cache2 = 31, mem, ahbdma, apbdma, + kbc = 36, stat_mon, pmc, fuse, kfuse, sbc1, nor, spi, sbc2, xio, sbc3, + dvc, dsi, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, + usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, + pex, owr, afi, csite, pcie_xclk, avpucq = 75, la, irama = 84, iramb, + iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev1, cdev2, + uartb = 96, vfir, spdif_in, spdif_out, vi, vi_sensor, tvo, cve, + osc, clk_32k, clk_m, sclk, cclk, hclk, pclk, blink, pll_a, pll_a_out0, + pll_c, pll_c_out1, pll_d, pll_d_out0, pll_e, pll_m, pll_m_out1, + pll_p, pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_u, + pll_x, audio, pll_ref, twd, clk_max, +}; + +static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; + +static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { + { 12000000, 600000000, 600, 12, 1, 8 }, + { 13000000, 600000000, 600, 13, 1, 8 }, + { 19200000, 600000000, 500, 16, 1, 6 }, + { 26000000, 600000000, 600, 26, 1, 8 }, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { + { 12000000, 666000000, 666, 12, 1, 8}, + { 13000000, 666000000, 666, 13, 1, 8}, + { 19200000, 666000000, 555, 16, 1, 8}, + { 26000000, 666000000, 666, 26, 1, 8}, + { 12000000, 600000000, 600, 12, 1, 8}, + { 13000000, 600000000, 600, 13, 1, 8}, + { 19200000, 600000000, 375, 12, 1, 6}, + { 26000000, 600000000, 600, 26, 1, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { + { 12000000, 216000000, 432, 12, 2, 8}, + { 13000000, 216000000, 432, 13, 2, 8}, + { 19200000, 216000000, 90, 4, 2, 1}, + { 26000000, 216000000, 432, 26, 2, 8}, + { 12000000, 432000000, 432, 12, 1, 8}, + { 13000000, 432000000, 432, 13, 1, 8}, + { 19200000, 432000000, 90, 4, 1, 1}, + { 26000000, 432000000, 432, 26, 1, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { + { 28800000, 56448000, 49, 25, 1, 1}, + { 28800000, 73728000, 64, 25, 1, 1}, + { 28800000, 24000000, 5, 6, 1, 1}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { + { 12000000, 216000000, 216, 12, 1, 4}, + { 13000000, 216000000, 216, 13, 1, 4}, + { 19200000, 216000000, 135, 12, 1, 3}, + { 26000000, 216000000, 216, 26, 1, 4}, + + { 12000000, 594000000, 594, 12, 1, 8}, + { 13000000, 594000000, 594, 13, 1, 8}, + { 19200000, 594000000, 495, 16, 1, 8}, + { 26000000, 594000000, 594, 26, 1, 8}, + + { 12000000, 1000000000, 1000, 12, 1, 12}, + { 13000000, 1000000000, 1000, 13, 1, 12}, + { 19200000, 1000000000, 625, 12, 1, 8}, + { 26000000, 1000000000, 1000, 26, 1, 12}, + + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { + { 12000000, 480000000, 960, 12, 2, 0}, + { 13000000, 480000000, 960, 13, 2, 0}, + { 19200000, 480000000, 200, 4, 2, 0}, + { 26000000, 480000000, 960, 26, 2, 0}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { + /* 1 GHz */ + { 12000000, 1000000000, 1000, 12, 1, 12}, + { 13000000, 1000000000, 1000, 13, 1, 12}, + { 19200000, 1000000000, 625, 12, 1, 8}, + { 26000000, 1000000000, 1000, 26, 1, 12}, + + /* 912 MHz */ + { 12000000, 912000000, 912, 12, 1, 12}, + { 13000000, 912000000, 912, 13, 1, 12}, + { 19200000, 912000000, 760, 16, 1, 8}, + { 26000000, 912000000, 912, 26, 1, 12}, + + /* 816 MHz */ + { 12000000, 816000000, 816, 12, 1, 12}, + { 13000000, 816000000, 816, 13, 1, 12}, + { 19200000, 816000000, 680, 16, 1, 8}, + { 26000000, 816000000, 816, 26, 1, 12}, + + /* 760 MHz */ + { 12000000, 760000000, 760, 12, 1, 12}, + { 13000000, 760000000, 760, 13, 1, 12}, + { 19200000, 760000000, 950, 24, 1, 8}, + { 26000000, 760000000, 760, 26, 1, 12}, + + /* 750 MHz */ + { 12000000, 750000000, 750, 12, 1, 12}, + { 13000000, 750000000, 750, 13, 1, 12}, + { 19200000, 750000000, 625, 16, 1, 8}, + { 26000000, 750000000, 750, 26, 1, 12}, + + /* 608 MHz */ + { 12000000, 608000000, 608, 12, 1, 12}, + { 13000000, 608000000, 608, 13, 1, 12}, + { 19200000, 608000000, 380, 12, 1, 8}, + { 26000000, 608000000, 608, 26, 1, 12}, + + /* 456 MHz */ + { 12000000, 456000000, 456, 12, 1, 12}, + { 13000000, 456000000, 456, 13, 1, 12}, + { 19200000, 456000000, 380, 16, 1, 8}, + { 26000000, 456000000, 456, 26, 1, 12}, + + /* 312 MHz */ + { 12000000, 312000000, 312, 12, 1, 12}, + { 13000000, 312000000, 312, 13, 1, 12}, + { 19200000, 312000000, 260, 16, 1, 8}, + { 26000000, 312000000, 312, 26, 1, 12}, + + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + { 12000000, 100000000, 200, 24, 1, 0 }, + { 0, 0, 0, 0, 0, 0 }, +}; + +/* PLL parameters */ +static struct tegra_clk_pll_params pll_c_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLC_BASE, + .misc_reg = PLLC_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_m_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1200000000, + .base_reg = PLLM_BASE, + .misc_reg = PLLM_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_p_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLP_BASE, + .misc_reg = PLLP_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_a_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLA_BASE, + .misc_reg = PLLA_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_d_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 40000000, + .vco_max = 1000000000, + .base_reg = PLLD_BASE, + .misc_reg = PLLD_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_u_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 48000000, + .vco_max = 960000000, + .base_reg = PLLU_BASE, + .misc_reg = PLLU_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_x_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1200000000, + .base_reg = PLLX_BASE, + .misc_reg = PLLX_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 12000000, + .cf_min = 0, + .cf_max = 0, + .vco_min = 0, + .vco_max = 0, + .base_reg = PLLE_BASE, + .misc_reg = PLLE_MISC, + .lock_bit_idx = PLLE_MISC_LOCK, + .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, + .lock_delay = 0, +}; + +/* Peripheral clock registers */ +static struct tegra_clk_periph_regs periph_l_regs = { + .enb_reg = CLK_OUT_ENB_L, + .enb_set_reg = CLK_OUT_ENB_SET_L, + .enb_clr_reg = CLK_OUT_ENB_CLR_L, + .rst_reg = RST_DEVICES_L, + .rst_set_reg = RST_DEVICES_SET_L, + .rst_clr_reg = RST_DEVICES_CLR_L, +}; + +static struct tegra_clk_periph_regs periph_h_regs = { + .enb_reg = CLK_OUT_ENB_H, + .enb_set_reg = CLK_OUT_ENB_SET_H, + .enb_clr_reg = CLK_OUT_ENB_CLR_H, + .rst_reg = RST_DEVICES_H, + .rst_set_reg = RST_DEVICES_SET_H, + .rst_clr_reg = RST_DEVICES_CLR_H, +}; + +static struct tegra_clk_periph_regs periph_u_regs = { + .enb_reg = CLK_OUT_ENB_U, + .enb_set_reg = CLK_OUT_ENB_SET_U, + .enb_clr_reg = CLK_OUT_ENB_CLR_U, + .rst_reg = RST_DEVICES_U, + .rst_set_reg = RST_DEVICES_SET_U, + .rst_clr_reg = RST_DEVICES_CLR_U, +}; + +static unsigned long tegra20_clk_measure_input_freq(void) +{ + u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL); + u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK; + u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; + unsigned long input_freq; + + switch (auto_clk_control) { + case OSC_CTRL_OSC_FREQ_12MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 12000000; + break; + case OSC_CTRL_OSC_FREQ_13MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 13000000; + break; + case OSC_CTRL_OSC_FREQ_19_2MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 19200000; + break; + case OSC_CTRL_OSC_FREQ_26MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 26000000; + break; + default: + pr_err("Unexpected clock autodetect value %d", + auto_clk_control); + BUG(); + return 0; + } + + return input_freq; +} + +static unsigned int tegra20_get_pll_ref_div(void) +{ + u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) & + OSC_CTRL_PLL_REF_DIV_MASK; + + switch (pll_ref_div) { + case OSC_CTRL_PLL_REF_DIV_1: + return 1; + case OSC_CTRL_PLL_REF_DIV_2: + return 2; + case OSC_CTRL_PLL_REF_DIV_4: + return 4; + default: + pr_err("Invalied pll ref divider %d\n", pll_ref_div); + BUG(); + } + return 0; +} + +static void tegra20_pll_init(void) +{ + struct clk *clk; + + /* PLLC */ + clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, NULL, 0, + 0, &pll_c_params, TEGRA_PLL_HAS_CPCON, + pll_c_freq_table, NULL); + clk_register_clkdev(clk, "pll_c", NULL); + clks[pll_c] = clk; + + /* PLLC_OUT1 */ + clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", + clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", + clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT, + 0, NULL); + clk_register_clkdev(clk, "pll_c_out1", NULL); + clks[pll_c_out1] = clk; + + /* PLLP */ + clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, NULL, 0, + 216000000, &pll_p_params, TEGRA_PLL_FIXED | + TEGRA_PLL_HAS_CPCON, pll_p_freq_table, NULL); + clk_register_clkdev(clk, "pll_p", NULL); + clks[pll_p] = clk; + + /* PLLP_OUT1 */ + clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", + clk_base + PLLP_OUTA, 0, + TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", + clk_base + PLLP_OUTA, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out1", NULL); + clks[pll_p_out1] = clk; + + /* PLLP_OUT2 */ + clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", + clk_base + PLLP_OUTA, 0, + TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, + 24, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", + clk_base + PLLP_OUTA, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out2", NULL); + clks[pll_p_out2] = clk; + + /* PLLP_OUT3 */ + clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", + clk_base + PLLP_OUTB, 0, + TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", + clk_base + PLLP_OUTB, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out3", NULL); + clks[pll_p_out3] = clk; + + /* PLLP_OUT4 */ + clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", + clk_base + PLLP_OUTB, 0, + TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, + 24, 8, 1, &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", + clk_base + PLLP_OUTB, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out4", NULL); + clks[pll_p_out4] = clk; + + /* PLLM */ + clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, NULL, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, + &pll_m_params, TEGRA_PLL_HAS_CPCON, + pll_m_freq_table, NULL); + clk_register_clkdev(clk, "pll_m", NULL); + clks[pll_m] = clk; + + /* PLLM_OUT1 */ + clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", + clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", + clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_m_out1", NULL); + clks[pll_m_out1] = clk; + + /* PLLX */ + clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, NULL, 0, + 0, &pll_x_params, TEGRA_PLL_HAS_CPCON, + pll_x_freq_table, NULL); + clk_register_clkdev(clk, "pll_x", NULL); + clks[pll_x] = clk; + + /* PLLU */ + clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, NULL, 0, + 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, + pll_u_freq_table, NULL); + clk_register_clkdev(clk, "pll_u", NULL); + clks[pll_u] = clk; + + /* PLLD */ + clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, NULL, 0, + 0, &pll_d_params, TEGRA_PLL_HAS_CPCON, + pll_d_freq_table, NULL); + clk_register_clkdev(clk, "pll_d", NULL); + clks[pll_d] = clk; + + /* PLLD_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d_out0", NULL); + clks[pll_d_out0] = clk; + + /* PLLA */ + clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, NULL, 0, + 0, &pll_a_params, TEGRA_PLL_HAS_CPCON, + pll_a_freq_table, NULL); + clk_register_clkdev(clk, "pll_a", NULL); + clks[pll_a] = clk; + + /* PLLA_OUT0 */ + clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", + clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", + clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_a_out0", NULL); + clks[pll_a_out0] = clk; + + /* PLLE */ + clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, NULL, + 0, 100000000, &pll_e_params, + 0, pll_e_freq_table, NULL); + clk_register_clkdev(clk, "pll_e", NULL); + clks[pll_e] = clk; +} + +static const char *cclk_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p_cclk", "pll_p_out4_cclk", + "pll_p_out3_cclk", "clk_d", "pll_x" }; +static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", + "pll_p_out3", "pll_p_out2", "clk_d", + "clk_32k", "pll_m_out1" }; + +static void tegra20_super_clk_init(void) +{ + struct clk *clk; + + /* + * DIV_U71 dividers for CCLK, these dividers are used only + * if parent clock is fixed rate. + */ + + /* + * Clock input to cclk divided from pll_p using + * U71 divider of cclk. + */ + clk = tegra_clk_register_divider("pll_p_cclk", "pll_p", + clk_base + SUPER_CCLK_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_cclk", NULL); + + /* + * Clock input to cclk divided from pll_p_out3 using + * U71 divider of cclk. + */ + clk = tegra_clk_register_divider("pll_p_out3_cclk", "pll_p_out3", + clk_base + SUPER_CCLK_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out3_cclk", NULL); + + /* + * Clock input to cclk divided from pll_p_out4 using + * U71 divider of cclk. + */ + clk = tegra_clk_register_divider("pll_p_out4_cclk", "pll_p_out4", + clk_base + SUPER_CCLK_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out4_cclk", NULL); + + /* CCLK */ + clk = tegra_clk_register_super_mux("cclk", cclk_parents, + ARRAY_SIZE(cclk_parents), CLK_SET_RATE_PARENT, + clk_base + CCLK_BURST_POLICY, 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "cclk", NULL); + clks[cclk] = clk; + + /* SCLK */ + clk = tegra_clk_register_super_mux("sclk", sclk_parents, + ARRAY_SIZE(sclk_parents), CLK_SET_RATE_PARENT, + clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "sclk", NULL); + clks[sclk] = clk; + + /* HCLK */ + clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, + clk_base + CLK_SYSTEM_RATE, 4, 2, 0, NULL); + clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT, + clk_base + CLK_SYSTEM_RATE, 7, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "hclk", NULL); + clks[hclk] = clk; + + /* PCLK */ + clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, + clk_base + CLK_SYSTEM_RATE, 0, 2, 0, NULL); + clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT, + clk_base + CLK_SYSTEM_RATE, 3, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "pclk", NULL); + clks[pclk] = clk; + + /* twd */ + clk = clk_register_fixed_factor(NULL, "twd", "cclk", 0, 1, 4); + clk_register_clkdev(clk, "twd", NULL); + clks[twd] = clk; +} + +static const char *audio_parents[] = {"spdif_in", "i2s1", "i2s2", "unused", + "pll_a_out0", "unused", "unused", + "unused"}; + +static void __init tegra20_audio_clk_init(void) +{ + struct clk *clk; + + /* audio */ + clk = clk_register_mux(NULL, "audio_mux", audio_parents, + ARRAY_SIZE(audio_parents), 0, + clk_base + AUDIO_SYNC_CLK, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio", "audio_mux", 0, + clk_base + AUDIO_SYNC_CLK, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio", NULL); + clks[audio] = clk; + + /* audio_2x */ + clk = clk_register_fixed_factor(NULL, "audio_doubler", "audio", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_periph_gate("audio_2x", "audio_doubler", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 89, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio_2x", NULL); + clks[audio_2x] = clk; + +} + +static const char *i2s1_parents[] = {"pll_a_out0", "audio_2x", "pll_p", + "clk_m"}; +static const char *i2s2_parents[] = {"pll_a_out0", "audio_2x", "pll_p", + "clk_m"}; +static const char *spdif_out_parents[] = {"pll_a_out0", "audio_2x", "pll_p", + "clk_m"}; +static const char *spdif_in_parents[] = {"pll_p", "pll_c", "pll_m"}; +static const char *pwm_parents[] = {"pll_p", "pll_c", "audio", "clk_m", + "clk_32k"}; +static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"}; +static const char *mux_pllmcpa[] = {"pll_m", "pll_c", "pll_c", "pll_a"}; +static const char *mux_pllpdc_clkm[] = {"pll_p", "pll_d_out0", "pll_c", + "clk_m"}; +static const char *mux_pllmcp_clkm[] = {"pll_m", "pll_c", "pll_p", "clk_m"}; + +static struct tegra_periph_init_data tegra_periph_clk_list[] = { + TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra20-i2s.0", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), + TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra20-i2s.1", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), + TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra20-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), + TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra20-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), + TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), + TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), + TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), + TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), + TEGRA_INIT_DATA_MUX("spi", NULL, "spi", mux_pllpcm_clkm, CLK_SOURCE_SPI, 43, &periph_h_regs, TEGRA_PERIPH_ON_APB, spi), + TEGRA_INIT_DATA_MUX("xio", NULL, "xio", mux_pllpcm_clkm, CLK_SOURCE_XIO, 45, &periph_h_regs, 0, xio), + TEGRA_INIT_DATA_MUX("twc", NULL, "twc", mux_pllpcm_clkm, CLK_SOURCE_TWC, 16, &periph_l_regs, TEGRA_PERIPH_ON_APB, twc), + TEGRA_INIT_DATA_MUX("ide", NULL, "ide", mux_pllpcm_clkm, CLK_SOURCE_XIO, 25, &periph_l_regs, 0, ide), + TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, 0, ndflash), + TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), + TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, 0, csite), + TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, 0, la), + TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), + TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), + TEGRA_INIT_DATA_MUX("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), + TEGRA_INIT_DATA_MUX("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), + TEGRA_INIT_DATA_MUX("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), + TEGRA_INIT_DATA_MUX("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe), + TEGRA_INIT_DATA_MUX("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), + TEGRA_INIT_DATA_MUX("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d), + TEGRA_INIT_DATA_MUX("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d), + TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), + TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), + TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), + TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), + TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), + TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve), + TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo), + TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac), + TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), + TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllpcm_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1), + TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllpcm_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2), + TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllpcm_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3), + TEGRA_INIT_DATA_DIV16("dvc", "div-clk", "tegra-i2c.3", mux_pllpcm_clkm, CLK_SOURCE_DVC, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, dvc), + TEGRA_INIT_DATA_MUX("hdmi", NULL, "hdmi", mux_pllpdc_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), + TEGRA_INIT_DATA("pwm", NULL, "tegra-pwm", pwm_parents, CLK_SOURCE_PWM, 28, 3, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, TEGRA_PERIPH_ON_APB, pwm), +}; + +static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { + TEGRA_INIT_DATA_NODIV("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 30, 2, 6, &periph_l_regs, TEGRA_PERIPH_ON_APB, uarta), + TEGRA_INIT_DATA_NODIV("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 30, 2, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, uartb), + TEGRA_INIT_DATA_NODIV("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 30, 2, 55, &periph_h_regs, TEGRA_PERIPH_ON_APB, uartc), + TEGRA_INIT_DATA_NODIV("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 30, 2, 65, &periph_u_regs, TEGRA_PERIPH_ON_APB, uartd), + TEGRA_INIT_DATA_NODIV("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 30, 2, 66, &periph_u_regs, TEGRA_PERIPH_ON_APB, uarte), + TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpdc_clkm, CLK_SOURCE_DISP1, 30, 2, 27, &periph_l_regs, 0, disp1), + TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26, &periph_l_regs, 0, disp2), +}; + +static void __init tegra20_periph_clk_init(void) +{ + struct tegra_periph_init_data *data; + struct clk *clk; + int i; + + /* apbdma */ + clk = tegra_clk_register_periph_gate("apbdma", "pclk", 0, clk_base, + 0, 34, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-apbdma"); + clks[apbdma] = clk; + + /* rtc */ + clk = tegra_clk_register_periph_gate("rtc", "clk_32k", + TEGRA_PERIPH_NO_RESET, + clk_base, 0, 4, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "rtc-tegra"); + clks[rtc] = clk; + + /* timer */ + clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, + 0, 5, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "timer"); + clks[timer] = clk; + + /* kbc */ + clk = tegra_clk_register_periph_gate("kbc", "clk_32k", + TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, + clk_base, 0, 36, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-kbc"); + clks[kbc] = clk; + + /* csus */ + clk = tegra_clk_register_periph_gate("csus", "clk_m", + TEGRA_PERIPH_NO_RESET, + clk_base, 0, 92, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "csus", "tengra_camera"); + clks[csus] = clk; + + /* vcp */ + clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, + clk_base, 0, 29, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "vcp", "tegra-avp"); + clks[vcp] = clk; + + /* bsea */ + clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, + clk_base, 0, 62, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "bsea", "tegra-avp"); + clks[bsea] = clk; + + /* bsev */ + clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, + clk_base, 0, 63, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "bsev", "tegra-aes"); + clks[bsev] = clk; + + /* emc */ + clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, + ARRAY_SIZE(mux_pllmcp_clkm), 0, + clk_base + CLK_SOURCE_EMC, + 30, 2, 0, NULL); + clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, + 57, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "emc", NULL); + clks[emc] = clk; + + /* usbd */ + clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0, + 22, &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "fsl-tegra-udc"); + clks[usbd] = clk; + + /* usb2 */ + clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0, + 58, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-ehci.1"); + clks[usb2] = clk; + + /* usb3 */ + clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0, + 59, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-ehci.2"); + clks[usb3] = clk; + + /* dsi */ + clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0, + 48, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "dsi"); + clks[dsi] = clk; + + /* csi */ + clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, + 0, 52, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "csi", "tegra_camera"); + clks[csi] = clk; + + /* isp */ + clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23, + &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "isp", "tegra_camera"); + clks[isp] = clk; + + /* pex */ + clk = tegra_clk_register_periph_gate("pex", "clk_m", 0, clk_base, 0, 70, + &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "pex", NULL); + clks[pex] = clk; + + /* afi */ + clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72, + &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "afi", NULL); + clks[afi] = clk; + + /* pcie_xclk */ + clk = tegra_clk_register_periph_gate("pcie_xclk", "clk_m", 0, clk_base, + 0, 74, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "pcie_xclk", NULL); + clks[pcie_xclk] = clk; + + /* cdev1 */ + clk = clk_register_fixed_rate(NULL, "cdev1_fixed", NULL, CLK_IS_ROOT, + 26000000); + clk = tegra_clk_register_periph_gate("cdev1", "cdev1_fixed", 0, + clk_base, 0, 94, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "cdev1", NULL); + clks[cdev1] = clk; + + /* cdev2 */ + clk = clk_register_fixed_rate(NULL, "cdev2_fixed", NULL, CLK_IS_ROOT, + 26000000); + clk = tegra_clk_register_periph_gate("cdev2", "cdev2_fixed", 0, + clk_base, 0, 93, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "cdev2", NULL); + clks[cdev2] = clk; + + for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { + data = &tegra_periph_clk_list[i]; + clk = tegra_clk_register_periph(data->name, data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset); + clk_register_clkdev(clk, data->con_id, data->dev_id); + clks[data->clk_id] = clk; + } + + for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { + data = &tegra_periph_nodiv_clk_list[i]; + clk = tegra_clk_register_periph_nodiv(data->name, + data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset); + clk_register_clkdev(clk, data->con_id, data->dev_id); + clks[data->clk_id] = clk; + } +} + + +static void __init tegra20_fixed_clk_init(void) +{ + struct clk *clk; + + /* clk_32k */ + clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, + 32768); + clk_register_clkdev(clk, "clk_32k", NULL); + clks[clk_32k] = clk; +} + +static void __init tegra20_pmc_clk_init(void) +{ + struct clk *clk; + + /* blink */ + writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); + clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, + pmc_base + PMC_DPD_PADS_ORIDE, + PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); + clk = clk_register_gate(NULL, "blink", "blink_override", 0, + pmc_base + PMC_CTRL, + PMC_CTRL_BLINK_ENB, 0, NULL); + clk_register_clkdev(clk, "blink", NULL); + clks[blink] = clk; +} + +static void __init tegra20_osc_clk_init(void) +{ + struct clk *clk; + unsigned long input_freq; + unsigned int pll_ref_div; + + input_freq = tegra20_clk_measure_input_freq(); + + /* clk_m */ + clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT | + CLK_IGNORE_UNUSED, input_freq); + clk_register_clkdev(clk, "clk_m", NULL); + clks[clk_m] = clk; + + /* pll_ref */ + pll_ref_div = tegra20_get_pll_ref_div(); + clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", + CLK_SET_RATE_PARENT, 1, pll_ref_div); + clk_register_clkdev(clk, "pll_ref", NULL); + clks[pll_ref] = clk; +} + +/* Tegra20 CPU clock and reset control functions */ +static void tegra20_wait_cpu_in_reset(u32 cpu) +{ + unsigned int reg; + + do { + reg = readl(clk_base + + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); + cpu_relax(); + } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ + + return; +} + +static void tegra20_put_cpu_in_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); + dmb(); +} + +static void tegra20_cpu_out_of_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); + wmb(); +} + +static void tegra20_enable_cpu_clock(u32 cpu) +{ + unsigned int reg; + + reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + writel(reg & ~CPU_CLOCK(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + barrier(); + reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); +} + +static void tegra20_disable_cpu_clock(u32 cpu) +{ + unsigned int reg; + + reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + writel(reg | CPU_CLOCK(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); +} + +static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { + .wait_for_reset = tegra20_wait_cpu_in_reset, + .put_in_reset = tegra20_put_cpu_in_reset, + .out_of_reset = tegra20_cpu_out_of_reset, + .enable_clock = tegra20_enable_cpu_clock, + .disable_clock = tegra20_disable_cpu_clock, +}; + +static __initdata struct tegra_clk_init_table init_table[] = { + {pll_p, clk_max, 216000000, 1}, + {pll_p_out1, clk_max, 28800000, 1}, + {pll_p_out2, clk_max, 48000000, 1}, + {pll_p_out3, clk_max, 72000000, 1}, + {pll_p_out4, clk_max, 24000000, 1}, + {pll_c, clk_max, 600000000, 1}, + {pll_c_out1, clk_max, 120000000, 1}, + {sclk, pll_c_out1, 0, 1}, + {hclk, clk_max, 0, 1}, + {pclk, clk_max, 60000000, 1}, + {csite, clk_max, 0, 1}, + {emc, clk_max, 0, 1}, + {cclk, clk_max, 0, 1}, + {uarta, pll_p, 0, 1}, + {uartd, pll_p, 0, 1}, + {usbd, clk_max, 12000000, 0}, + {usb2, clk_max, 12000000, 0}, + {usb3, clk_max, 12000000, 0}, + {pll_a, clk_max, 56448000, 1}, + {pll_a_out0, clk_max, 11289600, 1}, + {cdev1, clk_max, 0, 1}, + {blink, clk_max, 32768, 1}, + {i2s1, pll_a_out0, 11289600, 0}, + {i2s2, pll_a_out0, 11289600, 0}, + {sdmmc1, pll_p, 48000000, 0}, + {sdmmc3, pll_p, 48000000, 0}, + {sdmmc4, pll_p, 48000000, 0}, + {spi, pll_p, 20000000, 0}, + {sbc1, pll_p, 100000000, 0}, + {sbc2, pll_p, 100000000, 0}, + {sbc3, pll_p, 100000000, 0}, + {sbc4, pll_p, 100000000, 0}, + {host1x, pll_c, 150000000, 0}, + {disp1, pll_p, 600000000, 0}, + {disp2, pll_p, 600000000, 0}, + {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */ +}; + +/* + * Some clocks may be used by different drivers depending on the board + * configuration. List those here to register them twice in the clock lookup + * table under two names. + */ +static struct tegra_clk_duplicate tegra_clk_duplicates[] = { + TEGRA_CLK_DUPLICATE(uarta, "serial8250.0", NULL), + TEGRA_CLK_DUPLICATE(uartb, "serial8250.1", NULL), + TEGRA_CLK_DUPLICATE(uartc, "serial8250.2", NULL), + TEGRA_CLK_DUPLICATE(uartd, "serial8250.3", NULL), + TEGRA_CLK_DUPLICATE(uarte, "serial8250.4", NULL), + TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), + TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), + TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), + TEGRA_CLK_DUPLICATE(pll_p, "tegradc.0", "parent"), + TEGRA_CLK_DUPLICATE(pll_p, "tegradc.1", "parent"), + TEGRA_CLK_DUPLICATE(pll_d_out0, "hdmi", "parent"), + TEGRA_CLK_DUPLICATE(gr2d, "tegra_grhost", "gr2d"), + TEGRA_CLK_DUPLICATE(gr3d, "tegra_grhost", "gr3d"), + TEGRA_CLK_DUPLICATE(epp, "tegra_grhost", "epp"), + TEGRA_CLK_DUPLICATE(mpe, "tegra_grhost", "mpe"), + TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), + TEGRA_CLK_DUPLICATE(cclk, NULL, "cpu"), + TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.0", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.1", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.2", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.3", "fast-clk"), + TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* Must be the last entry */ +}; + +static const struct of_device_id pmc_match[] __initconst = { + { .compatible = "nvidia,tegra20-pmc" }, + {}, +}; + +void __init tegra20_clock_init(struct device_node *np) +{ + int i; + struct device_node *node; + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("Can't map CAR registers\n"); + BUG(); + } + + node = of_find_matching_node(NULL, pmc_match); + if (!node) { + pr_err("Failed to find pmc node\n"); + BUG(); + } + + pmc_base = of_iomap(node, 0); + if (!pmc_base) { + pr_err("Can't map pmc registers\n"); + BUG(); + } + + tegra20_osc_clk_init(); + tegra20_pmc_clk_init(); + tegra20_fixed_clk_init(); + tegra20_pll_init(); + tegra20_super_clk_init(); + tegra20_periph_clk_init(); + tegra20_audio_clk_init(); + + + for (i = 0; i < ARRAY_SIZE(clks); i++) { + if (IS_ERR(clks[i])) { + pr_err("Tegra20 clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + BUG(); + } + if (!clks[i]) + clks[i] = ERR_PTR(-EINVAL); + } + + tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + tegra_init_from_table(init_table, clks, clk_max); + + tegra_cpu_car_ops = &tegra20_cpu_car_ops; +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 5fcfa51d6b17..82835f24533c 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -487,4 +487,10 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl, void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max); +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +void tegra20_clock_init(struct device_node *np); +#else +static inline void tegra20_clock_init(struct device_node *np) {} +#endif /* CONFIG_ARCH_TEGRA_2x_SOC */ + #endif /* TEGRA_CLK_H */ From b08e8c0ecc42afa3a2e1019851af741980dd5a6b Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:25 +0530 Subject: [PATCH 059/148] clk: tegra: add clock support for Tegra30 Add Tegra30 clock support based on common clock framework. Signed-off-by: Prashant Gaikwad [swarren: ensure all OF lookups return valid cookies i.e. an explicit error pointer or valid pointer not NULL, adapt to renames in earlier patches, fixed some checkpatch issues.] Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-tegra30.c | 2057 +++++++++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 6 + 3 files changed, 2064 insertions(+) create mode 100644 drivers/clk/tegra/clk-tegra30.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 00484fd4e515..2b41b0f4f731 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -8,3 +8,4 @@ obj-y += clk-pll-out.o obj-y += clk-super.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o +obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c new file mode 100644 index 000000000000..1c2765db1199 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra30.c @@ -0,0 +1,2057 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define RST_DEVICES_L 0x004 +#define RST_DEVICES_H 0x008 +#define RST_DEVICES_U 0x00c +#define RST_DEVICES_V 0x358 +#define RST_DEVICES_W 0x35c +#define RST_DEVICES_SET_L 0x300 +#define RST_DEVICES_CLR_L 0x304 +#define RST_DEVICES_SET_H 0x308 +#define RST_DEVICES_CLR_H 0x30c +#define RST_DEVICES_SET_U 0x310 +#define RST_DEVICES_CLR_U 0x314 +#define RST_DEVICES_SET_V 0x430 +#define RST_DEVICES_CLR_V 0x434 +#define RST_DEVICES_SET_W 0x438 +#define RST_DEVICES_CLR_W 0x43c +#define RST_DEVICES_NUM 5 + +#define CLK_OUT_ENB_L 0x010 +#define CLK_OUT_ENB_H 0x014 +#define CLK_OUT_ENB_U 0x018 +#define CLK_OUT_ENB_V 0x360 +#define CLK_OUT_ENB_W 0x364 +#define CLK_OUT_ENB_SET_L 0x320 +#define CLK_OUT_ENB_CLR_L 0x324 +#define CLK_OUT_ENB_SET_H 0x328 +#define CLK_OUT_ENB_CLR_H 0x32c +#define CLK_OUT_ENB_SET_U 0x330 +#define CLK_OUT_ENB_CLR_U 0x334 +#define CLK_OUT_ENB_SET_V 0x440 +#define CLK_OUT_ENB_CLR_V 0x444 +#define CLK_OUT_ENB_SET_W 0x448 +#define CLK_OUT_ENB_CLR_W 0x44c +#define CLK_OUT_ENB_NUM 5 + +#define OSC_CTRL 0x50 +#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28) +#define OSC_CTRL_OSC_FREQ_13MHZ (0X0<<28) +#define OSC_CTRL_OSC_FREQ_19_2MHZ (0X4<<28) +#define OSC_CTRL_OSC_FREQ_12MHZ (0X8<<28) +#define OSC_CTRL_OSC_FREQ_26MHZ (0XC<<28) +#define OSC_CTRL_OSC_FREQ_16_8MHZ (0X1<<28) +#define OSC_CTRL_OSC_FREQ_38_4MHZ (0X5<<28) +#define OSC_CTRL_OSC_FREQ_48MHZ (0X9<<28) +#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) + +#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26) +#define OSC_CTRL_PLL_REF_DIV_1 (0<<26) +#define OSC_CTRL_PLL_REF_DIV_2 (1<<26) +#define OSC_CTRL_PLL_REF_DIV_4 (2<<26) + +#define OSC_FREQ_DET 0x58 +#define OSC_FREQ_DET_TRIG BIT(31) + +#define OSC_FREQ_DET_STATUS 0x5c +#define OSC_FREQ_DET_BUSY BIT(31) +#define OSC_FREQ_DET_CNT_MASK 0xffff + +#define CCLKG_BURST_POLICY 0x368 +#define SUPER_CCLKG_DIVIDER 0x36c +#define CCLKLP_BURST_POLICY 0x370 +#define SUPER_CCLKLP_DIVIDER 0x374 +#define SCLK_BURST_POLICY 0x028 +#define SUPER_SCLK_DIVIDER 0x02c + +#define SYSTEM_CLK_RATE 0x030 + +#define PLLC_BASE 0x80 +#define PLLC_MISC 0x8c +#define PLLM_BASE 0x90 +#define PLLM_MISC 0x9c +#define PLLP_BASE 0xa0 +#define PLLP_MISC 0xac +#define PLLX_BASE 0xe0 +#define PLLX_MISC 0xe4 +#define PLLD_BASE 0xd0 +#define PLLD_MISC 0xdc +#define PLLD2_BASE 0x4b8 +#define PLLD2_MISC 0x4bc +#define PLLE_BASE 0xe8 +#define PLLE_MISC 0xec +#define PLLA_BASE 0xb0 +#define PLLA_MISC 0xbc +#define PLLU_BASE 0xc0 +#define PLLU_MISC 0xcc + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLE_MISC_LOCK_ENABLE 9 + +#define PLL_BASE_LOCK 27 +#define PLLE_MISC_LOCK 11 + +#define PLLE_AUX 0x48c +#define PLLC_OUT 0x84 +#define PLLM_OUT 0x94 +#define PLLP_OUTA 0xa4 +#define PLLP_OUTB 0xa8 +#define PLLA_OUT 0xb4 + +#define AUDIO_SYNC_CLK_I2S0 0x4a0 +#define AUDIO_SYNC_CLK_I2S1 0x4a4 +#define AUDIO_SYNC_CLK_I2S2 0x4a8 +#define AUDIO_SYNC_CLK_I2S3 0x4ac +#define AUDIO_SYNC_CLK_I2S4 0x4b0 +#define AUDIO_SYNC_CLK_SPDIF 0x4b4 + +#define PMC_CLK_OUT_CNTRL 0x1a8 + +#define CLK_SOURCE_I2S0 0x1d8 +#define CLK_SOURCE_I2S1 0x100 +#define CLK_SOURCE_I2S2 0x104 +#define CLK_SOURCE_I2S3 0x3bc +#define CLK_SOURCE_I2S4 0x3c0 +#define CLK_SOURCE_SPDIF_OUT 0x108 +#define CLK_SOURCE_SPDIF_IN 0x10c +#define CLK_SOURCE_PWM 0x110 +#define CLK_SOURCE_D_AUDIO 0x3d0 +#define CLK_SOURCE_DAM0 0x3d8 +#define CLK_SOURCE_DAM1 0x3dc +#define CLK_SOURCE_DAM2 0x3e0 +#define CLK_SOURCE_HDA 0x428 +#define CLK_SOURCE_HDA2CODEC_2X 0x3e4 +#define CLK_SOURCE_SBC1 0x134 +#define CLK_SOURCE_SBC2 0x118 +#define CLK_SOURCE_SBC3 0x11c +#define CLK_SOURCE_SBC4 0x1b4 +#define CLK_SOURCE_SBC5 0x3c8 +#define CLK_SOURCE_SBC6 0x3cc +#define CLK_SOURCE_SATA_OOB 0x420 +#define CLK_SOURCE_SATA 0x424 +#define CLK_SOURCE_NDFLASH 0x160 +#define CLK_SOURCE_NDSPEED 0x3f8 +#define CLK_SOURCE_VFIR 0x168 +#define CLK_SOURCE_SDMMC1 0x150 +#define CLK_SOURCE_SDMMC2 0x154 +#define CLK_SOURCE_SDMMC3 0x1bc +#define CLK_SOURCE_SDMMC4 0x164 +#define CLK_SOURCE_VDE 0x1c8 +#define CLK_SOURCE_CSITE 0x1d4 +#define CLK_SOURCE_LA 0x1f8 +#define CLK_SOURCE_OWR 0x1cc +#define CLK_SOURCE_NOR 0x1d0 +#define CLK_SOURCE_MIPI 0x174 +#define CLK_SOURCE_I2C1 0x124 +#define CLK_SOURCE_I2C2 0x198 +#define CLK_SOURCE_I2C3 0x1b8 +#define CLK_SOURCE_I2C4 0x3c4 +#define CLK_SOURCE_I2C5 0x128 +#define CLK_SOURCE_UARTA 0x178 +#define CLK_SOURCE_UARTB 0x17c +#define CLK_SOURCE_UARTC 0x1a0 +#define CLK_SOURCE_UARTD 0x1c0 +#define CLK_SOURCE_UARTE 0x1c4 +#define CLK_SOURCE_VI 0x148 +#define CLK_SOURCE_VI_SENSOR 0x1a8 +#define CLK_SOURCE_3D 0x158 +#define CLK_SOURCE_3D2 0x3b0 +#define CLK_SOURCE_2D 0x15c +#define CLK_SOURCE_EPP 0x16c +#define CLK_SOURCE_MPE 0x170 +#define CLK_SOURCE_HOST1X 0x180 +#define CLK_SOURCE_CVE 0x140 +#define CLK_SOURCE_TVO 0x188 +#define CLK_SOURCE_DTV 0x1dc +#define CLK_SOURCE_HDMI 0x18c +#define CLK_SOURCE_TVDAC 0x194 +#define CLK_SOURCE_DISP1 0x138 +#define CLK_SOURCE_DISP2 0x13c +#define CLK_SOURCE_DSIB 0xd0 +#define CLK_SOURCE_TSENSOR 0x3b8 +#define CLK_SOURCE_ACTMON 0x3e8 +#define CLK_SOURCE_EXTERN1 0x3ec +#define CLK_SOURCE_EXTERN2 0x3f0 +#define CLK_SOURCE_EXTERN3 0x3f4 +#define CLK_SOURCE_I2CSLOW 0x3fc +#define CLK_SOURCE_SE 0x42c +#define CLK_SOURCE_MSELECT 0x3b4 +#define CLK_SOURCE_EMC 0x19c + +#define AUDIO_SYNC_DOUBLER 0x49c + +#define PMC_CTRL 0 +#define PMC_CTRL_BLINK_ENB 7 + +#define PMC_DPD_PADS_ORIDE 0x1c +#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 +#define PMC_BLINK_TIMER 0x40 + +#define UTMIP_PLL_CFG2 0x488 +#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) +#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4) + +#define UTMIP_PLL_CFG1 0x484 +#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6) +#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) +#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16) + +/* Tegra CPU clock and reset control regs */ +#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 +#define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR 0x34c +#define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 + +#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) +#define CPU_RESET(cpu) (0x1111ul << (cpu)) + +#define CLK_RESET_CCLK_BURST 0x20 +#define CLK_RESET_CCLK_DIVIDER 0x24 +#define CLK_RESET_PLLX_BASE 0xe0 +#define CLK_RESET_PLLX_MISC 0xe4 + +#define CLK_RESET_SOURCE_CSITE 0x1d4 + +#define CLK_RESET_CCLK_BURST_POLICY_SHIFT 28 +#define CLK_RESET_CCLK_RUN_POLICY_SHIFT 4 +#define CLK_RESET_CCLK_IDLE_POLICY_SHIFT 0 +#define CLK_RESET_CCLK_IDLE_POLICY 1 +#define CLK_RESET_CCLK_RUN_POLICY 2 +#define CLK_RESET_CCLK_BURST_POLICY_PLLX 8 + +#ifdef CONFIG_PM_SLEEP +static struct cpu_clk_suspend_context { + u32 pllx_misc; + u32 pllx_base; + + u32 cpu_burst; + u32 clk_csite_src; + u32 cclk_divider; +} tegra30_cpu_clk_sctx; +#endif + +static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; + +static void __iomem *clk_base; +static void __iomem *pmc_base; +static unsigned long input_freq; + +static DEFINE_SPINLOCK(clk_doubler_lock); +static DEFINE_SPINLOCK(clk_out_lock); +static DEFINE_SPINLOCK(pll_div_lock); +static DEFINE_SPINLOCK(cml_lock); +static DEFINE_SPINLOCK(pll_d_lock); + +#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, \ + _regs, _clk_num, periph_clk_enb_refcnt, \ + _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 29, 3, 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +#define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + 30, 2, 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs, \ + _clk_num, periph_clk_enb_refcnt, 0, _clk_id) + +#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_width, _clk_num, _regs, \ + _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id) + +/* + * IDs assigned here must be in sync with DT bindings definition + * for Tegra30 clocks. + */ +enum tegra30_clk { + cpu, rtc = 4, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, ndflash, + sdmmc1, sdmmc4, pwm = 17, i2s2, epp, gr2d = 21, usbd, isp, gr3d, + disp2 = 26, disp1, host1x, vcp, i2s0, cop_cache, mc, ahbdma, apbdma, + kbc = 36, statmon, pmc, kfuse = 40, sbc1, nor, sbc2 = 44, sbc3 = 46, + i2c5, dsia, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, + usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, + pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2c_slow, + dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92, + cdev1, cdev2, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4, + i2c4, sbc5, sbc6, d_audio, apbif, dam0, dam1, dam2, hda2codec_2x, + atomics, audio0_2x, audio1_2x, audio2_2x, audio3_2x, audio4_2x, + spdif_2x, actmon, extern1, extern2, extern3, sata_oob, sata, hda, se, + hda2hdmi, sata_cold, uartb = 160, vfir, spdif_out, spdif_in, vi, + vi_sensor, fuse, fuse_burn, cve, tvo, clk_32k, clk_m, clk_m_div2, + clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_m, pll_m_out1, pll_p, + pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_a, pll_a_out0, + pll_d, pll_d_out0, pll_d2, pll_d2_out0, pll_u, pll_x, pll_x_out0, pll_e, + spdif_in_sync, i2s0_sync, i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync, + vimclk_sync, audio0, audio1, audio2, audio3, audio4, spdif, clk_out_1, + clk_out_2, clk_out_3, sclk, blink, cclk_g, cclk_lp, twd, cml0, cml1, + i2cslow, hclk, pclk, clk_out_1_mux = 300, clk_max +}; + +static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; + +/* + * Structure defining the fields for USB UTMI clocks Parameters. + */ +struct utmi_clk_param { + /* Oscillator Frequency in KHz */ + u32 osc_frequency; + /* UTMIP PLL Enable Delay Count */ + u8 enable_delay_count; + /* UTMIP PLL Stable count */ + u8 stable_count; + /* UTMIP PLL Active delay count */ + u8 active_delay_count; + /* UTMIP PLL Xtal frequency count */ + u8 xtal_freq_count; +}; + +static const struct utmi_clk_param utmi_parameters[] = { +/* OSC_FREQUENCY, ENABLE_DLY, STABLE_CNT, ACTIVE_DLY, XTAL_FREQ_CNT */ + {13000000, 0x02, 0x33, 0x05, 0x7F}, + {19200000, 0x03, 0x4B, 0x06, 0xBB}, + {12000000, 0x02, 0x2F, 0x04, 0x76}, + {26000000, 0x04, 0x66, 0x09, 0xFE}, + {16800000, 0x03, 0x41, 0x0A, 0xA4}, +}; + +static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { + { 12000000, 1040000000, 520, 6, 1, 8}, + { 13000000, 1040000000, 480, 6, 1, 8}, + { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */ + { 19200000, 1040000000, 325, 6, 1, 6}, + { 26000000, 1040000000, 520, 13, 1, 8}, + + { 12000000, 832000000, 416, 6, 1, 8}, + { 13000000, 832000000, 832, 13, 1, 8}, + { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */ + { 19200000, 832000000, 260, 6, 1, 8}, + { 26000000, 832000000, 416, 13, 1, 8}, + + { 12000000, 624000000, 624, 12, 1, 8}, + { 13000000, 624000000, 624, 13, 1, 8}, + { 16800000, 600000000, 520, 14, 1, 8}, + { 19200000, 624000000, 520, 16, 1, 8}, + { 26000000, 624000000, 624, 26, 1, 8}, + + { 12000000, 600000000, 600, 12, 1, 8}, + { 13000000, 600000000, 600, 13, 1, 8}, + { 16800000, 600000000, 500, 14, 1, 8}, + { 19200000, 600000000, 375, 12, 1, 6}, + { 26000000, 600000000, 600, 26, 1, 8}, + + { 12000000, 520000000, 520, 12, 1, 8}, + { 13000000, 520000000, 520, 13, 1, 8}, + { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */ + { 19200000, 520000000, 325, 12, 1, 6}, + { 26000000, 520000000, 520, 26, 1, 8}, + + { 12000000, 416000000, 416, 12, 1, 8}, + { 13000000, 416000000, 416, 13, 1, 8}, + { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */ + { 19200000, 416000000, 260, 12, 1, 6}, + { 26000000, 416000000, 416, 26, 1, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { + { 12000000, 666000000, 666, 12, 1, 8}, + { 13000000, 666000000, 666, 13, 1, 8}, + { 16800000, 666000000, 555, 14, 1, 8}, + { 19200000, 666000000, 555, 16, 1, 8}, + { 26000000, 666000000, 666, 26, 1, 8}, + { 12000000, 600000000, 600, 12, 1, 8}, + { 13000000, 600000000, 600, 13, 1, 8}, + { 16800000, 600000000, 500, 14, 1, 8}, + { 19200000, 600000000, 375, 12, 1, 6}, + { 26000000, 600000000, 600, 26, 1, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { + { 12000000, 216000000, 432, 12, 2, 8}, + { 13000000, 216000000, 432, 13, 2, 8}, + { 16800000, 216000000, 360, 14, 2, 8}, + { 19200000, 216000000, 360, 16, 2, 8}, + { 26000000, 216000000, 432, 26, 2, 8}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { + { 9600000, 564480000, 294, 5, 1, 4}, + { 9600000, 552960000, 288, 5, 1, 4}, + { 9600000, 24000000, 5, 2, 1, 1}, + + { 28800000, 56448000, 49, 25, 1, 1}, + { 28800000, 73728000, 64, 25, 1, 1}, + { 28800000, 24000000, 5, 6, 1, 1}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { + { 12000000, 216000000, 216, 12, 1, 4}, + { 13000000, 216000000, 216, 13, 1, 4}, + { 16800000, 216000000, 180, 14, 1, 4}, + { 19200000, 216000000, 180, 16, 1, 4}, + { 26000000, 216000000, 216, 26, 1, 4}, + + { 12000000, 594000000, 594, 12, 1, 8}, + { 13000000, 594000000, 594, 13, 1, 8}, + { 16800000, 594000000, 495, 14, 1, 8}, + { 19200000, 594000000, 495, 16, 1, 8}, + { 26000000, 594000000, 594, 26, 1, 8}, + + { 12000000, 1000000000, 1000, 12, 1, 12}, + { 13000000, 1000000000, 1000, 13, 1, 12}, + { 19200000, 1000000000, 625, 12, 1, 8}, + { 26000000, 1000000000, 1000, 26, 1, 12}, + + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { + { 12000000, 480000000, 960, 12, 2, 12}, + { 13000000, 480000000, 960, 13, 2, 12}, + { 16800000, 480000000, 400, 7, 2, 5}, + { 19200000, 480000000, 200, 4, 2, 3}, + { 26000000, 480000000, 960, 26, 2, 12}, + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { + /* 1.7 GHz */ + { 12000000, 1700000000, 850, 6, 1, 8}, + { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */ + { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */ + { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */ + { 26000000, 1700000000, 850, 13, 1, 8}, + + /* 1.6 GHz */ + { 12000000, 1600000000, 800, 6, 1, 8}, + { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */ + { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */ + { 19200000, 1600000000, 500, 6, 1, 8}, + { 26000000, 1600000000, 800, 13, 1, 8}, + + /* 1.5 GHz */ + { 12000000, 1500000000, 750, 6, 1, 8}, + { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */ + { 16800000, 1500000000, 625, 7, 1, 8}, + { 19200000, 1500000000, 625, 8, 1, 8}, + { 26000000, 1500000000, 750, 13, 1, 8}, + + /* 1.4 GHz */ + { 12000000, 1400000000, 700, 6, 1, 8}, + { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */ + { 16800000, 1400000000, 1000, 12, 1, 8}, + { 19200000, 1400000000, 875, 12, 1, 8}, + { 26000000, 1400000000, 700, 13, 1, 8}, + + /* 1.3 GHz */ + { 12000000, 1300000000, 975, 9, 1, 8}, + { 13000000, 1300000000, 1000, 10, 1, 8}, + { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */ + { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */ + { 26000000, 1300000000, 650, 13, 1, 8}, + + /* 1.2 GHz */ + { 12000000, 1200000000, 1000, 10, 1, 8}, + { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */ + { 16800000, 1200000000, 1000, 14, 1, 8}, + { 19200000, 1200000000, 1000, 16, 1, 8}, + { 26000000, 1200000000, 600, 13, 1, 8}, + + /* 1.1 GHz */ + { 12000000, 1100000000, 825, 9, 1, 8}, + { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */ + { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */ + { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */ + { 26000000, 1100000000, 550, 13, 1, 8}, + + /* 1 GHz */ + { 12000000, 1000000000, 1000, 12, 1, 8}, + { 13000000, 1000000000, 1000, 13, 1, 8}, + { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */ + { 19200000, 1000000000, 625, 12, 1, 8}, + { 26000000, 1000000000, 1000, 26, 1, 8}, + + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + { 12000000, 100000000, 150, 1, 18, 11}, + { 216000000, 100000000, 200, 18, 24, 13}, + { 0, 0, 0, 0, 0, 0 }, +}; + +/* PLL parameters */ +static struct tegra_clk_pll_params pll_c_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLC_BASE, + .misc_reg = PLLC_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_m_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1200000000, + .base_reg = PLLM_BASE, + .misc_reg = PLLM_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_p_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLP_BASE, + .misc_reg = PLLP_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_a_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1400000000, + .base_reg = PLLA_BASE, + .misc_reg = PLLA_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_d_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 40000000, + .vco_max = 1000000000, + .base_reg = PLLD_BASE, + .misc_reg = PLLD_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_d2_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 40000000, + .vco_max = 1000000000, + .base_reg = PLLD2_BASE, + .misc_reg = PLLD2_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_u_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 48000000, + .vco_max = 960000000, + .base_reg = PLLU_BASE, + .misc_reg = PLLU_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct tegra_clk_pll_params pll_x_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 20000000, + .vco_max = 1700000000, + .base_reg = PLLX_BASE, + .misc_reg = PLLX_MISC, + .lock_bit_idx = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 216000000, + .cf_min = 12000000, + .cf_max = 12000000, + .vco_min = 1200000000, + .vco_max = 2400000000U, + .base_reg = PLLE_BASE, + .misc_reg = PLLE_MISC, + .lock_bit_idx = PLLE_MISC_LOCK, + .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +/* Peripheral clock registers */ +static struct tegra_clk_periph_regs periph_l_regs = { + .enb_reg = CLK_OUT_ENB_L, + .enb_set_reg = CLK_OUT_ENB_SET_L, + .enb_clr_reg = CLK_OUT_ENB_CLR_L, + .rst_reg = RST_DEVICES_L, + .rst_set_reg = RST_DEVICES_SET_L, + .rst_clr_reg = RST_DEVICES_CLR_L, +}; + +static struct tegra_clk_periph_regs periph_h_regs = { + .enb_reg = CLK_OUT_ENB_H, + .enb_set_reg = CLK_OUT_ENB_SET_H, + .enb_clr_reg = CLK_OUT_ENB_CLR_H, + .rst_reg = RST_DEVICES_H, + .rst_set_reg = RST_DEVICES_SET_H, + .rst_clr_reg = RST_DEVICES_CLR_H, +}; + +static struct tegra_clk_periph_regs periph_u_regs = { + .enb_reg = CLK_OUT_ENB_U, + .enb_set_reg = CLK_OUT_ENB_SET_U, + .enb_clr_reg = CLK_OUT_ENB_CLR_U, + .rst_reg = RST_DEVICES_U, + .rst_set_reg = RST_DEVICES_SET_U, + .rst_clr_reg = RST_DEVICES_CLR_U, +}; + +static struct tegra_clk_periph_regs periph_v_regs = { + .enb_reg = CLK_OUT_ENB_V, + .enb_set_reg = CLK_OUT_ENB_SET_V, + .enb_clr_reg = CLK_OUT_ENB_CLR_V, + .rst_reg = RST_DEVICES_V, + .rst_set_reg = RST_DEVICES_SET_V, + .rst_clr_reg = RST_DEVICES_CLR_V, +}; + +static struct tegra_clk_periph_regs periph_w_regs = { + .enb_reg = CLK_OUT_ENB_W, + .enb_set_reg = CLK_OUT_ENB_SET_W, + .enb_clr_reg = CLK_OUT_ENB_CLR_W, + .rst_reg = RST_DEVICES_W, + .rst_set_reg = RST_DEVICES_SET_W, + .rst_clr_reg = RST_DEVICES_CLR_W, +}; + +static void tegra30_clk_measure_input_freq(void) +{ + u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL); + u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK; + u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; + + switch (auto_clk_control) { + case OSC_CTRL_OSC_FREQ_12MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 12000000; + break; + case OSC_CTRL_OSC_FREQ_13MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 13000000; + break; + case OSC_CTRL_OSC_FREQ_19_2MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 19200000; + break; + case OSC_CTRL_OSC_FREQ_26MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 26000000; + break; + case OSC_CTRL_OSC_FREQ_16_8MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); + input_freq = 16800000; + break; + case OSC_CTRL_OSC_FREQ_38_4MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2); + input_freq = 38400000; + break; + case OSC_CTRL_OSC_FREQ_48MHZ: + BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4); + input_freq = 48000000; + break; + default: + pr_err("Unexpected auto clock control value %d", + auto_clk_control); + BUG(); + return; + } +} + +static unsigned int tegra30_get_pll_ref_div(void) +{ + u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) & + OSC_CTRL_PLL_REF_DIV_MASK; + + switch (pll_ref_div) { + case OSC_CTRL_PLL_REF_DIV_1: + return 1; + case OSC_CTRL_PLL_REF_DIV_2: + return 2; + case OSC_CTRL_PLL_REF_DIV_4: + return 4; + default: + pr_err("Invalid pll ref divider %d", pll_ref_div); + BUG(); + } + return 0; +} + +static void tegra30_utmi_param_configure(void) +{ + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { + if (input_freq == utmi_parameters[i].osc_frequency) + break; + } + + if (i >= ARRAY_SIZE(utmi_parameters)) { + pr_err("%s: Unexpected input rate %lu\n", __func__, input_freq); + return; + } + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL stable and active counts */ + reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); + reg |= UTMIP_PLL_CFG2_STABLE_COUNT( + utmi_parameters[i].stable_count); + + reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT( + utmi_parameters[i].active_delay_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; + + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL delay and oscillator frequency counts */ + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT( + utmi_parameters[i].enable_delay_count); + + reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); + reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT( + utmi_parameters[i].xtal_freq_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; + + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); +} + +static const char *pll_e_parents[] = {"pll_ref", "pll_p"}; + +static void __init tegra30_pll_init(void) +{ + struct clk *clk; + + /* PLLC */ + clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_c_params, + TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, + pll_c_freq_table, NULL); + clk_register_clkdev(clk, "pll_c", NULL); + clks[pll_c] = clk; + + /* PLLC_OUT1 */ + clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", + clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", + clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT, + 0, NULL); + clk_register_clkdev(clk, "pll_c_out1", NULL); + clks[pll_c_out1] = clk; + + /* PLLP */ + clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc_base, 0, + 408000000, &pll_p_params, + TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_USE_LOCK, pll_p_freq_table, NULL); + clk_register_clkdev(clk, "pll_p", NULL); + clks[pll_p] = clk; + + /* PLLP_OUT1 */ + clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", + clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", + clk_base + PLLP_OUTA, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out1", NULL); + clks[pll_p_out1] = clk; + + /* PLLP_OUT2 */ + clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", + clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", + clk_base + PLLP_OUTA, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out2", NULL); + clks[pll_p_out2] = clk; + + /* PLLP_OUT3 */ + clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", + clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", + clk_base + PLLP_OUTB, 1, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out3", NULL); + clks[pll_p_out3] = clk; + + /* PLLP_OUT4 */ + clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", + clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | + TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, + &pll_div_lock); + clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", + clk_base + PLLP_OUTB, 17, 16, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + &pll_div_lock); + clk_register_clkdev(clk, "pll_p_out4", NULL); + clks[pll_p_out4] = clk; + + /* PLLM */ + clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, pmc_base, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, + &pll_m_params, TEGRA_PLLM | TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, + pll_m_freq_table, NULL); + clk_register_clkdev(clk, "pll_m", NULL); + clks[pll_m] = clk; + + /* PLLM_OUT1 */ + clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", + clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", + clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_m_out1", NULL); + clks[pll_m_out1] = clk; + + /* PLLX */ + clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_x_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, + pll_x_freq_table, NULL); + clk_register_clkdev(clk, "pll_x", NULL); + clks[pll_x] = clk; + + /* PLLX_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_x_out0", NULL); + clks[pll_x_out0] = clk; + + /* PLLU */ + clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, + pll_u_freq_table, + NULL); + clk_register_clkdev(clk, "pll_u", NULL); + clks[pll_u] = clk; + + tegra30_utmi_param_configure(); + + /* PLLD */ + clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_d_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, + pll_d_freq_table, &pll_d_lock); + clk_register_clkdev(clk, "pll_d", NULL); + clks[pll_d] = clk; + + /* PLLD_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d_out0", NULL); + clks[pll_d_out0] = clk; + + /* PLLD2 */ + clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 0, + 0, &pll_d2_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, + pll_d_freq_table, NULL); + clk_register_clkdev(clk, "pll_d2", NULL); + clks[pll_d2] = clk; + + /* PLLD2_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d2_out0", NULL); + clks[pll_d2_out0] = clk; + + /* PLLA */ + clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, pmc_base, + 0, 0, &pll_a_params, TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_USE_LOCK, pll_a_freq_table, NULL); + clk_register_clkdev(clk, "pll_a", NULL); + clks[pll_a] = clk; + + /* PLLA_OUT0 */ + clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", + clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", + clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_a_out0", NULL); + clks[pll_a_out0] = clk; + + /* PLLE */ + clk = clk_register_mux(NULL, "pll_e_mux", pll_e_parents, + ARRAY_SIZE(pll_e_parents), 0, + clk_base + PLLE_AUX, 2, 1, 0, NULL); + clk = tegra_clk_register_plle("pll_e", "pll_e_mux", clk_base, pmc_base, + CLK_GET_RATE_NOCACHE, 100000000, &pll_e_params, + TEGRA_PLLE_CONFIGURE, pll_e_freq_table, NULL); + clk_register_clkdev(clk, "pll_e", NULL); + clks[pll_e] = clk; +} + +static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync", + "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",}; +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern1", }; +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern2", }; +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern3", }; + +static void __init tegra30_audio_clk_init(void) +{ + struct clk *clk; + + /* spdif_in_sync */ + clk = tegra_clk_register_sync_source("spdif_in_sync", 24000000, + 24000000); + clk_register_clkdev(clk, "spdif_in_sync", NULL); + clks[spdif_in_sync] = clk; + + /* i2s0_sync */ + clk = tegra_clk_register_sync_source("i2s0_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s0_sync", NULL); + clks[i2s0_sync] = clk; + + /* i2s1_sync */ + clk = tegra_clk_register_sync_source("i2s1_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s1_sync", NULL); + clks[i2s1_sync] = clk; + + /* i2s2_sync */ + clk = tegra_clk_register_sync_source("i2s2_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s2_sync", NULL); + clks[i2s2_sync] = clk; + + /* i2s3_sync */ + clk = tegra_clk_register_sync_source("i2s3_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s3_sync", NULL); + clks[i2s3_sync] = clk; + + /* i2s4_sync */ + clk = tegra_clk_register_sync_source("i2s4_sync", 24000000, 24000000); + clk_register_clkdev(clk, "i2s4_sync", NULL); + clks[i2s4_sync] = clk; + + /* vimclk_sync */ + clk = tegra_clk_register_sync_source("vimclk_sync", 24000000, 24000000); + clk_register_clkdev(clk, "vimclk_sync", NULL); + clks[vimclk_sync] = clk; + + /* audio0 */ + clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S0, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio0", NULL); + clks[audio0] = clk; + + /* audio1 */ + clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S1, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio1", NULL); + clks[audio1] = clk; + + /* audio2 */ + clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S2, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio2", NULL); + clks[audio2] = clk; + + /* audio3 */ + clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S3, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio3", NULL); + clks[audio3] = clk; + + /* audio4 */ + clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0, + clk_base + AUDIO_SYNC_CLK_I2S4, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "audio4", NULL); + clks[audio4] = clk; + + /* spdif */ + clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), 0, + clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, NULL); + clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0, + clk_base + AUDIO_SYNC_CLK_SPDIF, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "spdif", NULL); + clks[spdif] = clk; + + /* audio0_2x */ + clk = clk_register_fixed_factor(NULL, "audio0_doubler", "audio0", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio0_div", "audio0_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 24, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio0_2x", "audio0_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 113, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio0_2x", NULL); + clks[audio0_2x] = clk; + + /* audio1_2x */ + clk = clk_register_fixed_factor(NULL, "audio1_doubler", "audio1", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio1_div", "audio1_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 25, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio1_2x", "audio1_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 114, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio1_2x", NULL); + clks[audio1_2x] = clk; + + /* audio2_2x */ + clk = clk_register_fixed_factor(NULL, "audio2_doubler", "audio2", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio2_div", "audio2_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 26, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio2_2x", "audio2_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 115, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio2_2x", NULL); + clks[audio2_2x] = clk; + + /* audio3_2x */ + clk = clk_register_fixed_factor(NULL, "audio3_doubler", "audio3", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio3_div", "audio3_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 27, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio3_2x", "audio3_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 116, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio3_2x", NULL); + clks[audio3_2x] = clk; + + /* audio4_2x */ + clk = clk_register_fixed_factor(NULL, "audio4_doubler", "audio4", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("audio4_div", "audio4_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 28, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("audio4_2x", "audio4_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 117, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "audio4_2x", NULL); + clks[audio4_2x] = clk; + + /* spdif_2x */ + clk = clk_register_fixed_factor(NULL, "spdif_doubler", "spdif", + CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider("spdif_div", "spdif_doubler", + clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 29, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate("spdif_2x", "spdif_div", + TEGRA_PERIPH_NO_RESET, clk_base, + CLK_SET_RATE_PARENT, 118, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "spdif_2x", NULL); + clks[spdif_2x] = clk; +} + +static void __init tegra30_pmc_clk_init(void) +{ + struct clk *clk; + + /* clk_out_1 */ + clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0, + &clk_out_lock); + clks[clk_out_1_mux] = clk; + clk = clk_register_gate(NULL, "clk_out_1", "clk_out_1_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 2, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern1", "clk_out_1"); + clks[clk_out_1] = clk; + + /* clk_out_2 */ + clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0, + &clk_out_lock); + clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 10, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern2", "clk_out_2"); + clks[clk_out_2] = clk; + + /* clk_out_3 */ + clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, + ARRAY_SIZE(clk_out1_parents), 0, + pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0, + &clk_out_lock); + clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0, + pmc_base + PMC_CLK_OUT_CNTRL, 18, 0, + &clk_out_lock); + clk_register_clkdev(clk, "extern3", "clk_out_3"); + clks[clk_out_3] = clk; + + /* blink */ + writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); + clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, + pmc_base + PMC_DPD_PADS_ORIDE, + PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); + clk = clk_register_gate(NULL, "blink", "blink_override", 0, + pmc_base + PMC_CTRL, + PMC_CTRL_BLINK_ENB, 0, NULL); + clk_register_clkdev(clk, "blink", NULL); + clks[blink] = clk; + +} + +const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p_cclkg", "pll_p_out4_cclkg", + "pll_p_out3_cclkg", "unused", "pll_x" }; +const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p_cclklp", "pll_p_out4_cclklp", + "pll_p_out3_cclklp", "unused", "pll_x", + "pll_x_out0" }; +const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", + "pll_p_out3", "pll_p_out2", "unused", + "clk_32k", "pll_m_out1" }; + +static void __init tegra30_super_clk_init(void) +{ + struct clk *clk; + + /* + * Clock input to cclk_g divided from pll_p using + * U71 divider of cclk_g. + */ + clk = tegra_clk_register_divider("pll_p_cclkg", "pll_p", + clk_base + SUPER_CCLKG_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_cclkg", NULL); + + /* + * Clock input to cclk_g divided from pll_p_out3 using + * U71 divider of cclk_g. + */ + clk = tegra_clk_register_divider("pll_p_out3_cclkg", "pll_p_out3", + clk_base + SUPER_CCLKG_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out3_cclkg", NULL); + + /* + * Clock input to cclk_g divided from pll_p_out4 using + * U71 divider of cclk_g. + */ + clk = tegra_clk_register_divider("pll_p_out4_cclkg", "pll_p_out4", + clk_base + SUPER_CCLKG_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out4_cclkg", NULL); + + /* CCLKG */ + clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, + ARRAY_SIZE(cclk_g_parents), + CLK_SET_RATE_PARENT, + clk_base + CCLKG_BURST_POLICY, + 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "cclk_g", NULL); + clks[cclk_g] = clk; + + /* + * Clock input to cclk_lp divided from pll_p using + * U71 divider of cclk_lp. + */ + clk = tegra_clk_register_divider("pll_p_cclklp", "pll_p", + clk_base + SUPER_CCLKLP_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_cclklp", NULL); + + /* + * Clock input to cclk_lp divided from pll_p_out3 using + * U71 divider of cclk_lp. + */ + clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3", + clk_base + SUPER_CCLKG_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL); + + /* + * Clock input to cclk_lp divided from pll_p_out4 using + * U71 divider of cclk_lp. + */ + clk = tegra_clk_register_divider("pll_p_out4_cclklp", "pll_p_out4", + clk_base + SUPER_CCLKLP_DIVIDER, 0, + TEGRA_DIVIDER_INT, 16, 8, 1, NULL); + clk_register_clkdev(clk, "pll_p_out4_cclklp", NULL); + + /* CCLKLP */ + clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents, + ARRAY_SIZE(cclk_lp_parents), + CLK_SET_RATE_PARENT, + clk_base + CCLKLP_BURST_POLICY, + TEGRA_DIVIDER_2, 4, 8, 9, + NULL); + clk_register_clkdev(clk, "cclk_lp", NULL); + clks[cclk_lp] = clk; + + /* SCLK */ + clk = tegra_clk_register_super_mux("sclk", sclk_parents, + ARRAY_SIZE(sclk_parents), + CLK_SET_RATE_PARENT, + clk_base + SCLK_BURST_POLICY, + 0, 4, 0, 0, NULL); + clk_register_clkdev(clk, "sclk", NULL); + clks[sclk] = clk; + + /* HCLK */ + clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, + clk_base + SYSTEM_CLK_RATE, 4, 2, 0, NULL); + clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT, + clk_base + SYSTEM_CLK_RATE, 7, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "hclk", NULL); + clks[hclk] = clk; + + /* PCLK */ + clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, + clk_base + SYSTEM_CLK_RATE, 0, 2, 0, NULL); + clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT, + clk_base + SYSTEM_CLK_RATE, 3, + CLK_GATE_SET_TO_DISABLE, NULL); + clk_register_clkdev(clk, "pclk", NULL); + clks[pclk] = clk; + + /* twd */ + clk = clk_register_fixed_factor(NULL, "twd", "cclk_g", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "twd", NULL); + clks[twd] = clk; +} + +static const char *mux_pllacp_clkm[] = { "pll_a_out0", "unused", "pll_p", + "clk_m" }; +static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" }; +static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" }; +static const char *i2s0_parents[] = { "pll_a_out0", "audio0_2x", "pll_p", + "clk_m" }; +static const char *i2s1_parents[] = { "pll_a_out0", "audio1_2x", "pll_p", + "clk_m" }; +static const char *i2s2_parents[] = { "pll_a_out0", "audio2_2x", "pll_p", + "clk_m" }; +static const char *i2s3_parents[] = { "pll_a_out0", "audio3_2x", "pll_p", + "clk_m" }; +static const char *i2s4_parents[] = { "pll_a_out0", "audio4_2x", "pll_p", + "clk_m" }; +static const char *spdif_out_parents[] = { "pll_a_out0", "spdif_2x", "pll_p", + "clk_m" }; +static const char *spdif_in_parents[] = { "pll_p", "pll_c", "pll_m" }; +static const char *mux_pllpc_clk32k_clkm[] = { "pll_p", "pll_c", "clk_32k", + "clk_m" }; +static const char *mux_pllpc_clkm_clk32k[] = { "pll_p", "pll_c", "clk_m", + "clk_32k" }; +static const char *mux_pllmcpa[] = { "pll_m", "pll_c", "pll_p", "pll_a_out0" }; +static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c", + "clk_m" }; +static const char *mux_pllp_clkm[] = { "pll_p", "unused", "unused", "clk_m" }; +static const char *mux_pllpmdacd2_clkm[] = { "pll_p", "pll_m", "pll_d_out0", + "pll_a_out0", "pll_c", + "pll_d2_out0", "clk_m" }; +static const char *mux_plla_clk32k_pllp_clkm_plle[] = { "pll_a_out0", + "clk_32k", "pll_p", + "clk_m", "pll_e" }; +static const char *mux_plld_out0_plld2_out0[] = { "pll_d_out0", + "pll_d2_out0" }; + +static struct tegra_periph_init_data tegra_periph_clk_list[] = { + TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", i2s0_parents, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0), + TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), + TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), + TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", i2s3_parents, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3), + TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", i2s4_parents, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4), + TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), + TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), + TEGRA_INIT_DATA_MUX("d_audio", "d_audio", "tegra30-ahub", mux_pllacp_clkm, CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, 0, d_audio), + TEGRA_INIT_DATA_MUX("dam0", NULL, "tegra30-dam.0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, &periph_v_regs, 0, dam0), + TEGRA_INIT_DATA_MUX("dam1", NULL, "tegra30-dam.1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, &periph_v_regs, 0, dam1), + TEGRA_INIT_DATA_MUX("dam2", NULL, "tegra30-dam.2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, &periph_v_regs, 0, dam2), + TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, 0, hda), + TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, 0, hda2codec_2x), + TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), + TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), + TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), + TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), + TEGRA_INIT_DATA_MUX("sbc5", NULL, "spi_tegra.4", mux_pllpcm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5), + TEGRA_INIT_DATA_MUX("sbc6", NULL, "spi_tegra.5", mux_pllpcm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6), + TEGRA_INIT_DATA_MUX("sata_oob", NULL, "tegra_sata_oob", mux_pllpcm_clkm, CLK_SOURCE_SATA_OOB, 123, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata_oob), + TEGRA_INIT_DATA_MUX("sata", NULL, "tegra_sata", mux_pllpcm_clkm, CLK_SOURCE_SATA, 124, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata), + TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, TEGRA_PERIPH_ON_APB, ndflash), + TEGRA_INIT_DATA_MUX("ndspeed", NULL, "tegra_nand_speed", mux_pllpcm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), + TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), + TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite), + TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la), + TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), + TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), + TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllpc_clkm_clk32k, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor), + TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllpc_clk32k_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow), + TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), + TEGRA_INIT_DATA_INT("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), + TEGRA_INIT_DATA_INT("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), + TEGRA_INIT_DATA_INT("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe), + TEGRA_INIT_DATA_INT("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), + TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d), + TEGRA_INIT_DATA_INT("3d2", NULL, "3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, &periph_v_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d2), + TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d), + TEGRA_INIT_DATA_INT("se", NULL, "se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, 0, se), + TEGRA_INIT_DATA_MUX("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect), + TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), + TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), + TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), + TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), + TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), + TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve), + TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo), + TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac), + TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllpc_clk32k_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon), + TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), + TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1), + TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2), + TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3), + TEGRA_INIT_DATA_DIV16("i2c4", "div-clk", "tegra-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2c4), + TEGRA_INIT_DATA_DIV16("i2c5", "div-clk", "tegra-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c5), + TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta), + TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb), + TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc), + TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd), + TEGRA_INIT_DATA_UART("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 66, &periph_u_regs, uarte), + TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), + TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1), + TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2), + TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3), + TEGRA_INIT_DATA("pwm", NULL, "pwm", mux_pllpc_clk32k_clkm, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, 0, pwm), +}; + +static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { + TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP1, 29, 3, 27, &periph_l_regs, 0, disp1), + TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP2, 29, 3, 26, &periph_l_regs, 0, disp2), + TEGRA_INIT_DATA_NODIV("dsib", NULL, "tegradc.1", mux_plld_out0_plld2_out0, CLK_SOURCE_DSIB, 25, 1, 82, &periph_u_regs, 0, dsib), +}; + +static void __init tegra30_periph_clk_init(void) +{ + struct tegra_periph_init_data *data; + struct clk *clk; + int i; + + /* apbdma */ + clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base, 0, 34, + &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-apbdma"); + clks[apbdma] = clk; + + /* rtc */ + clk = tegra_clk_register_periph_gate("rtc", "clk_32k", + TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, + clk_base, 0, 4, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "rtc-tegra"); + clks[rtc] = clk; + + /* timer */ + clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, 0, + 5, &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "timer"); + clks[timer] = clk; + + /* kbc */ + clk = tegra_clk_register_periph_gate("kbc", "clk_32k", + TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, + clk_base, 0, 36, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-kbc"); + clks[kbc] = clk; + + /* csus */ + clk = tegra_clk_register_periph_gate("csus", "clk_m", + TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, + clk_base, 0, 92, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "csus", "tengra_camera"); + clks[csus] = clk; + + /* vcp */ + clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0, 29, + &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "vcp", "tegra-avp"); + clks[vcp] = clk; + + /* bsea */ + clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, clk_base, 0, + 62, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "bsea", "tegra-avp"); + clks[bsea] = clk; + + /* bsev */ + clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, clk_base, 0, + 63, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "bsev", "tegra-aes"); + clks[bsev] = clk; + + /* usbd */ + clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0, + 22, &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "fsl-tegra-udc"); + clks[usbd] = clk; + + /* usb2 */ + clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0, + 58, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-ehci.1"); + clks[usb2] = clk; + + /* usb3 */ + clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0, + 59, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra-ehci.2"); + clks[usb3] = clk; + + /* dsia */ + clk = tegra_clk_register_periph_gate("dsia", "pll_d_out0", 0, clk_base, + 0, 48, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "dsia", "tegradc.0"); + clks[dsia] = clk; + + /* csi */ + clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, + 0, 52, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "csi", "tegra_camera"); + clks[csi] = clk; + + /* isp */ + clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23, + &periph_l_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "isp", "tegra_camera"); + clks[isp] = clk; + + /* pcie */ + clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0, + 70, &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "pcie", "tegra-pcie"); + clks[pcie] = clk; + + /* afi */ + clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72, + &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "afi", "tegra-pcie"); + clks[afi] = clk; + + /* kfuse */ + clk = tegra_clk_register_periph_gate("kfuse", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 40, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "kfuse-tegra"); + clks[kfuse] = clk; + + /* fuse */ + clk = tegra_clk_register_periph_gate("fuse", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 39, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "fuse", "fuse-tegra"); + clks[fuse] = clk; + + /* fuse_burn */ + clk = tegra_clk_register_periph_gate("fuse_burn", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 39, &periph_h_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "fuse_burn", "fuse-tegra"); + clks[fuse_burn] = clk; + + /* apbif */ + clk = tegra_clk_register_periph_gate("apbif", "clk_m", 0, + clk_base, 0, 107, &periph_v_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "apbif", "tegra30-ahub"); + clks[apbif] = clk; + + /* hda2hdmi */ + clk = tegra_clk_register_periph_gate("hda2hdmi", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 128, &periph_w_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, "hda2hdmi", "tegra30-hda"); + clks[hda2hdmi] = clk; + + /* sata_cold */ + clk = tegra_clk_register_periph_gate("sata_cold", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 129, &periph_w_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra_sata_cold"); + clks[sata_cold] = clk; + + /* dtv */ + clk = tegra_clk_register_periph_gate("dtv", "clk_m", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 79, &periph_u_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "dtv"); + clks[dtv] = clk; + + /* emc */ + clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, + ARRAY_SIZE(mux_pllmcp_clkm), 0, + clk_base + CLK_SOURCE_EMC, + 30, 2, 0, NULL); + clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, + 57, &periph_h_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "emc", NULL); + clks[emc] = clk; + + /* i2c1-fast */ + clk = clk_register_fixed_factor(NULL, "i2c1-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.0"); + + /* i2c2-fast */ + clk = clk_register_fixed_factor(NULL, "i2c2-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.1"); + + /* i2c3-fast */ + clk = clk_register_fixed_factor(NULL, "i2c3-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.2"); + + /* i2c4-fast */ + clk = clk_register_fixed_factor(NULL, "i2c4-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.3"); + + /* i2c5-fast */ + clk = clk_register_fixed_factor(NULL, "i2c5-fast", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "fast-clk", "tegra-i2c.5"); + + /* dsi1-fixed */ + clk = clk_register_fixed_factor(NULL, "dsi1-fixed", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "dsi-fixed", "tegradc.0"); + + /* dsi2-fixed */ + clk = clk_register_fixed_factor(NULL, "dsi2-fixed", "pll_p_out3", + CLK_SET_RATE_PARENT, 1, 1); + clk_register_clkdev(clk, "dsi-fixed", "tegradc.1"); + + for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { + data = &tegra_periph_clk_list[i]; + clk = tegra_clk_register_periph(data->name, data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset); + clk_register_clkdev(clk, data->con_id, data->dev_id); + clks[data->clk_id] = clk; + } + + for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { + data = &tegra_periph_nodiv_clk_list[i]; + clk = tegra_clk_register_periph_nodiv(data->name, + data->parent_names, + data->num_parents, &data->periph, + clk_base, data->offset); + clk_register_clkdev(clk, data->con_id, data->dev_id); + clks[data->clk_id] = clk; + } +} + +static void __init tegra30_fixed_clk_init(void) +{ + struct clk *clk; + + /* clk_32k */ + clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, + 32768); + clk_register_clkdev(clk, "clk_32k", NULL); + clks[clk_32k] = clk; + + /* clk_m_div2 */ + clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "clk_m_div2", NULL); + clks[clk_m_div2] = clk; + + /* clk_m_div4 */ + clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", + CLK_SET_RATE_PARENT, 1, 4); + clk_register_clkdev(clk, "clk_m_div4", NULL); + clks[clk_m_div4] = clk; + + /* cml0 */ + clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, + 0, 0, &cml_lock); + clk_register_clkdev(clk, "cml0", NULL); + clks[cml0] = clk; + + /* cml1 */ + clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX, + 1, 0, &cml_lock); + clk_register_clkdev(clk, "cml1", NULL); + clks[cml1] = clk; + + /* pciex */ + clk = clk_register_fixed_rate(NULL, "pciex", "pll_e", 0, 100000000); + clk_register_clkdev(clk, "pciex", NULL); + clks[pciex] = clk; +} + +static void __init tegra30_osc_clk_init(void) +{ + struct clk *clk; + unsigned int pll_ref_div; + + tegra30_clk_measure_input_freq(); + + /* clk_m */ + clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, + input_freq); + clk_register_clkdev(clk, "clk_m", NULL); + clks[clk_m] = clk; + + /* pll_ref */ + pll_ref_div = tegra30_get_pll_ref_div(); + clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", + CLK_SET_RATE_PARENT, 1, pll_ref_div); + clk_register_clkdev(clk, "pll_ref", NULL); + clks[pll_ref] = clk; +} + +/* Tegra30 CPU clock and reset control functions */ +static void tegra30_wait_cpu_in_reset(u32 cpu) +{ + unsigned int reg; + + do { + reg = readl(clk_base + + TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); + cpu_relax(); + } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ + + return; +} + +static void tegra30_put_cpu_in_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); + dmb(); +} + +static void tegra30_cpu_out_of_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); + wmb(); +} + + +static void tegra30_enable_cpu_clock(u32 cpu) +{ + unsigned int reg; + + writel(CPU_CLOCK(cpu), + clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); + reg = readl(clk_base + + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); +} + +static void tegra30_disable_cpu_clock(u32 cpu) +{ + + unsigned int reg; + + reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + writel(reg | CPU_CLOCK(cpu), + clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); +} + +#ifdef CONFIG_PM_SLEEP +static bool tegra30_cpu_rail_off_ready(void) +{ + unsigned int cpu_rst_status; + int cpu_pwr_status; + + cpu_rst_status = readl(clk_base + + TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); + cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) || + tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) || + tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3); + + if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status) + return false; + + return true; +} + +static void tegra30_cpu_clock_suspend(void) +{ + /* switch coresite to clk_m, save off original source */ + tegra30_cpu_clk_sctx.clk_csite_src = + readl(clk_base + CLK_RESET_SOURCE_CSITE); + writel(3<<30, clk_base + CLK_RESET_SOURCE_CSITE); + + tegra30_cpu_clk_sctx.cpu_burst = + readl(clk_base + CLK_RESET_CCLK_BURST); + tegra30_cpu_clk_sctx.pllx_base = + readl(clk_base + CLK_RESET_PLLX_BASE); + tegra30_cpu_clk_sctx.pllx_misc = + readl(clk_base + CLK_RESET_PLLX_MISC); + tegra30_cpu_clk_sctx.cclk_divider = + readl(clk_base + CLK_RESET_CCLK_DIVIDER); +} + +static void tegra30_cpu_clock_resume(void) +{ + unsigned int reg, policy; + + /* Is CPU complex already running on PLLX? */ + reg = readl(clk_base + CLK_RESET_CCLK_BURST); + policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF; + + if (policy == CLK_RESET_CCLK_IDLE_POLICY) + reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF; + else if (policy == CLK_RESET_CCLK_RUN_POLICY) + reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF; + else + BUG(); + + if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) { + /* restore PLLX settings if CPU is on different PLL */ + writel(tegra30_cpu_clk_sctx.pllx_misc, + clk_base + CLK_RESET_PLLX_MISC); + writel(tegra30_cpu_clk_sctx.pllx_base, + clk_base + CLK_RESET_PLLX_BASE); + + /* wait for PLL stabilization if PLLX was enabled */ + if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30)) + udelay(300); + } + + /* + * Restore original burst policy setting for calls resulting from CPU + * LP2 in idle or system suspend. + */ + writel(tegra30_cpu_clk_sctx.cclk_divider, + clk_base + CLK_RESET_CCLK_DIVIDER); + writel(tegra30_cpu_clk_sctx.cpu_burst, + clk_base + CLK_RESET_CCLK_BURST); + + writel(tegra30_cpu_clk_sctx.clk_csite_src, + clk_base + CLK_RESET_SOURCE_CSITE); +} +#endif + +static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { + .wait_for_reset = tegra30_wait_cpu_in_reset, + .put_in_reset = tegra30_put_cpu_in_reset, + .out_of_reset = tegra30_cpu_out_of_reset, + .enable_clock = tegra30_enable_cpu_clock, + .disable_clock = tegra30_disable_cpu_clock, +#ifdef CONFIG_PM_SLEEP + .rail_off_ready = tegra30_cpu_rail_off_ready, + .suspend = tegra30_cpu_clock_suspend, + .resume = tegra30_cpu_clock_resume, +#endif +}; + +static __initdata struct tegra_clk_init_table init_table[] = { + {uarta, pll_p, 408000000, 1}, + {pll_a, clk_max, 564480000, 1}, + {pll_a_out0, clk_max, 11289600, 1}, + {extern1, pll_a_out0, 0, 1}, + {clk_out_1_mux, extern1, 0, 0}, + {clk_out_1, clk_max, 0, 1}, + {blink, clk_max, 0, 1}, + {i2s0, pll_a_out0, 11289600, 0}, + {i2s1, pll_a_out0, 11289600, 0}, + {i2s2, pll_a_out0, 11289600, 0}, + {i2s3, pll_a_out0, 11289600, 0}, + {i2s4, pll_a_out0, 11289600, 0}, + {sdmmc1, pll_p, 48000000, 0}, + {sdmmc2, pll_p, 48000000, 0}, + {sdmmc3, pll_p, 48000000, 0}, + {pll_m, clk_max, 0, 1}, + {pclk, clk_max, 0, 1}, + {csite, clk_max, 0, 1}, + {emc, clk_max, 0, 1}, + {mselect, clk_max, 0, 1}, + {sbc1, pll_p, 100000000, 0}, + {sbc2, pll_p, 100000000, 0}, + {sbc3, pll_p, 100000000, 0}, + {sbc4, pll_p, 100000000, 0}, + {sbc5, pll_p, 100000000, 0}, + {sbc6, pll_p, 100000000, 0}, + {host1x, pll_c, 150000000, 0}, + {disp1, pll_p, 600000000, 0}, + {disp2, pll_p, 600000000, 0}, + {twd, clk_max, 0, 1}, + {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ +}; + +/* + * Some clocks may be used by different drivers depending on the board + * configuration. List those here to register them twice in the clock lookup + * table under two names. + */ +static struct tegra_clk_duplicate tegra_clk_duplicates[] = { + TEGRA_CLK_DUPLICATE(uarta, "serial8250.0", NULL), + TEGRA_CLK_DUPLICATE(uartb, "serial8250.1", NULL), + TEGRA_CLK_DUPLICATE(uartc, "serial8250.2", NULL), + TEGRA_CLK_DUPLICATE(uartd, "serial8250.3", NULL), + TEGRA_CLK_DUPLICATE(uarte, "serial8250.4", NULL), + TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), + TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), + TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), + TEGRA_CLK_DUPLICATE(pll_p, "tegradc.0", "parent"), + TEGRA_CLK_DUPLICATE(pll_p, "tegradc.1", "parent"), + TEGRA_CLK_DUPLICATE(pll_d2_out0, "hdmi", "parent"), + TEGRA_CLK_DUPLICATE(dsib, "tegradc.0", "dsib"), + TEGRA_CLK_DUPLICATE(dsia, "tegradc.1", "dsia"), + TEGRA_CLK_DUPLICATE(bsev, "tegra-avp", "bsev"), + TEGRA_CLK_DUPLICATE(bsev, "nvavp", "bsev"), + TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), + TEGRA_CLK_DUPLICATE(bsea, "tegra-aes", "bsea"), + TEGRA_CLK_DUPLICATE(bsea, "nvavp", "bsea"), + TEGRA_CLK_DUPLICATE(cml1, "tegra_sata_cml", NULL), + TEGRA_CLK_DUPLICATE(cml0, "tegra_pcie", "cml"), + TEGRA_CLK_DUPLICATE(pciex, "tegra_pcie", "pciex"), + TEGRA_CLK_DUPLICATE(i2c1, "tegra-i2c-slave.0", NULL), + TEGRA_CLK_DUPLICATE(i2c2, "tegra-i2c-slave.1", NULL), + TEGRA_CLK_DUPLICATE(i2c3, "tegra-i2c-slave.2", NULL), + TEGRA_CLK_DUPLICATE(i2c4, "tegra-i2c-slave.3", NULL), + TEGRA_CLK_DUPLICATE(i2c5, "tegra-i2c-slave.4", NULL), + TEGRA_CLK_DUPLICATE(sbc1, "spi_slave_tegra.0", NULL), + TEGRA_CLK_DUPLICATE(sbc2, "spi_slave_tegra.1", NULL), + TEGRA_CLK_DUPLICATE(sbc3, "spi_slave_tegra.2", NULL), + TEGRA_CLK_DUPLICATE(sbc4, "spi_slave_tegra.3", NULL), + TEGRA_CLK_DUPLICATE(sbc5, "spi_slave_tegra.4", NULL), + TEGRA_CLK_DUPLICATE(sbc6, "spi_slave_tegra.5", NULL), + TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), + TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"), + TEGRA_CLK_DUPLICATE(i2s0, NULL, "i2s0"), + TEGRA_CLK_DUPLICATE(i2s1, NULL, "i2s1"), + TEGRA_CLK_DUPLICATE(i2s2, NULL, "i2s2"), + TEGRA_CLK_DUPLICATE(i2s3, NULL, "i2s3"), + TEGRA_CLK_DUPLICATE(i2s4, NULL, "i2s4"), + TEGRA_CLK_DUPLICATE(dam0, NULL, "dam0"), + TEGRA_CLK_DUPLICATE(dam1, NULL, "dam1"), + TEGRA_CLK_DUPLICATE(dam2, NULL, "dam2"), + TEGRA_CLK_DUPLICATE(spdif_in, NULL, "spdif_in"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.0", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.1", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.2", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.3", "fast-clk"), + TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.4", "fast-clk"), + TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* MUST be the last entry */ +}; + +static const struct of_device_id pmc_match[] __initconst = { + { .compatible = "nvidia,tegra30-pmc" }, + {}, +}; + +void __init tegra30_clock_init(struct device_node *np) +{ + struct device_node *node; + int i; + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("ioremap tegra30 CAR failed\n"); + return; + } + + node = of_find_matching_node(NULL, pmc_match); + if (!node) { + pr_err("Failed to find pmc node\n"); + BUG(); + } + + pmc_base = of_iomap(node, 0); + if (!pmc_base) { + pr_err("Can't map pmc registers\n"); + BUG(); + } + + tegra30_osc_clk_init(); + tegra30_fixed_clk_init(); + tegra30_pll_init(); + tegra30_super_clk_init(); + tegra30_periph_clk_init(); + tegra30_audio_clk_init(); + tegra30_pmc_clk_init(); + + for (i = 0; i < ARRAY_SIZE(clks); i++) { + if (IS_ERR(clks[i])) { + pr_err("Tegra30 clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + BUG(); + } + if (!clks[i]) + clks[i] = ERR_PTR(-EINVAL); + } + + tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + tegra_init_from_table(init_table, clks, clk_max); + + tegra_cpu_car_ops = &tegra30_cpu_car_ops; +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 82835f24533c..0744731c6229 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -493,4 +493,10 @@ void tegra20_clock_init(struct device_node *np); static inline void tegra20_clock_init(struct device_node *np) {} #endif /* CONFIG_ARCH_TEGRA_2x_SOC */ +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +void tegra30_clock_init(struct device_node *np); +#else +static inline void tegra30_clock_init(struct device_node *np) {} +#endif /* CONFIG_ARCH_TEGRA_3x_SOC */ + #endif /* TEGRA_CLK_H */ From 61fd290d213e25d5a119b8ca25644001ed9f8f2d Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:26 +0530 Subject: [PATCH 060/148] ARM: tegra: migrate to new clock code Migrate Tegra clock support to drivers/clk/tegra, this involves moving: 1. definition of tegra_cpu_car_ops to clk.c 2. definition of reset functions to clk-peripheral.c 3. change parent of cpu clock. 4. Remove legacy clock initialization. 5. Initialize clocks using DT. 6. Remove all instance of mach/clk.h Signed-off-by: Prashant Gaikwad [swarren: use to_clk_periph_gate().] Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/board-dt-tegra20.c | 30 ------------------ arch/arm/mach-tegra/board-dt-tegra30.c | 31 ------------------ arch/arm/mach-tegra/clock.c | 19 ----------- arch/arm/mach-tegra/common.c | 44 ++------------------------ arch/arm/mach-tegra/cpu-tegra.c | 2 +- arch/arm/mach-tegra/include/mach/clk.h | 3 -- arch/arm/mach-tegra/pcie.c | 2 +- arch/arm/mach-tegra/powergate.c | 2 +- drivers/clk/tegra/clk-periph.c | 38 ++++++++++++++++++++++ drivers/clk/tegra/clk.c | 16 ++++++++++ drivers/dma/tegra20-apb-dma.c | 2 +- drivers/gpu/drm/tegra/dc.c | 3 +- drivers/gpu/drm/tegra/drm.c | 1 - drivers/gpu/drm/tegra/hdmi.c | 3 +- drivers/i2c/busses/i2c-tegra.c | 3 +- drivers/input/keyboard/tegra-kbc.c | 2 +- drivers/spi/spi-tegra20-sflash.c | 2 +- drivers/spi/spi-tegra20-slink.c | 2 +- drivers/staging/nvec/nvec.c | 3 +- include/linux/clk/tegra.h | 5 +++ sound/soc/tegra/tegra30_ahub.c | 2 +- 21 files changed, 73 insertions(+), 142 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index e1f87dd314ef..0c11b8af3af3 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -42,7 +42,6 @@ #include #include "board.h" -#include "clock.h" #include "common.h" #include "iomap.h" @@ -104,37 +103,8 @@ static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { {} }; -static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = { - /* name parent rate enabled */ - { "uarta", "pll_p", 216000000, true }, - { "uartd", "pll_p", 216000000, true }, - { "usbd", "clk_m", 12000000, false }, - { "usb2", "clk_m", 12000000, false }, - { "usb3", "clk_m", 12000000, false }, - { "pll_a", "pll_p_out1", 56448000, true }, - { "pll_a_out0", "pll_a", 11289600, true }, - { "cdev1", NULL, 0, true }, - { "blink", "clk_32k", 32768, true }, - { "i2s1", "pll_a_out0", 11289600, false}, - { "i2s2", "pll_a_out0", 11289600, false}, - { "sdmmc1", "pll_p", 48000000, false}, - { "sdmmc3", "pll_p", 48000000, false}, - { "sdmmc4", "pll_p", 48000000, false}, - { "spi", "pll_p", 20000000, false }, - { "sbc1", "pll_p", 100000000, false }, - { "sbc2", "pll_p", 100000000, false }, - { "sbc3", "pll_p", 100000000, false }, - { "sbc4", "pll_p", 100000000, false }, - { "host1x", "pll_c", 150000000, false }, - { "disp1", "pll_p", 600000000, false }, - { "disp2", "pll_p", 600000000, false }, - { NULL, NULL, 0, 0}, -}; - static void __init tegra_dt_init(void) { - tegra_clk_init_from_table(tegra_dt_clk_init_table); - /* * Finished with the static registrations now; fill in the missing * devices diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index cfe5fc02be77..92f6014d22a1 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -35,7 +35,6 @@ #include #include "board.h" -#include "clock.h" #include "common.h" #include "iomap.h" @@ -67,38 +66,8 @@ static struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { {} }; -static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = { - /* name parent rate enabled */ - { "uarta", "pll_p", 408000000, true }, - { "pll_a", "pll_p_out1", 564480000, true }, - { "pll_a_out0", "pll_a", 11289600, true }, - { "extern1", "pll_a_out0", 0, true }, - { "clk_out_1", "extern1", 0, true }, - { "blink", "clk_32k", 32768, true }, - { "i2s0", "pll_a_out0", 11289600, false}, - { "i2s1", "pll_a_out0", 11289600, false}, - { "i2s2", "pll_a_out0", 11289600, false}, - { "i2s3", "pll_a_out0", 11289600, false}, - { "i2s4", "pll_a_out0", 11289600, false}, - { "sdmmc1", "pll_p", 48000000, false}, - { "sdmmc3", "pll_p", 48000000, false}, - { "sdmmc4", "pll_p", 48000000, false}, - { "sbc1", "pll_p", 100000000, false}, - { "sbc2", "pll_p", 100000000, false}, - { "sbc3", "pll_p", 100000000, false}, - { "sbc4", "pll_p", 100000000, false}, - { "sbc5", "pll_p", 100000000, false}, - { "sbc6", "pll_p", 100000000, false}, - { "host1x", "pll_c", 150000000, false}, - { "disp1", "pll_p", 600000000, false}, - { "disp2", "pll_p", 600000000, false}, - { NULL, NULL, 0, 0}, -}; - static void __init tegra30_dt_init(void) { - tegra_clk_init_from_table(tegra_dt_clk_init_table); - of_platform_populate(NULL, of_default_bus_match_table, tegra30_auxdata_lookup, NULL); } diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 8c0ff061f8cf..baa0c5b008f1 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -31,9 +31,6 @@ #include "board.h" #include "clock.h" -/* Global data of Tegra CPU CAR ops */ -struct tegra_cpu_car_ops *tegra_cpu_car_ops; - /* * Locking: * @@ -131,22 +128,6 @@ void tegra_clk_init_from_table(struct tegra_clk_init_table *table) tegra_clk_init_one_from_table(table); } -void tegra_periph_reset_deassert(struct clk *c) -{ - struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); - BUG_ON(!clk->reset); - clk->reset(__clk_get_hw(c), false); -} -EXPORT_SYMBOL(tegra_periph_reset_deassert); - -void tegra_periph_reset_assert(struct clk *c) -{ - struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); - BUG_ON(!clk->reset); - clk->reset(__clk_get_hw(c), true); -} -EXPORT_SYMBOL(tegra_periph_reset_assert); - /* Several extended clock configuration bits (e.g., clock routing, clock * phase control) are included in PLL and peripheral clock source * registers. */ diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 3efe80b2af28..87dd69ccdf8e 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #include #include "board.h" -#include "clock.h" #include "common.h" #include "fuse.h" #include "iomap.h" @@ -65,6 +65,7 @@ static const struct of_device_id tegra_dt_irq_match[] __initconst = { void __init tegra_dt_init_irq(void) { + tegra_clocks_init(); tegra_init_irq(); of_irq_init(tegra_dt_irq_match); } @@ -80,43 +81,6 @@ void tegra_assert_system_reset(char mode, const char *cmd) writel_relaxed(reg, reset); } -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -static __initdata struct tegra_clk_init_table tegra20_clk_init_table[] = { - /* name parent rate enabled */ - { "clk_m", NULL, 0, true }, - { "pll_p", "clk_m", 216000000, true }, - { "pll_p_out1", "pll_p", 28800000, true }, - { "pll_p_out2", "pll_p", 48000000, true }, - { "pll_p_out3", "pll_p", 72000000, true }, - { "pll_p_out4", "pll_p", 24000000, true }, - { "pll_c", "clk_m", 600000000, true }, - { "pll_c_out1", "pll_c", 120000000, true }, - { "sclk", "pll_c_out1", 120000000, true }, - { "hclk", "sclk", 120000000, true }, - { "pclk", "hclk", 60000000, true }, - { "csite", NULL, 0, true }, - { "emc", NULL, 0, true }, - { "cpu", NULL, 0, true }, - { NULL, NULL, 0, 0}, -}; -#endif - -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = { - /* name parent rate enabled */ - { "clk_m", NULL, 0, true }, - { "pll_p", "pll_ref", 408000000, true }, - { "pll_p_out1", "pll_p", 9600000, true }, - { "pll_p_out4", "pll_p", 102000000, true }, - { "sclk", "pll_p_out4", 102000000, true }, - { "hclk", "sclk", 102000000, true }, - { "pclk", "hclk", 51000000, true }, - { "csite", NULL, 0, true }, - { NULL, NULL, 0, 0}, -}; -#endif - - static void __init tegra_init_cache(void) { #ifdef CONFIG_CACHE_L2X0 @@ -141,8 +105,6 @@ void __init tegra20_init_early(void) tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); - tegra2_init_clocks(); - tegra_clk_init_from_table(tegra20_clk_init_table); tegra_init_cache(); tegra_pmc_init(); tegra_powergate_init(); @@ -155,8 +117,6 @@ void __init tegra30_init_early(void) tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); - tegra30_init_clocks(); - tegra_clk_init_from_table(tegra30_clk_init_table); tegra_init_cache(); tegra_pmc_init(); tegra_powergate_init(); diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index 85d4a23bba03..ebffed67e2f5 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -266,7 +266,7 @@ static int __init tegra_cpufreq_init(void) if (IS_ERR(pll_x_clk)) return PTR_ERR(pll_x_clk); - pll_p_clk = clk_get_sys(NULL, "pll_p"); + pll_p_clk = clk_get_sys(NULL, "pll_p_cclk"); if (IS_ERR(pll_p_clk)) return PTR_ERR(pll_p_clk); diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h index 95f3a547c770..85bbf10a7d0d 100644 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ b/arch/arm/mach-tegra/include/mach/clk.h @@ -31,9 +31,6 @@ enum tegra_clk_ex_param { TEGRA_CLK_PLLD_MIPI_MUX_SEL, }; -void tegra_periph_reset_deassert(struct clk *c); -void tegra_periph_reset_assert(struct clk *c); - #ifndef CONFIG_COMMON_CLK unsigned long clk_get_rate_all_locked(struct clk *c); #endif diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c index bffcd643d7a3..b60165f1ca02 100644 --- a/arch/arm/mach-tegra/pcie.c +++ b/arch/arm/mach-tegra/pcie.c @@ -33,11 +33,11 @@ #include #include #include +#include #include #include -#include #include #include "board.h" diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index 2cc1185d902e..c6bc8f85759c 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -26,8 +26,8 @@ #include #include #include +#include -#include #include #include "fuse.h" diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index 5978e81b175b..788486e6331a 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -110,6 +110,44 @@ static void clk_periph_disable(struct clk_hw *hw) gate_ops->disable(gate_hw); } +void tegra_periph_reset_deassert(struct clk *c) +{ + struct clk_hw *hw = __clk_get_hw(c); + struct tegra_clk_periph *periph = to_clk_periph(hw); + struct tegra_clk_periph_gate *gate; + + if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { + gate = to_clk_periph_gate(hw); + if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { + WARN_ON(1); + return; + } + } else { + gate = &periph->gate; + } + + tegra_periph_reset(gate, 0); +} + +void tegra_periph_reset_assert(struct clk *c) +{ + struct clk_hw *hw = __clk_get_hw(c); + struct tegra_clk_periph *periph = to_clk_periph(hw); + struct tegra_clk_periph_gate *gate; + + if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { + gate = to_clk_periph_gate(hw); + if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { + WARN_ON(1); + return; + } + } else { + gate = &periph->gate; + } + + tegra_periph_reset(gate, 1); +} + const struct clk_ops tegra_clk_periph_ops = { .get_parent = clk_periph_get_parent, .set_parent = clk_periph_set_parent, diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index cf023a937208..a603b9af0ad3 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -16,9 +16,14 @@ #include #include +#include +#include #include "clk.h" +/* Global data of Tegra CPU CAR ops */ +struct tegra_cpu_car_ops *tegra_cpu_car_ops; + void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max) { @@ -67,3 +72,14 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, } } } + +static const struct of_device_id tegra_dt_clk_match[] = { + { .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init }, + { .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init }, + { } +}; + +void __init tegra_clocks_init(void) +{ + of_clk_init(tegra_dt_clk_match); +} diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index c39e61bc8172..afc9b89e20f4 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -31,8 +31,8 @@ #include #include #include +#include -#include #include "dmaengine.h" #define TEGRA_APBDMA_GENERAL 0x0 diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 656b2e3334a6..56813f967c8f 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -12,8 +12,7 @@ #include #include #include - -#include +#include #include "drm.h" #include "dc.h" diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 3a503c9e4686..d980dc75788c 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -11,7 +11,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index e060c7e6434d..92ad276cc5e0 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -14,8 +14,7 @@ #include #include #include - -#include +#include #include "hdmi.h" #include "drm.h" diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 7b38877ffec1..c7aca35e38fd 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -29,11 +29,10 @@ #include #include #include +#include #include -#include - #define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000)) #define BYTES_PER_FIFO_WORD 4 diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index c76f96872d31..54ac1dc7d477 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #define KBC_MAX_DEBOUNCE_CNT 0x3ffu diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 448a8cc71df3..02feaa51a0fa 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #define SPI_COMMAND 0x000 #define SPI_GO BIT(30) diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 651167f2e0af..fa208a5cc612 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #define SLINK_COMMAND 0x000 #define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0) diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 2830946860d1..d51615b19797 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -37,8 +37,7 @@ #include #include #include - -#include +#include #include "nvec.h" diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 0977f2a24757..a7e5a3999099 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -17,6 +17,8 @@ #ifndef __LINUX_CLK_TEGRA_H_ #define __LINUX_CLK_TEGRA_H_ +#include + /* * Tegra CPU clock and reset control ops * @@ -120,5 +122,8 @@ static inline void tegra_cpu_clock_resume(void) void tegra20_cpu_car_ops_init(void); void tegra30_cpu_car_ops_init(void); +void tegra_periph_reset_deassert(struct clk *c); +void tegra_periph_reset_assert(struct clk *c); +void tegra_clocks_init(void); #endif /* __LINUX_CLK_TEGRA_H_ */ diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index f354dc390a0b..bb31c4123a7b 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include "tegra30_ahub.h" From 52dec4c9eacc339dbf1b2ab549248df1cc6eb030 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:16:27 +0530 Subject: [PATCH 061/148] ARM: tegra: remove legacy clock code Remove all legacy clock code from mach-tegra. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Makefile | 5 - arch/arm/mach-tegra/clock.c | 147 -- arch/arm/mach-tegra/clock.h | 153 -- arch/arm/mach-tegra/include/mach/clk.h | 41 - arch/arm/mach-tegra/tegra20_clocks.c | 1623 ------------- arch/arm/mach-tegra/tegra20_clocks.h | 42 - arch/arm/mach-tegra/tegra20_clocks_data.c | 1143 ---------- arch/arm/mach-tegra/tegra30_clocks.c | 2506 --------------------- arch/arm/mach-tegra/tegra30_clocks.h | 54 - arch/arm/mach-tegra/tegra30_clocks_data.c | 1425 ------------ include/linux/clk/tegra.h | 2 - 11 files changed, 7141 deletions(-) delete mode 100644 arch/arm/mach-tegra/clock.c delete mode 100644 arch/arm/mach-tegra/clock.h delete mode 100644 arch/arm/mach-tegra/include/mach/clk.h delete mode 100644 arch/arm/mach-tegra/tegra20_clocks.c delete mode 100644 arch/arm/mach-tegra/tegra20_clocks.h delete mode 100644 arch/arm/mach-tegra/tegra20_clocks_data.c delete mode 100644 arch/arm/mach-tegra/tegra30_clocks.c delete mode 100644 arch/arm/mach-tegra/tegra30_clocks.h delete mode 100644 arch/arm/mach-tegra/tegra30_clocks_data.c diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index f0520961bafe..6018a05e808c 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -1,7 +1,6 @@ obj-y += common.o obj-y += io.o obj-y += irq.o -obj-y += clock.o obj-y += fuse.o obj-y += pmc.o obj-y += flowctrl.o @@ -12,16 +11,12 @@ obj-y += reset.o obj-y += reset-handler.o obj-y += sleep.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o endif -obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o -obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c deleted file mode 100644 index baa0c5b008f1..000000000000 --- a/arch/arm/mach-tegra/clock.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "board.h" -#include "clock.h" - -/* - * Locking: - * - * An additional mutex, clock_list_lock, is used to protect the list of all - * clocks. - * - */ -static DEFINE_MUTEX(clock_list_lock); -static LIST_HEAD(clocks); - -void tegra_clk_add(struct clk *clk) -{ - struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk)); - - mutex_lock(&clock_list_lock); - list_add(&c->node, &clocks); - mutex_unlock(&clock_list_lock); -} - -struct clk *tegra_get_clock_by_name(const char *name) -{ - struct clk_tegra *c; - struct clk *ret = NULL; - mutex_lock(&clock_list_lock); - list_for_each_entry(c, &clocks, node) { - if (strcmp(__clk_get_name(c->hw.clk), name) == 0) { - ret = c->hw.clk; - break; - } - } - mutex_unlock(&clock_list_lock); - return ret; -} - -static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table) -{ - struct clk *c; - struct clk *p; - struct clk *parent; - - int ret = 0; - - c = tegra_get_clock_by_name(table->name); - - if (!c) { - pr_warn("Unable to initialize clock %s\n", - table->name); - return -ENODEV; - } - - parent = clk_get_parent(c); - - if (table->parent) { - p = tegra_get_clock_by_name(table->parent); - if (!p) { - pr_warn("Unable to find parent %s of clock %s\n", - table->parent, table->name); - return -ENODEV; - } - - if (parent != p) { - ret = clk_set_parent(c, p); - if (ret) { - pr_warn("Unable to set parent %s of clock %s: %d\n", - table->parent, table->name, ret); - return -EINVAL; - } - } - } - - if (table->rate && table->rate != clk_get_rate(c)) { - ret = clk_set_rate(c, table->rate); - if (ret) { - pr_warn("Unable to set clock %s to rate %lu: %d\n", - table->name, table->rate, ret); - return -EINVAL; - } - } - - if (table->enabled) { - ret = clk_prepare_enable(c); - if (ret) { - pr_warn("Unable to enable clock %s: %d\n", - table->name, ret); - return -EINVAL; - } - } - - return 0; -} - -void tegra_clk_init_from_table(struct tegra_clk_init_table *table) -{ - for (; table->name; table++) - tegra_clk_init_one_from_table(table); -} - -/* Several extended clock configuration bits (e.g., clock routing, clock - * phase control) are included in PLL and peripheral clock source - * registers. */ -int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) -{ - int ret = 0; - struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); - - if (!clk->clk_cfg_ex) { - ret = -ENOSYS; - goto out; - } - ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting); - -out: - return ret; -} diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h deleted file mode 100644 index 2aa37f5c44c0..000000000000 --- a/arch/arm/mach-tegra/clock.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * arch/arm/mach-tegra/include/mach/clock.h - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __MACH_TEGRA_CLOCK_H -#define __MACH_TEGRA_CLOCK_H - -#include -#include -#include - -#include - -#define DIV_BUS (1 << 0) -#define DIV_U71 (1 << 1) -#define DIV_U71_FIXED (1 << 2) -#define DIV_2 (1 << 3) -#define DIV_U16 (1 << 4) -#define PLL_FIXED (1 << 5) -#define PLL_HAS_CPCON (1 << 6) -#define MUX (1 << 7) -#define PLLD (1 << 8) -#define PERIPH_NO_RESET (1 << 9) -#define PERIPH_NO_ENB (1 << 10) -#define PERIPH_EMC_ENB (1 << 11) -#define PERIPH_MANUAL_RESET (1 << 12) -#define PLL_ALT_MISC_REG (1 << 13) -#define PLLU (1 << 14) -#define PLLX (1 << 15) -#define MUX_PWM (1 << 16) -#define MUX8 (1 << 17) -#define DIV_U71_UART (1 << 18) -#define MUX_CLK_OUT (1 << 19) -#define PLLM (1 << 20) -#define DIV_U71_INT (1 << 21) -#define DIV_U71_IDLE (1 << 22) -#define ENABLE_ON_INIT (1 << 28) -#define PERIPH_ON_APB (1 << 29) - -struct clk_tegra; -#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw) - -struct clk_mux_sel { - struct clk *input; - u32 value; -}; - -struct clk_pll_freq_table { - unsigned long input_rate; - unsigned long output_rate; - u16 n; - u16 m; - u8 p; - u8 cpcon; -}; - -enum clk_state { - UNINITIALIZED = 0, - ON, - OFF, -}; - -struct clk_tegra { - /* node for master clocks list */ - struct list_head node; /* node for list of all clocks */ - struct clk_lookup lookup; - struct clk_hw hw; - - bool set; - unsigned long fixed_rate; - unsigned long max_rate; - unsigned long min_rate; - u32 flags; - const char *name; - - enum clk_state state; - u32 div; - u32 mul; - - u32 reg; - u32 reg_shift; - - struct list_head shared_bus_list; - - union { - struct { - unsigned int clk_num; - } periph; - struct { - unsigned long input_min; - unsigned long input_max; - unsigned long cf_min; - unsigned long cf_max; - unsigned long vco_min; - unsigned long vco_max; - const struct clk_pll_freq_table *freq_table; - int lock_delay; - unsigned long fixed_rate; - } pll; - struct { - u32 sel; - u32 reg_mask; - } mux; - struct { - struct clk *main; - struct clk *backup; - } cpu; - struct { - struct list_head node; - bool enabled; - unsigned long rate; - } shared_bus_user; - } u; - - void (*reset)(struct clk_hw *, bool); - int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32); -}; - -struct clk_duplicate { - const char *name; - struct clk_lookup lookup; -}; - -struct tegra_clk_init_table { - const char *name; - const char *parent; - unsigned long rate; - bool enabled; -}; - -void tegra_clk_add(struct clk *c); -void tegra2_init_clocks(void); -void tegra30_init_clocks(void); -struct clk *tegra_get_clock_by_name(const char *name); -void tegra_clk_init_from_table(struct tegra_clk_init_table *table); - -#endif diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h deleted file mode 100644 index 85bbf10a7d0d..000000000000 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * arch/arm/mach-tegra/include/mach/clk.h - * - * Copyright (C) 2010 Google, Inc. - * - * Author: - * Erik Gilling - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __MACH_CLK_H -#define __MACH_CLK_H - -struct clk; - -enum tegra_clk_ex_param { - TEGRA_CLK_VI_INP_SEL, - TEGRA_CLK_DTV_INVERT, - TEGRA_CLK_NAND_PAD_DIV2_ENB, - TEGRA_CLK_PLLD_CSI_OUT_ENB, - TEGRA_CLK_PLLD_DSI_OUT_ENB, - TEGRA_CLK_PLLD_MIPI_MUX_SEL, -}; - -#ifndef CONFIG_COMMON_CLK -unsigned long clk_get_rate_all_locked(struct clk *c); -#endif - -void tegra2_sdmmc_tap_delay(struct clk *c, int delay); -int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting); - -#endif diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c deleted file mode 100644 index 1a80ff65e5fc..000000000000 --- a/arch/arm/mach-tegra/tegra20_clocks.c +++ /dev/null @@ -1,1623 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra20_clocks.c - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clock.h" -#include "fuse.h" -#include "iomap.h" -#include "tegra2_emc.h" - -#define RST_DEVICES 0x004 -#define RST_DEVICES_SET 0x300 -#define RST_DEVICES_CLR 0x304 -#define RST_DEVICES_NUM 3 - -#define CLK_OUT_ENB 0x010 -#define CLK_OUT_ENB_SET 0x320 -#define CLK_OUT_ENB_CLR 0x324 -#define CLK_OUT_ENB_NUM 3 - -#define CLK_MASK_ARM 0x44 -#define MISC_CLK_ENB 0x48 - -#define OSC_CTRL 0x50 -#define OSC_CTRL_OSC_FREQ_MASK (3<<30) -#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30) -#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30) -#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30) -#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30) -#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) - -#define OSC_FREQ_DET 0x58 -#define OSC_FREQ_DET_TRIG (1<<31) - -#define OSC_FREQ_DET_STATUS 0x5C -#define OSC_FREQ_DET_BUSY (1<<31) -#define OSC_FREQ_DET_CNT_MASK 0xFFFF - -#define PERIPH_CLK_SOURCE_I2S1 0x100 -#define PERIPH_CLK_SOURCE_EMC 0x19c -#define PERIPH_CLK_SOURCE_OSC 0x1fc -#define PERIPH_CLK_SOURCE_NUM \ - ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4) - -#define PERIPH_CLK_SOURCE_MASK (3<<30) -#define PERIPH_CLK_SOURCE_SHIFT 30 -#define PERIPH_CLK_SOURCE_PWM_MASK (7<<28) -#define PERIPH_CLK_SOURCE_PWM_SHIFT 28 -#define PERIPH_CLK_SOURCE_ENABLE (1<<28) -#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF -#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF -#define PERIPH_CLK_SOURCE_DIV_SHIFT 0 - -#define SDMMC_CLK_INT_FB_SEL (1 << 23) -#define SDMMC_CLK_INT_FB_DLY_SHIFT 16 -#define SDMMC_CLK_INT_FB_DLY_MASK (0xF << SDMMC_CLK_INT_FB_DLY_SHIFT) - -#define PLL_BASE 0x0 -#define PLL_BASE_BYPASS (1<<31) -#define PLL_BASE_ENABLE (1<<30) -#define PLL_BASE_REF_ENABLE (1<<29) -#define PLL_BASE_OVERRIDE (1<<28) -#define PLL_BASE_DIVP_MASK (0x7<<20) -#define PLL_BASE_DIVP_SHIFT 20 -#define PLL_BASE_DIVN_MASK (0x3FF<<8) -#define PLL_BASE_DIVN_SHIFT 8 -#define PLL_BASE_DIVM_MASK (0x1F) -#define PLL_BASE_DIVM_SHIFT 0 - -#define PLL_OUT_RATIO_MASK (0xFF<<8) -#define PLL_OUT_RATIO_SHIFT 8 -#define PLL_OUT_OVERRIDE (1<<2) -#define PLL_OUT_CLKEN (1<<1) -#define PLL_OUT_RESET_DISABLE (1<<0) - -#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc) - -#define PLL_MISC_DCCON_SHIFT 20 -#define PLL_MISC_CPCON_SHIFT 8 -#define PLL_MISC_CPCON_MASK (0xF<u.periph.clk_num / 32) * 4) -#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->u.periph.clk_num / 32) * 8) -#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->u.periph.clk_num % 32)) - -#define SUPER_CLK_MUX 0x00 -#define SUPER_STATE_SHIFT 28 -#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT) -#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT) -#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT) -#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT) -#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT) -#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT) -#define SUPER_SOURCE_MASK 0xF -#define SUPER_FIQ_SOURCE_SHIFT 12 -#define SUPER_IRQ_SOURCE_SHIFT 8 -#define SUPER_RUN_SOURCE_SHIFT 4 -#define SUPER_IDLE_SOURCE_SHIFT 0 - -#define SUPER_CLK_DIVIDER 0x04 - -#define BUS_CLK_DISABLE (1<<3) -#define BUS_CLK_DIV_MASK 0x3 - -#define PMC_CTRL 0x0 - #define PMC_CTRL_BLINK_ENB (1 << 7) - -#define PMC_DPD_PADS_ORIDE 0x1c - #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20) - -#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0 -#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff -#define PMC_BLINK_TIMER_ENB (1 << 15) -#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16 -#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff - -/* Tegra CPU clock and reset control regs */ -#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c -#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 -#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 - -#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) -#define CPU_RESET(cpu) (0x1111ul << (cpu)) - -static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); -static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); - -/* - * Some clocks share a register with other clocks. Any clock op that - * non-atomically modifies a register used by another clock must lock - * clock_register_lock first. - */ -static DEFINE_SPINLOCK(clock_register_lock); - -/* - * Some peripheral clocks share an enable bit, so refcount the enable bits - * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U - */ -static int tegra_periph_clk_enable_refcount[3 * 32]; - -#define clk_writel(value, reg) \ - __raw_writel(value, reg_clk_base + (reg)) -#define clk_readl(reg) \ - __raw_readl(reg_clk_base + (reg)) -#define pmc_writel(value, reg) \ - __raw_writel(value, reg_pmc_base + (reg)) -#define pmc_readl(reg) \ - __raw_readl(reg_pmc_base + (reg)) - -static unsigned long clk_measure_input_freq(void) -{ - u32 clock_autodetect; - clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET); - do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY); - clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS); - if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) { - return 12000000; - } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) { - return 13000000; - } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) { - return 19200000; - } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) { - return 26000000; - } else { - pr_err("%s: Unexpected clock autodetect value %d", - __func__, clock_autodetect); - BUG(); - return 0; - } -} - -static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate) -{ - s64 divider_u71 = parent_rate * 2; - divider_u71 += rate - 1; - do_div(divider_u71, rate); - - if (divider_u71 - 2 < 0) - return 0; - - if (divider_u71 - 2 > 255) - return -EINVAL; - - return divider_u71 - 2; -} - -static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) -{ - s64 divider_u16; - - divider_u16 = parent_rate; - divider_u16 += rate - 1; - do_div(divider_u16, rate); - - if (divider_u16 - 1 < 0) - return 0; - - if (divider_u16 - 1 > 0xFFFF) - return -EINVAL; - - return divider_u16 - 1; -} - -static unsigned long tegra_clk_fixed_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - return to_clk_tegra(hw)->fixed_rate; -} - -struct clk_ops tegra_clk_32k_ops = { - .recalc_rate = tegra_clk_fixed_recalc_rate, -}; - -/* clk_m functions */ -static unsigned long tegra20_clk_m_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - if (!to_clk_tegra(hw)->fixed_rate) - to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq(); - return to_clk_tegra(hw)->fixed_rate; -} - -static void tegra20_clk_m_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 osc_ctrl = clk_readl(OSC_CTRL); - u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK; - - switch (c->fixed_rate) { - case 12000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ; - break; - case 13000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ; - break; - case 19200000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ; - break; - case 26000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ; - break; - default: - BUG(); - } - clk_writel(auto_clock_control, OSC_CTRL); -} - -struct clk_ops tegra_clk_m_ops = { - .init = tegra20_clk_m_init, - .recalc_rate = tegra20_clk_m_recalc_rate, -}; - -/* super clock functions */ -/* "super clocks" on tegra have two-stage muxes and a clock skipping - * super divider. We will ignore the clock skipping divider, since we - * can't lower the voltage when using the clock skip, but we can if we - * lower the PLL frequency. - */ -static int tegra20_super_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg + SUPER_CLK_MUX); - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - c->state = ON; - return c->state; -} - -static int tegra20_super_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - clk_writel(0, c->reg + SUPER_CLK_DIVIDER); - return 0; -} - -static void tegra20_super_clk_disable(struct clk_hw *hw) -{ - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - /* oops - don't disable the CPU clock! */ - BUG(); -} - -static u8 tegra20_super_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - int val = clk_readl(c->reg + SUPER_CLK_MUX); - int source; - int shift; - - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - source = (val >> shift) & SUPER_SOURCE_MASK; - return source; -} - -static int tegra20_super_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg + SUPER_CLK_MUX); - int shift; - - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - val &= ~(SUPER_SOURCE_MASK << shift); - val |= index << shift; - - clk_writel(val, c->reg); - - return 0; -} - -/* FIX ME: Need to switch parents to change the source PLL rate */ -static unsigned long tegra20_super_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - return prate; -} - -static long tegra20_super_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - return *prate; -} - -static int tegra20_super_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - return 0; -} - -struct clk_ops tegra_super_ops = { - .is_enabled = tegra20_super_clk_is_enabled, - .enable = tegra20_super_clk_enable, - .disable = tegra20_super_clk_disable, - .set_parent = tegra20_super_clk_set_parent, - .get_parent = tegra20_super_clk_get_parent, - .set_rate = tegra20_super_clk_set_rate, - .round_rate = tegra20_super_clk_round_rate, - .recalc_rate = tegra20_super_clk_recalc_rate, -}; - -static unsigned long tegra20_twd_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra_twd_ops = { - .recalc_rate = tegra20_twd_clk_recalc_rate, -}; - -static u8 tegra20_cop_clk_get_parent(struct clk_hw *hw) -{ - return 0; -} - -struct clk_ops tegra_cop_ops = { - .get_parent = tegra20_cop_clk_get_parent, -}; - -/* virtual cop clock functions. Used to acquire the fake 'cop' clock to - * reset the COP block (i.e. AVP) */ -void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert) -{ - unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR; - - pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert"); - clk_writel(1 << 1, reg); -} - -/* bus clock functions */ -static int tegra20_bus_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - - c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON; - return c->state; -} - -static int tegra20_bus_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 val; - - spin_lock_irqsave(&clock_register_lock, flags); - - val = clk_readl(c->reg); - val &= ~(BUS_CLK_DISABLE << c->reg_shift); - clk_writel(val, c->reg); - - spin_unlock_irqrestore(&clock_register_lock, flags); - - return 0; -} - -static void tegra20_bus_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 val; - - spin_lock_irqsave(&clock_register_lock, flags); - - val = clk_readl(c->reg); - val |= BUS_CLK_DISABLE << c->reg_shift; - clk_writel(val, c->reg); - - spin_unlock_irqrestore(&clock_register_lock, flags); -} - -static unsigned long tegra20_bus_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - u64 rate = prate; - - c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1; - c->mul = 1; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -static int tegra20_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - int ret = -EINVAL; - unsigned long flags; - u32 val; - int i; - - spin_lock_irqsave(&clock_register_lock, flags); - - val = clk_readl(c->reg); - for (i = 1; i <= 4; i++) { - if (rate == parent_rate / i) { - val &= ~(BUS_CLK_DIV_MASK << c->reg_shift); - val |= (i - 1) << c->reg_shift; - clk_writel(val, c->reg); - c->div = i; - c->mul = 1; - ret = 0; - break; - } - } - - spin_unlock_irqrestore(&clock_register_lock, flags); - - return ret; -} - -static long tegra20_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - s64 divider; - - if (rate >= parent_rate) - return rate; - - divider = parent_rate; - divider += rate - 1; - do_div(divider, rate); - - if (divider < 0) - return divider; - - if (divider > 4) - divider = 4; - do_div(parent_rate, divider); - - return parent_rate; -} - -struct clk_ops tegra_bus_ops = { - .is_enabled = tegra20_bus_clk_is_enabled, - .enable = tegra20_bus_clk_enable, - .disable = tegra20_bus_clk_disable, - .set_rate = tegra20_bus_clk_set_rate, - .round_rate = tegra20_bus_clk_round_rate, - .recalc_rate = tegra20_bus_clk_recalc_rate, -}; - -/* Blink output functions */ -static int tegra20_blink_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = pmc_readl(PMC_CTRL); - c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF; - return c->state; -} - -static unsigned long tegra20_blink_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = prate; - u32 val; - - c->mul = 1; - val = pmc_readl(c->reg); - - if (val & PMC_BLINK_TIMER_ENB) { - unsigned int on_off; - - on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) & - PMC_BLINK_TIMER_DATA_ON_MASK; - val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off += val; - /* each tick in the blink timer is 4 32KHz clocks */ - c->div = on_off * 4; - } else { - c->div = 1; - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -static int tegra20_blink_clk_enable(struct clk_hw *hw) -{ - u32 val; - - val = pmc_readl(PMC_DPD_PADS_ORIDE); - pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); - - val = pmc_readl(PMC_CTRL); - pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL); - - return 0; -} - -static void tegra20_blink_clk_disable(struct clk_hw *hw) -{ - u32 val; - - val = pmc_readl(PMC_CTRL); - pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL); - - val = pmc_readl(PMC_DPD_PADS_ORIDE); - pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); -} - -static int tegra20_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (rate >= parent_rate) { - c->div = 1; - pmc_writel(0, c->reg); - } else { - unsigned int on_off; - u32 val; - - on_off = DIV_ROUND_UP(parent_rate / 8, rate); - c->div = on_off * 8; - - val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) << - PMC_BLINK_TIMER_DATA_ON_SHIFT; - on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val |= on_off; - val |= PMC_BLINK_TIMER_ENB; - pmc_writel(val, c->reg); - } - - return 0; -} - -static long tegra20_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - int div; - int mul; - long round_rate = *prate; - - mul = 1; - - if (rate >= *prate) { - div = 1; - } else { - div = DIV_ROUND_UP(*prate / 8, rate); - div *= 8; - } - - round_rate *= mul; - round_rate += div - 1; - do_div(round_rate, div); - - return round_rate; -} - -struct clk_ops tegra_blink_clk_ops = { - .is_enabled = tegra20_blink_clk_is_enabled, - .enable = tegra20_blink_clk_enable, - .disable = tegra20_blink_clk_disable, - .set_rate = tegra20_blink_clk_set_rate, - .round_rate = tegra20_blink_clk_round_rate, - .recalc_rate = tegra20_blink_clk_recalc_rate, -}; - -/* PLL Functions */ -static int tegra20_pll_clk_wait_for_lock(struct clk_tegra *c) -{ - udelay(c->u.pll.lock_delay); - return 0; -} - -static int tegra20_pll_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg + PLL_BASE); - - c->state = (val & PLL_BASE_ENABLE) ? ON : OFF; - return c->state; -} - -static unsigned long tegra20_pll_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg + PLL_BASE); - u64 rate = prate; - - if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) { - const struct clk_pll_freq_table *sel; - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == prate && - sel->output_rate == c->u.pll.fixed_rate) { - c->mul = sel->n; - c->div = sel->m * sel->p; - break; - } - } - pr_err("Clock %s has unknown fixed frequency\n", - __clk_get_name(hw->clk)); - BUG(); - } else if (val & PLL_BASE_BYPASS) { - c->mul = 1; - c->div = 1; - } else { - c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT; - c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT; - if (c->flags & PLLU) - c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2; - else - c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1; - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -static int tegra20_pll_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - val = clk_readl(c->reg + PLL_BASE); - val &= ~PLL_BASE_BYPASS; - val |= PLL_BASE_ENABLE; - clk_writel(val, c->reg + PLL_BASE); - - tegra20_pll_clk_wait_for_lock(c); - - return 0; -} - -static void tegra20_pll_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - val = clk_readl(c->reg); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); - clk_writel(val, c->reg); -} - -static int tegra20_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long input_rate = parent_rate; - const struct clk_pll_freq_table *sel; - u32 val; - - pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate); - - if (c->flags & PLL_FIXED) { - int ret = 0; - if (rate != c->u.pll.fixed_rate) { - pr_err("%s: Can not change %s fixed rate %lu to %lu\n", - __func__, __clk_get_name(hw->clk), - c->u.pll.fixed_rate, rate); - ret = -EINVAL; - } - return ret; - } - - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && sel->output_rate == rate) { - c->mul = sel->n; - c->div = sel->m * sel->p; - - val = clk_readl(c->reg + PLL_BASE); - if (c->flags & PLL_FIXED) - val |= PLL_BASE_OVERRIDE; - val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK | - PLL_BASE_DIVM_MASK); - val |= (sel->m << PLL_BASE_DIVM_SHIFT) | - (sel->n << PLL_BASE_DIVN_SHIFT); - BUG_ON(sel->p < 1 || sel->p > 2); - if (c->flags & PLLU) { - if (sel->p == 1) - val |= PLLU_BASE_POST_DIV; - } else { - if (sel->p == 2) - val |= 1 << PLL_BASE_DIVP_SHIFT; - } - clk_writel(val, c->reg + PLL_BASE); - - if (c->flags & PLL_HAS_CPCON) { - val = clk_readl(c->reg + PLL_MISC(c)); - val &= ~PLL_MISC_CPCON_MASK; - val |= sel->cpcon << PLL_MISC_CPCON_SHIFT; - clk_writel(val, c->reg + PLL_MISC(c)); - } - - if (c->state == ON) - tegra20_pll_clk_enable(hw); - return 0; - } - } - return -EINVAL; -} - -static long tegra20_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - const struct clk_pll_freq_table *sel; - unsigned long input_rate = *prate; - u64 output_rate = *prate; - int mul; - int div; - - if (c->flags & PLL_FIXED) - return c->u.pll.fixed_rate; - - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) - if (sel->input_rate == input_rate && sel->output_rate == rate) { - mul = sel->n; - div = sel->m * sel->p; - break; - } - - if (sel->input_rate == 0) - return -EINVAL; - - output_rate *= mul; - output_rate += div - 1; /* round up */ - do_div(output_rate, div); - - return output_rate; -} - -struct clk_ops tegra_pll_ops = { - .is_enabled = tegra20_pll_clk_is_enabled, - .enable = tegra20_pll_clk_enable, - .disable = tegra20_pll_clk_disable, - .set_rate = tegra20_pll_clk_set_rate, - .recalc_rate = tegra20_pll_clk_recalc_rate, - .round_rate = tegra20_pll_clk_round_rate, -}; - -static void tegra20_pllx_clk_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (tegra_sku_id == 7) - c->max_rate = 750000000; -} - -struct clk_ops tegra_pllx_ops = { - .init = tegra20_pllx_clk_init, - .is_enabled = tegra20_pll_clk_is_enabled, - .enable = tegra20_pll_clk_enable, - .disable = tegra20_pll_clk_disable, - .set_rate = tegra20_pll_clk_set_rate, - .recalc_rate = tegra20_pll_clk_recalc_rate, - .round_rate = tegra20_pll_clk_round_rate, -}; - -static int tegra20_plle_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - mdelay(1); - - val = clk_readl(c->reg + PLL_BASE); - if (!(val & PLLE_MISC_READY)) - return -EBUSY; - - val = clk_readl(c->reg + PLL_BASE); - val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS; - clk_writel(val, c->reg + PLL_BASE); - - return 0; -} - -struct clk_ops tegra_plle_ops = { - .is_enabled = tegra20_pll_clk_is_enabled, - .enable = tegra20_plle_clk_enable, - .set_rate = tegra20_pll_clk_set_rate, - .recalc_rate = tegra20_pll_clk_recalc_rate, - .round_rate = tegra20_pll_clk_round_rate, -}; - -/* Clock divider ops */ -static int tegra20_pll_div_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - - val >>= c->reg_shift; - c->state = (val & PLL_OUT_CLKEN) ? ON : OFF; - if (!(val & PLL_OUT_RESET_DISABLE)) - c->state = OFF; - return c->state; -} - -static unsigned long tegra20_pll_div_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = prate; - u32 val = clk_readl(c->reg); - u32 divu71; - - val >>= c->reg_shift; - - if (c->flags & DIV_U71) { - divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT; - c->div = (divu71 + 2); - c->mul = 2; - } else if (c->flags & DIV_2) { - c->div = 2; - c->mul = 1; - } else { - c->div = 1; - c->mul = 1; - } - - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - - return rate; -} - -static int tegra20_pll_div_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 new_val; - u32 val; - - pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); - - if (c->flags & DIV_U71) { - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - - new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE; - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel(val, c->reg); - spin_unlock_irqrestore(&clock_register_lock, flags); - return 0; - } else if (c->flags & DIV_2) { - BUG_ON(!(c->flags & PLLD)); - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - val &= ~PLLD_MISC_DIV_RST; - clk_writel(val, c->reg); - spin_unlock_irqrestore(&clock_register_lock, flags); - return 0; - } - return -EINVAL; -} - -static void tegra20_pll_div_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 new_val; - u32 val; - - pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); - - if (c->flags & DIV_U71) { - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - - new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE); - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel(val, c->reg); - spin_unlock_irqrestore(&clock_register_lock, flags); - } else if (c->flags & DIV_2) { - BUG_ON(!(c->flags & PLLD)); - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - val |= PLLD_MISC_DIV_RST; - clk_writel(val, c->reg); - spin_unlock_irqrestore(&clock_register_lock, flags); - } -} - -static int tegra20_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - int divider_u71; - u32 new_val; - u32 val; - - pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate); - - if (c->flags & DIV_U71) { - divider_u71 = clk_div71_get_divider(parent_rate, rate); - if (divider_u71 >= 0) { - spin_lock_irqsave(&clock_register_lock, flags); - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - if (c->flags & DIV_U71_FIXED) - new_val |= PLL_OUT_OVERRIDE; - new_val &= ~PLL_OUT_RATIO_MASK; - new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT; - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel(val, c->reg); - c->div = divider_u71 + 2; - c->mul = 2; - spin_unlock_irqrestore(&clock_register_lock, flags); - return 0; - } - } else if (c->flags & DIV_2) { - if (parent_rate == rate * 2) - return 0; - } - return -EINVAL; -} - -static long tegra20_pll_div_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long parent_rate = *prate; - int divider; - - pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate); - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider(parent_rate, rate); - if (divider < 0) - return divider; - return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_2) { - return DIV_ROUND_UP(parent_rate, 2); - } - return -EINVAL; -} - -struct clk_ops tegra_pll_div_ops = { - .is_enabled = tegra20_pll_div_clk_is_enabled, - .enable = tegra20_pll_div_clk_enable, - .disable = tegra20_pll_div_clk_disable, - .set_rate = tegra20_pll_div_clk_set_rate, - .round_rate = tegra20_pll_div_clk_round_rate, - .recalc_rate = tegra20_pll_div_clk_recalc_rate, -}; - -/* Periph clk ops */ - -static int tegra20_periph_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - c->state = ON; - - if (!c->u.periph.clk_num) - goto out; - - if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) & - PERIPH_CLK_TO_ENB_BIT(c))) - c->state = OFF; - - if (!(c->flags & PERIPH_NO_RESET)) - if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) & - PERIPH_CLK_TO_ENB_BIT(c)) - c->state = OFF; - -out: - return c->state; -} - -static int tegra20_periph_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - u32 val; - - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - if (!c->u.periph.clk_num) - return 0; - - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1) - return 0; - - spin_lock_irqsave(&clock_register_lock, flags); - - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c)); - if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET)) - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); - if (c->flags & PERIPH_EMC_ENB) { - /* The EMC peripheral clock has 2 extra enable bits */ - /* FIXME: Do they need to be disabled? */ - val = clk_readl(c->reg); - val |= 0x3 << 24; - clk_writel(val, c->reg); - } - - spin_unlock_irqrestore(&clock_register_lock, flags); - - return 0; -} - -static void tegra20_periph_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long flags; - - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - if (!c->u.periph.clk_num) - return; - - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; - - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0) - return; - - spin_lock_irqsave(&clock_register_lock, flags); - - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); - - spin_unlock_irqrestore(&clock_register_lock, flags); -} - -void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR; - - pr_debug("%s %s on clock %s\n", __func__, - assert ? "assert" : "deassert", __clk_get_name(hw->clk)); - - BUG_ON(!c->u.periph.clk_num); - - if (!(c->flags & PERIPH_NO_RESET)) - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - base + PERIPH_CLK_TO_ENB_SET_REG(c)); -} - -static int tegra20_periph_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - u32 mask; - u32 shift; - - pr_debug("%s: %s %d\n", __func__, __clk_get_name(hw->clk), index); - - if (c->flags & MUX_PWM) { - shift = PERIPH_CLK_SOURCE_PWM_SHIFT; - mask = PERIPH_CLK_SOURCE_PWM_MASK; - } else { - shift = PERIPH_CLK_SOURCE_SHIFT; - mask = PERIPH_CLK_SOURCE_MASK; - } - - val = clk_readl(c->reg); - val &= ~mask; - val |= (index) << shift; - - clk_writel(val, c->reg); - - return 0; -} - -static u8 tegra20_periph_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - u32 mask; - u32 shift; - - if (c->flags & MUX_PWM) { - shift = PERIPH_CLK_SOURCE_PWM_SHIFT; - mask = PERIPH_CLK_SOURCE_PWM_MASK; - } else { - shift = PERIPH_CLK_SOURCE_SHIFT; - mask = PERIPH_CLK_SOURCE_MASK; - } - - if (c->flags & MUX) - return (val & mask) >> shift; - else - return 0; -} - -static unsigned long tegra20_periph_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long rate = prate; - u32 val = clk_readl(c->reg); - - if (c->flags & DIV_U71) { - u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; - c->div = divu71 + 2; - c->mul = 2; - } else if (c->flags & DIV_U16) { - u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; - c->div = divu16 + 1; - c->mul = 1; - } else { - c->div = 1; - c->mul = 1; - return rate; - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -static int tegra20_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - int divider; - - val = clk_readl(c->reg); - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider(parent_rate, rate); - - if (divider >= 0) { - val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; - val |= divider; - clk_writel(val, c->reg); - c->div = divider + 2; - c->mul = 2; - return 0; - } - } else if (c->flags & DIV_U16) { - divider = clk_div16_get_divider(parent_rate, rate); - if (divider >= 0) { - val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; - val |= divider; - clk_writel(val, c->reg); - c->div = divider + 1; - c->mul = 1; - return 0; - } - } else if (parent_rate <= rate) { - c->div = 1; - c->mul = 1; - return 0; - } - - return -EINVAL; -} - -static long tegra20_periph_clk_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); - int divider; - - pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate); - - if (prate) - parent_rate = *prate; - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider(parent_rate, rate); - if (divider < 0) - return divider; - - return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_U16) { - divider = clk_div16_get_divider(parent_rate, rate); - if (divider < 0) - return divider; - return DIV_ROUND_UP(parent_rate, divider + 1); - } - return -EINVAL; -} - -struct clk_ops tegra_periph_clk_ops = { - .is_enabled = tegra20_periph_clk_is_enabled, - .enable = tegra20_periph_clk_enable, - .disable = tegra20_periph_clk_disable, - .set_parent = tegra20_periph_clk_set_parent, - .get_parent = tegra20_periph_clk_get_parent, - .set_rate = tegra20_periph_clk_set_rate, - .round_rate = tegra20_periph_clk_round_rate, - .recalc_rate = tegra20_periph_clk_recalc_rate, -}; - -/* External memory controller clock ops */ -static void tegra20_emc_clk_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - c->max_rate = __clk_get_rate(hw->clk); -} - -static long tegra20_emc_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - long emc_rate; - long clk_rate; - - /* - * The slowest entry in the EMC clock table that is at least as - * fast as rate. - */ - emc_rate = tegra_emc_round_rate(rate); - if (emc_rate < 0) - return c->max_rate; - - /* - * The fastest rate the PLL will generate that is at most the - * requested rate. - */ - clk_rate = tegra20_periph_clk_round_rate(hw, emc_rate, NULL); - - /* - * If this fails, and emc_rate > clk_rate, it's because the maximum - * rate in the EMC tables is larger than the maximum rate of the EMC - * clock. The EMC clock's max rate is the rate it was running when the - * kernel booted. Such a mismatch is probably due to using the wrong - * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25. - */ - WARN_ONCE(emc_rate != clk_rate, - "emc_rate %ld != clk_rate %ld", - emc_rate, clk_rate); - - return emc_rate; -} - -static int tegra20_emc_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - int ret; - - /* - * The Tegra2 memory controller has an interlock with the clock - * block that allows memory shadowed registers to be updated, - * and then transfer them to the main registers at the same - * time as the clock update without glitches. - */ - ret = tegra_emc_set_rate(rate); - if (ret < 0) - return ret; - - ret = tegra20_periph_clk_set_rate(hw, rate, parent_rate); - udelay(1); - - return ret; -} - -struct clk_ops tegra_emc_clk_ops = { - .init = tegra20_emc_clk_init, - .is_enabled = tegra20_periph_clk_is_enabled, - .enable = tegra20_periph_clk_enable, - .disable = tegra20_periph_clk_disable, - .set_parent = tegra20_periph_clk_set_parent, - .get_parent = tegra20_periph_clk_get_parent, - .set_rate = tegra20_emc_clk_set_rate, - .round_rate = tegra20_emc_clk_round_rate, - .recalc_rate = tegra20_periph_clk_recalc_rate, -}; - -/* Clock doubler ops */ -static int tegra20_clk_double_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - c->state = ON; - - if (!c->u.periph.clk_num) - goto out; - - if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) & - PERIPH_CLK_TO_ENB_BIT(c))) - c->state = OFF; - -out: - return c->state; -}; - -static unsigned long tegra20_clk_double_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = prate; - - c->mul = 2; - c->div = 1; - - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - - return rate; -} - -static long tegra20_clk_double_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - unsigned long output_rate = *prate; - - do_div(output_rate, 2); - return output_rate; -} - -static int tegra20_clk_double_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - if (rate != 2 * parent_rate) - return -EINVAL; - return 0; -} - -struct clk_ops tegra_clk_double_ops = { - .is_enabled = tegra20_clk_double_is_enabled, - .enable = tegra20_periph_clk_enable, - .disable = tegra20_periph_clk_disable, - .set_rate = tegra20_clk_double_set_rate, - .recalc_rate = tegra20_clk_double_recalc_rate, - .round_rate = tegra20_clk_double_round_rate, -}; - -/* Audio sync clock ops */ -static int tegra20_audio_sync_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - - c->state = (val & (1<<4)) ? OFF : ON; - return c->state; -} - -static int tegra20_audio_sync_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - clk_writel(0, c->reg); - return 0; -} - -static void tegra20_audio_sync_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - clk_writel(1, c->reg); -} - -static u8 tegra20_audio_sync_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - int source; - - source = val & 0xf; - return source; -} - -static int tegra20_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg); - val &= ~0xf; - val |= index; - - clk_writel(val, c->reg); - - return 0; -} - -struct clk_ops tegra_audio_sync_clk_ops = { - .is_enabled = tegra20_audio_sync_clk_is_enabled, - .enable = tegra20_audio_sync_clk_enable, - .disable = tegra20_audio_sync_clk_disable, - .set_parent = tegra20_audio_sync_clk_set_parent, - .get_parent = tegra20_audio_sync_clk_get_parent, -}; - -/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */ - -static int tegra20_cdev_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - /* We could un-tristate the cdev1 or cdev2 pingroup here; this is - * currently done in the pinmux code. */ - c->state = ON; - - BUG_ON(!c->u.periph.clk_num); - - if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) & - PERIPH_CLK_TO_ENB_BIT(c))) - c->state = OFF; - return c->state; -} - -static int tegra20_cdev_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - BUG_ON(!c->u.periph.clk_num); - - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c)); - return 0; -} - -static void tegra20_cdev_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - BUG_ON(!c->u.periph.clk_num); - - clk_writel(PERIPH_CLK_TO_ENB_BIT(c), - CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); -} - -static unsigned long tegra20_cdev_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - return to_clk_tegra(hw)->fixed_rate; -} - -struct clk_ops tegra_cdev_clk_ops = { - .is_enabled = tegra20_cdev_clk_is_enabled, - .enable = tegra20_cdev_clk_enable, - .disable = tegra20_cdev_clk_disable, - .recalc_rate = tegra20_cdev_recalc_rate, -}; - -/* Tegra20 CPU clock and reset control functions */ -static void tegra20_wait_cpu_in_reset(u32 cpu) -{ - unsigned int reg; - - do { - reg = readl(reg_clk_base + - TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); - cpu_relax(); - } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ - - return; -} - -static void tegra20_put_cpu_in_reset(u32 cpu) -{ - writel(CPU_RESET(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); - dmb(); -} - -static void tegra20_cpu_out_of_reset(u32 cpu) -{ - writel(CPU_RESET(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); - wmb(); -} - -static void tegra20_enable_cpu_clock(u32 cpu) -{ - unsigned int reg; - - reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - writel(reg & ~CPU_CLOCK(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - barrier(); - reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); -} - -static void tegra20_disable_cpu_clock(u32 cpu) -{ - unsigned int reg; - - reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - writel(reg | CPU_CLOCK(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); -} - -static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { - .wait_for_reset = tegra20_wait_cpu_in_reset, - .put_in_reset = tegra20_put_cpu_in_reset, - .out_of_reset = tegra20_cpu_out_of_reset, - .enable_clock = tegra20_enable_cpu_clock, - .disable_clock = tegra20_disable_cpu_clock, -}; - -void __init tegra20_cpu_car_ops_init(void) -{ - tegra_cpu_car_ops = &tegra20_cpu_car_ops; -} diff --git a/arch/arm/mach-tegra/tegra20_clocks.h b/arch/arm/mach-tegra/tegra20_clocks.h deleted file mode 100644 index 8bfd31bcc490..000000000000 --- a/arch/arm/mach-tegra/tegra20_clocks.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __MACH_TEGRA20_CLOCK_H -#define __MACH_TEGRA20_CLOCK_H - -extern struct clk_ops tegra_clk_32k_ops; -extern struct clk_ops tegra_pll_ops; -extern struct clk_ops tegra_clk_m_ops; -extern struct clk_ops tegra_pll_div_ops; -extern struct clk_ops tegra_pllx_ops; -extern struct clk_ops tegra_plle_ops; -extern struct clk_ops tegra_clk_double_ops; -extern struct clk_ops tegra_cdev_clk_ops; -extern struct clk_ops tegra_audio_sync_clk_ops; -extern struct clk_ops tegra_super_ops; -extern struct clk_ops tegra_cpu_ops; -extern struct clk_ops tegra_twd_ops; -extern struct clk_ops tegra_cop_ops; -extern struct clk_ops tegra_bus_ops; -extern struct clk_ops tegra_blink_clk_ops; -extern struct clk_ops tegra_emc_clk_ops; -extern struct clk_ops tegra_periph_clk_ops; -extern struct clk_ops tegra_clk_shared_bus_ops; - -void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert); -void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert); - -#endif diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c deleted file mode 100644 index 022cdaef7ca5..000000000000 --- a/arch/arm/mach-tegra/tegra20_clocks_data.c +++ /dev/null @@ -1,1143 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra2_clocks.c - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clock.h" -#include "fuse.h" -#include "tegra2_emc.h" -#include "tegra20_clocks.h" - -/* Clock definitions */ - -#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ - _parent_names, _parents, _parent) \ - static struct clk tegra_##_name = { \ - .hw = &tegra_##_name##_hw.hw, \ - .name = #_name, \ - .rate = _rate, \ - .ops = _ops, \ - .flags = _flags, \ - .parent_names = _parent_names, \ - .parents = _parents, \ - .num_parents = ARRAY_SIZE(_parent_names), \ - .parent = _parent, \ - }; - -static struct clk tegra_clk_32k; -static struct clk_tegra tegra_clk_32k_hw = { - .hw = { - .clk = &tegra_clk_32k, - }, - .fixed_rate = 32768, -}; - -static struct clk tegra_clk_32k = { - .name = "clk_32k", - .rate = 32768, - .ops = &tegra_clk_32k_ops, - .hw = &tegra_clk_32k_hw.hw, - .flags = CLK_IS_ROOT, -}; - -static struct clk tegra_clk_m; -static struct clk_tegra tegra_clk_m_hw = { - .hw = { - .clk = &tegra_clk_m, - }, - .flags = ENABLE_ON_INIT, - .reg = 0x1fc, - .reg_shift = 28, - .max_rate = 26000000, - .fixed_rate = 0, -}; - -static struct clk tegra_clk_m = { - .name = "clk_m", - .ops = &tegra_clk_m_ops, - .hw = &tegra_clk_m_hw.hw, - .flags = CLK_IS_ROOT, -}; - -#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \ - _input_max, _cf_min, _cf_max, _vco_min, \ - _vco_max, _freq_table, _lock_delay, _ops, \ - _fixed_rate, _parent) \ - static const char *tegra_##_name##_parent_names[] = { \ - #_parent, \ - }; \ - static struct clk *tegra_##_name##_parents[] = { \ - &tegra_##_parent, \ - }; \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .flags = _flags, \ - .reg = _reg, \ - .max_rate = _max_rate, \ - .u.pll = { \ - .input_min = _input_min, \ - .input_max = _input_max, \ - .cf_min = _cf_min, \ - .cf_max = _cf_max, \ - .vco_min = _vco_min, \ - .vco_max = _vco_max, \ - .freq_table = _freq_table, \ - .lock_delay = _lock_delay, \ - .fixed_rate = _fixed_rate, \ - }, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent = &tegra_##_parent, \ - .parent_names = tegra_##_name##_parent_names, \ - .parents = tegra_##_name##_parents, \ - .num_parents = 1, \ - }; - -#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \ - _max_rate, _ops, _parent, _clk_flags) \ - static const char *tegra_##_name##_parent_names[] = { \ - #_parent, \ - }; \ - static struct clk *tegra_##_name##_parents[] = { \ - &tegra_##_parent, \ - }; \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .flags = _flags, \ - .reg = _reg, \ - .max_rate = _max_rate, \ - .reg_shift = _reg_shift, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra_pll_div_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent = &tegra_##_parent, \ - .parent_names = tegra_##_name##_parent_names, \ - .parents = tegra_##_name##_parents, \ - .num_parents = 1, \ - .flags = _clk_flags, \ - }; - - -static struct clk_pll_freq_table tegra_pll_s_freq_table[] = { - {32768, 12000000, 366, 1, 1, 0}, - {32768, 13000000, 397, 1, 1, 0}, - {32768, 19200000, 586, 1, 1, 0}, - {32768, 26000000, 793, 1, 1, 0}, - {0, 0, 0, 0, 0, 0}, -}; - -DEFINE_PLL(pll_s, PLL_ALT_MISC_REG, 0xf0, 26000000, 32768, 32768, 0, - 0, 12000000, 26000000, tegra_pll_s_freq_table, 300, - tegra_pll_ops, 0, clk_32k); - -static struct clk_pll_freq_table tegra_pll_c_freq_table[] = { - { 12000000, 600000000, 600, 12, 1, 8 }, - { 13000000, 600000000, 600, 13, 1, 8 }, - { 19200000, 600000000, 500, 16, 1, 6 }, - { 26000000, 600000000, 600, 26, 1, 8 }, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 600000000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300, - tegra_pll_ops, 0, clk_m); - -DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 600000000, - tegra_pll_div_ops, pll_c, 0); - -static struct clk_pll_freq_table tegra_pll_m_freq_table[] = { - { 12000000, 666000000, 666, 12, 1, 8}, - { 13000000, 666000000, 666, 13, 1, 8}, - { 19200000, 666000000, 555, 16, 1, 8}, - { 26000000, 666000000, 666, 26, 1, 8}, - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_m, PLL_HAS_CPCON, 0x90, 800000000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1200000000, tegra_pll_m_freq_table, 300, - tegra_pll_ops, 0, clk_m); - -DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000, - tegra_pll_div_ops, pll_m, 0); - -static struct clk_pll_freq_table tegra_pll_p_freq_table[] = { - { 12000000, 216000000, 432, 12, 2, 8}, - { 13000000, 216000000, 432, 13, 2, 8}, - { 19200000, 216000000, 90, 4, 2, 1}, - { 26000000, 216000000, 432, 26, 2, 8}, - { 12000000, 432000000, 432, 12, 1, 8}, - { 13000000, 432000000, 432, 13, 1, 8}, - { 19200000, 432000000, 90, 4, 1, 1}, - { 26000000, 432000000, 432, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - - -DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000, - 2000000, 31000000, 1000000, 6000000, 20000000, 1400000000, - tegra_pll_p_freq_table, 300, tegra_pll_ops, 216000000, clk_m); - -DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 0, - 432000000, tegra_pll_div_ops, pll_p, 0); -DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 16, - 432000000, tegra_pll_div_ops, pll_p, 0); -DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 0, - 432000000, tegra_pll_div_ops, pll_p, 0); -DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 16, - 432000000, tegra_pll_div_ops, pll_p, 0); - -static struct clk_pll_freq_table tegra_pll_a_freq_table[] = { - { 28800000, 56448000, 49, 25, 1, 1}, - { 28800000, 73728000, 64, 25, 1, 1}, - { 28800000, 24000000, 5, 6, 1, 1}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 73728000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1400000000, tegra_pll_a_freq_table, 300, - tegra_pll_ops, 0, pll_p_out1); - -DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 73728000, - tegra_pll_div_ops, pll_a, 0); - -static struct clk_pll_freq_table tegra_pll_d_freq_table[] = { - { 12000000, 216000000, 216, 12, 1, 4}, - { 13000000, 216000000, 216, 13, 1, 4}, - { 19200000, 216000000, 135, 12, 1, 3}, - { 26000000, 216000000, 216, 26, 1, 4}, - - { 12000000, 297000000, 99, 4, 1, 4 }, - { 12000000, 339000000, 113, 4, 1, 4 }, - - { 12000000, 594000000, 594, 12, 1, 8}, - { 13000000, 594000000, 594, 13, 1, 8}, - { 19200000, 594000000, 495, 16, 1, 8}, - { 26000000, 594000000, 594, 26, 1, 8}, - - { 12000000, 616000000, 616, 12, 1, 8}, - - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000, - 1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table, - 1000, tegra_pll_ops, 0, clk_m); - -DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, - tegra_pll_div_ops, pll_d, CLK_SET_RATE_PARENT); - -static struct clk_pll_freq_table tegra_pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 2, 0}, - { 13000000, 480000000, 960, 13, 2, 0}, - { 19200000, 480000000, 200, 4, 2, 0}, - { 26000000, 480000000, 960, 26, 2, 0}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_u, PLLU, 0xc0, 480000000, 2000000, 40000000, 1000000, 6000000, - 48000000, 960000000, tegra_pll_u_freq_table, 1000, - tegra_pll_ops, 0, clk_m); - -static struct clk_pll_freq_table tegra_pll_x_freq_table[] = { - /* 1 GHz */ - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, - - /* 912 MHz */ - { 12000000, 912000000, 912, 12, 1, 12}, - { 13000000, 912000000, 912, 13, 1, 12}, - { 19200000, 912000000, 760, 16, 1, 8}, - { 26000000, 912000000, 912, 26, 1, 12}, - - /* 816 MHz */ - { 12000000, 816000000, 816, 12, 1, 12}, - { 13000000, 816000000, 816, 13, 1, 12}, - { 19200000, 816000000, 680, 16, 1, 8}, - { 26000000, 816000000, 816, 26, 1, 12}, - - /* 760 MHz */ - { 12000000, 760000000, 760, 12, 1, 12}, - { 13000000, 760000000, 760, 13, 1, 12}, - { 19200000, 760000000, 950, 24, 1, 8}, - { 26000000, 760000000, 760, 26, 1, 12}, - - /* 750 MHz */ - { 12000000, 750000000, 750, 12, 1, 12}, - { 13000000, 750000000, 750, 13, 1, 12}, - { 19200000, 750000000, 625, 16, 1, 8}, - { 26000000, 750000000, 750, 26, 1, 12}, - - /* 608 MHz */ - { 12000000, 608000000, 608, 12, 1, 12}, - { 13000000, 608000000, 608, 13, 1, 12}, - { 19200000, 608000000, 380, 12, 1, 8}, - { 26000000, 608000000, 608, 26, 1, 12}, - - /* 456 MHz */ - { 12000000, 456000000, 456, 12, 1, 12}, - { 13000000, 456000000, 456, 13, 1, 12}, - { 19200000, 456000000, 380, 16, 1, 8}, - { 26000000, 456000000, 456, 26, 1, 12}, - - /* 312 MHz */ - { 12000000, 312000000, 312, 12, 1, 12}, - { 13000000, 312000000, 312, 13, 1, 12}, - { 19200000, 312000000, 260, 16, 1, 8}, - { 26000000, 312000000, 312, 26, 1, 12}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG, 0xe0, 1000000000, 2000000, - 31000000, 1000000, 6000000, 20000000, 1200000000, - tegra_pll_x_freq_table, 300, tegra_pllx_ops, 0, clk_m); - -static struct clk_pll_freq_table tegra_pll_e_freq_table[] = { - { 12000000, 100000000, 200, 24, 1, 0 }, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 12000000, 12000000, 0, 0, - 0, 0, tegra_pll_e_freq_table, 0, tegra_plle_ops, 0, clk_m); - -static const char *tegra_common_parent_names[] = { - "clk_m", -}; - -static struct clk *tegra_common_parents[] = { - &tegra_clk_m, -}; - -static struct clk tegra_clk_d; -static struct clk_tegra tegra_clk_d_hw = { - .hw = { - .clk = &tegra_clk_d, - }, - .flags = PERIPH_NO_RESET, - .reg = 0x34, - .reg_shift = 12, - .max_rate = 52000000, - .u.periph = { - .clk_num = 90, - }, -}; - -static struct clk tegra_clk_d = { - .name = "clk_d", - .hw = &tegra_clk_d_hw.hw, - .ops = &tegra_clk_double_ops, - .parent = &tegra_clk_m, - .parent_names = tegra_common_parent_names, - .parents = tegra_common_parents, - .num_parents = ARRAY_SIZE(tegra_common_parent_names), -}; - -static struct clk tegra_cdev1; -static struct clk_tegra tegra_cdev1_hw = { - .hw = { - .clk = &tegra_cdev1, - }, - .fixed_rate = 26000000, - .u.periph = { - .clk_num = 94, - }, -}; -static struct clk tegra_cdev1 = { - .name = "cdev1", - .hw = &tegra_cdev1_hw.hw, - .ops = &tegra_cdev_clk_ops, - .flags = CLK_IS_ROOT, -}; - -/* dap_mclk2, belongs to the cdev2 pingroup. */ -static struct clk tegra_cdev2; -static struct clk_tegra tegra_cdev2_hw = { - .hw = { - .clk = &tegra_cdev2, - }, - .fixed_rate = 26000000, - .u.periph = { - .clk_num = 93, - }, -}; -static struct clk tegra_cdev2 = { - .name = "cdev2", - .hw = &tegra_cdev2_hw.hw, - .ops = &tegra_cdev_clk_ops, - .flags = CLK_IS_ROOT, -}; - -/* initialized before peripheral clocks */ -static struct clk_mux_sel mux_audio_sync_clk[8+1]; -static const struct audio_sources { - const char *name; - int value; -} mux_audio_sync_clk_sources[] = { - { .name = "spdif_in", .value = 0 }, - { .name = "i2s1", .value = 1 }, - { .name = "i2s2", .value = 2 }, - { .name = "pll_a_out0", .value = 4 }, -#if 0 /* FIXME: not implemented */ - { .name = "ac97", .value = 3 }, - { .name = "ext_audio_clk2", .value = 5 }, - { .name = "ext_audio_clk1", .value = 6 }, - { .name = "ext_vimclk", .value = 7 }, -#endif - { NULL, 0 } -}; - -static const char *audio_parent_names[] = { - "spdif_in", - "i2s1", - "i2s2", - "dummy", - "pll_a_out0", - "dummy", - "dummy", - "dummy", -}; - -static struct clk *audio_parents[] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, -}; - -static struct clk tegra_audio; -static struct clk_tegra tegra_audio_hw = { - .hw = { - .clk = &tegra_audio, - }, - .reg = 0x38, - .max_rate = 73728000, -}; -DEFINE_CLK_TEGRA(audio, 0, &tegra_audio_sync_clk_ops, 0, audio_parent_names, - audio_parents, NULL); - -static const char *audio_2x_parent_names[] = { - "audio", -}; - -static struct clk *audio_2x_parents[] = { - &tegra_audio, -}; - -static struct clk tegra_audio_2x; -static struct clk_tegra tegra_audio_2x_hw = { - .hw = { - .clk = &tegra_audio_2x, - }, - .flags = PERIPH_NO_RESET, - .max_rate = 48000000, - .reg = 0x34, - .reg_shift = 8, - .u.periph = { - .clk_num = 89, - }, -}; -DEFINE_CLK_TEGRA(audio_2x, 0, &tegra_clk_double_ops, 0, audio_2x_parent_names, - audio_2x_parents, &tegra_audio); - -static struct clk_lookup tegra_audio_clk_lookups[] = { - { .con_id = "audio", .clk = &tegra_audio }, - { .con_id = "audio_2x", .clk = &tegra_audio_2x } -}; - -/* This is called after peripheral clocks are initialized, as the - * audio_sync clock depends on some of the peripheral clocks. - */ - -static void init_audio_sync_clock_mux(void) -{ - int i; - struct clk_mux_sel *sel = mux_audio_sync_clk; - const struct audio_sources *src = mux_audio_sync_clk_sources; - struct clk_lookup *lookup; - - for (i = 0; src->name; i++, sel++, src++) { - sel->input = tegra_get_clock_by_name(src->name); - if (!sel->input) - pr_err("%s: could not find clk %s\n", __func__, - src->name); - audio_parents[src->value] = sel->input; - sel->value = src->value; - } - - lookup = tegra_audio_clk_lookups; - for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) { - struct clk *c = lookup->clk; - struct clk_tegra *clk = to_clk_tegra(c->hw); - __clk_init(NULL, c); - INIT_LIST_HEAD(&clk->shared_bus_list); - clk->lookup.con_id = lookup->con_id; - clk->lookup.clk = c; - clkdev_add(&clk->lookup); - tegra_clk_add(c); - } -} - -static const char *mux_cclk[] = { - "clk_m", - "pll_c", - "clk_32k", - "pll_m", - "pll_p", - "pll_p_out4", - "pll_p_out3", - "clk_d", - "pll_x", -}; - - -static struct clk *mux_cclk_p[] = { - &tegra_clk_m, - &tegra_pll_c, - &tegra_clk_32k, - &tegra_pll_m, - &tegra_pll_p, - &tegra_pll_p_out4, - &tegra_pll_p_out3, - &tegra_clk_d, - &tegra_pll_x, -}; - -static const char *mux_sclk[] = { - "clk_m", - "pll_c_out1", - "pll_p_out4", - "pllp_p_out3", - "pll_p_out2", - "clk_d", - "clk_32k", - "pll_m_out1", -}; - -static struct clk *mux_sclk_p[] = { - &tegra_clk_m, - &tegra_pll_c_out1, - &tegra_pll_p_out4, - &tegra_pll_p_out3, - &tegra_pll_p_out2, - &tegra_clk_d, - &tegra_clk_32k, - &tegra_pll_m_out1, -}; - -static struct clk tegra_cclk; -static struct clk_tegra tegra_cclk_hw = { - .hw = { - .clk = &tegra_cclk, - }, - .reg = 0x20, - .max_rate = 1000000000, -}; -DEFINE_CLK_TEGRA(cclk, 0, &tegra_super_ops, 0, mux_cclk, - mux_cclk_p, NULL); - -static const char *mux_twd[] = { - "cclk", -}; - -static struct clk *mux_twd_p[] = { - &tegra_cclk, -}; - -static struct clk tegra_clk_twd; -static struct clk_tegra tegra_clk_twd_hw = { - .hw = { - .clk = &tegra_clk_twd, - }, - .max_rate = 1000000000, - .mul = 1, - .div = 4, -}; - -static struct clk tegra_clk_twd = { - .name = "twd", - .ops = &tegra_twd_ops, - .hw = &tegra_clk_twd_hw.hw, - .parent = &tegra_cclk, - .parent_names = mux_twd, - .parents = mux_twd_p, - .num_parents = ARRAY_SIZE(mux_twd), -}; - -static struct clk tegra_sclk; -static struct clk_tegra tegra_sclk_hw = { - .hw = { - .clk = &tegra_sclk, - }, - .reg = 0x28, - .max_rate = 240000000, - .min_rate = 120000000, -}; -DEFINE_CLK_TEGRA(sclk, 0, &tegra_super_ops, 0, mux_sclk, - mux_sclk_p, NULL); - -static const char *tegra_cop_parent_names[] = { - "tegra_sclk", -}; - -static struct clk *tegra_cop_parents[] = { - &tegra_sclk, -}; - -static struct clk tegra_cop; -static struct clk_tegra tegra_cop_hw = { - .hw = { - .clk = &tegra_cop, - }, - .max_rate = 240000000, - .reset = &tegra2_cop_clk_reset, -}; -DEFINE_CLK_TEGRA(cop, 0, &tegra_cop_ops, CLK_SET_RATE_PARENT, - tegra_cop_parent_names, tegra_cop_parents, &tegra_sclk); - -static const char *tegra_hclk_parent_names[] = { - "tegra_sclk", -}; - -static struct clk *tegra_hclk_parents[] = { - &tegra_sclk, -}; - -static struct clk tegra_hclk; -static struct clk_tegra tegra_hclk_hw = { - .hw = { - .clk = &tegra_hclk, - }, - .flags = DIV_BUS, - .reg = 0x30, - .reg_shift = 4, - .max_rate = 240000000, -}; -DEFINE_CLK_TEGRA(hclk, 0, &tegra_bus_ops, 0, tegra_hclk_parent_names, - tegra_hclk_parents, &tegra_sclk); - -static const char *tegra_pclk_parent_names[] = { - "tegra_hclk", -}; - -static struct clk *tegra_pclk_parents[] = { - &tegra_hclk, -}; - -static struct clk tegra_pclk; -static struct clk_tegra tegra_pclk_hw = { - .hw = { - .clk = &tegra_pclk, - }, - .flags = DIV_BUS, - .reg = 0x30, - .reg_shift = 0, - .max_rate = 120000000, -}; -DEFINE_CLK_TEGRA(pclk, 0, &tegra_bus_ops, 0, tegra_pclk_parent_names, - tegra_pclk_parents, &tegra_hclk); - -static const char *tegra_blink_parent_names[] = { - "clk_32k", -}; - -static struct clk *tegra_blink_parents[] = { - &tegra_clk_32k, -}; - -static struct clk tegra_blink; -static struct clk_tegra tegra_blink_hw = { - .hw = { - .clk = &tegra_blink, - }, - .reg = 0x40, - .max_rate = 32768, -}; -DEFINE_CLK_TEGRA(blink, 0, &tegra_blink_clk_ops, 0, tegra_blink_parent_names, - tegra_blink_parents, &tegra_clk_32k); - -static const char *mux_pllm_pllc_pllp_plla[] = { - "pll_m", - "pll_c", - "pll_p", - "pll_a_out0", -}; - -static struct clk *mux_pllm_pllc_pllp_plla_p[] = { - &tegra_pll_m, - &tegra_pll_c, - &tegra_pll_p, - &tegra_pll_a_out0, -}; - -static const char *mux_pllm_pllc_pllp_clkm[] = { - "pll_m", - "pll_c", - "pll_p", - "clk_m", -}; - -static struct clk *mux_pllm_pllc_pllp_clkm_p[] = { - &tegra_pll_m, - &tegra_pll_c, - &tegra_pll_p, - &tegra_clk_m, -}; - -static const char *mux_pllp_pllc_pllm_clkm[] = { - "pll_p", - "pll_c", - "pll_m", - "clk_m", -}; - -static struct clk *mux_pllp_pllc_pllm_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_pll_m, - &tegra_clk_m, -}; - -static const char *mux_pllaout0_audio2x_pllp_clkm[] = { - "pll_a_out0", - "audio_2x", - "pll_p", - "clk_m", -}; - -static struct clk *mux_pllaout0_audio2x_pllp_clkm_p[] = { - &tegra_pll_a_out0, - &tegra_audio_2x, - &tegra_pll_p, - &tegra_clk_m, -}; - -static const char *mux_pllp_plld_pllc_clkm[] = { - "pllp", - "pll_d_out0", - "pll_c", - "clk_m", -}; - -static struct clk *mux_pllp_plld_pllc_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_d_out0, - &tegra_pll_c, - &tegra_clk_m, -}; - -static const char *mux_pllp_pllc_audio_clkm_clk32[] = { - "pll_p", - "pll_c", - "audio", - "clk_m", - "clk_32k", -}; - -static struct clk *mux_pllp_pllc_audio_clkm_clk32_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_audio, - &tegra_clk_m, - &tegra_clk_32k, -}; - -static const char *mux_pllp_pllc_pllm[] = { - "pll_p", - "pll_c", - "pll_m" -}; - -static struct clk *mux_pllp_pllc_pllm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_pll_m, -}; - -static const char *mux_clk_m[] = { - "clk_m", -}; - -static struct clk *mux_clk_m_p[] = { - &tegra_clk_m, -}; - -static const char *mux_pllp_out3[] = { - "pll_p_out3", -}; - -static struct clk *mux_pllp_out3_p[] = { - &tegra_pll_p_out3, -}; - -static const char *mux_plld[] = { - "pll_d", -}; - -static struct clk *mux_plld_p[] = { - &tegra_pll_d, -}; - -static const char *mux_clk_32k[] = { - "clk_32k", -}; - -static struct clk *mux_clk_32k_p[] = { - &tegra_clk_32k, -}; - -static const char *mux_pclk[] = { - "pclk", -}; - -static struct clk *mux_pclk_p[] = { - &tegra_pclk, -}; - -static struct clk tegra_emc; -static struct clk_tegra tegra_emc_hw = { - .hw = { - .clk = &tegra_emc, - }, - .reg = 0x19c, - .max_rate = 800000000, - .flags = MUX | DIV_U71 | PERIPH_EMC_ENB, - .reset = &tegra2_periph_clk_reset, - .u.periph = { - .clk_num = 57, - }, -}; -DEFINE_CLK_TEGRA(emc, 0, &tegra_emc_clk_ops, 0, mux_pllm_pllc_pllp_clkm, - mux_pllm_pllc_pllp_clkm_p, NULL); - -#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \ - _max, _inputs, _flags) \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - .reg = _reg, \ - .flags = _flags, \ - .max_rate = _max, \ - .u.periph = { \ - .clk_num = _clk_num, \ - }, \ - .reset = tegra2_periph_clk_reset, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra_periph_clk_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent_names = _inputs, \ - .parents = _inputs##_p, \ - .num_parents = ARRAY_SIZE(_inputs), \ - }; - -PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 108000000, mux_pclk, 0); -PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET); -PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(i2s1, "tegra20-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(i2s2, "tegra20-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(spdif_out, "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(spdif_in, "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71); -PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71 | MUX_PWM); -PERIPH_CLK(spi, "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(xio, "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(twc, "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(ide, "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(vde, "tegra-avp", "vde", 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */ -/* FIXME: what is la? */ -PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(i2c1, "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(i2c2, "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(i2c3, "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(dvc, "tegra-i2c.3", "div-clk", 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX); -PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET); /* scales with voltage and process_id */ -PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET); /* scales with voltage and process_id */ -PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */ -PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */ -PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */ -PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(dsi, "dsi", NULL, 48, 0, 500000000, mux_plld, 0); /* scales with voltage */ -PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0); -PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */ -PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET); -PERIPH_CLK(pex, NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET); -PERIPH_CLK(afi, NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET); -PERIPH_CLK(pcie_xclk, NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET); - -static struct clk *tegra_list_clks[] = { - &tegra_apbdma, - &tegra_rtc, - &tegra_timer, - &tegra_i2s1, - &tegra_i2s2, - &tegra_spdif_out, - &tegra_spdif_in, - &tegra_pwm, - &tegra_spi, - &tegra_xio, - &tegra_twc, - &tegra_sbc1, - &tegra_sbc2, - &tegra_sbc3, - &tegra_sbc4, - &tegra_ide, - &tegra_ndflash, - &tegra_vfir, - &tegra_sdmmc1, - &tegra_sdmmc2, - &tegra_sdmmc3, - &tegra_sdmmc4, - &tegra_vcp, - &tegra_bsea, - &tegra_bsev, - &tegra_vde, - &tegra_csite, - &tegra_la, - &tegra_owr, - &tegra_nor, - &tegra_mipi, - &tegra_i2c1, - &tegra_i2c2, - &tegra_i2c3, - &tegra_dvc, - &tegra_uarta, - &tegra_uartb, - &tegra_uartc, - &tegra_uartd, - &tegra_uarte, - &tegra_3d, - &tegra_2d, - &tegra_vi, - &tegra_vi_sensor, - &tegra_epp, - &tegra_mpe, - &tegra_host1x, - &tegra_cve, - &tegra_tvo, - &tegra_hdmi, - &tegra_tvdac, - &tegra_disp1, - &tegra_disp2, - &tegra_usbd, - &tegra_usb2, - &tegra_usb3, - &tegra_dsi, - &tegra_csi, - &tegra_isp, - &tegra_csus, - &tegra_pex, - &tegra_afi, - &tegra_pcie_xclk, -}; - -#define CLK_DUPLICATE(_name, _dev, _con) \ - { \ - .name = _name, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - } - -/* Some clocks may be used by different drivers depending on the board - * configuration. List those here to register them twice in the clock lookup - * table under two names. - */ -static struct clk_duplicate tegra_clk_duplicates[] = { - CLK_DUPLICATE("uarta", "serial8250.0", NULL), - CLK_DUPLICATE("uartb", "serial8250.1", NULL), - CLK_DUPLICATE("uartc", "serial8250.2", NULL), - CLK_DUPLICATE("uartd", "serial8250.3", NULL), - CLK_DUPLICATE("uarte", "serial8250.4", NULL), - CLK_DUPLICATE("usbd", "utmip-pad", NULL), - CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL), - CLK_DUPLICATE("usbd", "tegra-otg", NULL), - CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"), - CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"), - CLK_DUPLICATE("epp", "tegra_grhost", "epp"), - CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"), - CLK_DUPLICATE("cop", "tegra-avp", "cop"), - CLK_DUPLICATE("vde", "tegra-aes", "vde"), - CLK_DUPLICATE("cclk", NULL, "cpu"), - CLK_DUPLICATE("twd", "smp_twd", NULL), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), - CLK_DUPLICATE("pll_p", "tegradc.0", "parent"), - CLK_DUPLICATE("pll_p", "tegradc.1", "parent"), - CLK_DUPLICATE("pll_d_out0", "hdmi", "parent"), -}; - -#define CLK(dev, con, ck) \ - { \ - .dev_id = dev, \ - .con_id = con, \ - .clk = ck, \ - } - -static struct clk *tegra_ptr_clks[] = { - &tegra_clk_32k, - &tegra_pll_s, - &tegra_clk_m, - &tegra_pll_m, - &tegra_pll_m_out1, - &tegra_pll_c, - &tegra_pll_c_out1, - &tegra_pll_p, - &tegra_pll_p_out1, - &tegra_pll_p_out2, - &tegra_pll_p_out3, - &tegra_pll_p_out4, - &tegra_pll_a, - &tegra_pll_a_out0, - &tegra_pll_d, - &tegra_pll_d_out0, - &tegra_pll_u, - &tegra_pll_x, - &tegra_pll_e, - &tegra_cclk, - &tegra_clk_twd, - &tegra_sclk, - &tegra_hclk, - &tegra_pclk, - &tegra_clk_d, - &tegra_cdev1, - &tegra_cdev2, - &tegra_blink, - &tegra_cop, - &tegra_emc, -}; - -static void tegra2_init_one_clock(struct clk *c) -{ - struct clk_tegra *clk = to_clk_tegra(c->hw); - int ret; - - ret = __clk_init(NULL, c); - if (ret) - pr_err("clk init failed %s\n", __clk_get_name(c)); - - INIT_LIST_HEAD(&clk->shared_bus_list); - if (!clk->lookup.dev_id && !clk->lookup.con_id) - clk->lookup.con_id = c->name; - clk->lookup.clk = c; - clkdev_add(&clk->lookup); - tegra_clk_add(c); -} - -void __init tegra2_init_clocks(void) -{ - int i; - struct clk *c; - - for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++) - tegra2_init_one_clock(tegra_ptr_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++) - tegra2_init_one_clock(tegra_list_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) { - c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name); - if (!c) { - pr_err("%s: Unknown duplicate clock %s\n", __func__, - tegra_clk_duplicates[i].name); - continue; - } - - tegra_clk_duplicates[i].lookup.clk = c; - clkdev_add(&tegra_clk_duplicates[i].lookup); - } - - init_audio_sync_clock_mux(); - tegra20_cpu_car_ops_init(); -} diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c deleted file mode 100644 index 4330787fe5cb..000000000000 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ /dev/null @@ -1,2506 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra30_clocks.c - * - * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "clock.h" -#include "fuse.h" -#include "iomap.h" - -#define USE_PLL_LOCK_BITS 0 - -#define RST_DEVICES_L 0x004 -#define RST_DEVICES_H 0x008 -#define RST_DEVICES_U 0x00C -#define RST_DEVICES_V 0x358 -#define RST_DEVICES_W 0x35C -#define RST_DEVICES_SET_L 0x300 -#define RST_DEVICES_CLR_L 0x304 -#define RST_DEVICES_SET_V 0x430 -#define RST_DEVICES_CLR_V 0x434 -#define RST_DEVICES_NUM 5 - -#define CLK_OUT_ENB_L 0x010 -#define CLK_OUT_ENB_H 0x014 -#define CLK_OUT_ENB_U 0x018 -#define CLK_OUT_ENB_V 0x360 -#define CLK_OUT_ENB_W 0x364 -#define CLK_OUT_ENB_SET_L 0x320 -#define CLK_OUT_ENB_CLR_L 0x324 -#define CLK_OUT_ENB_SET_V 0x440 -#define CLK_OUT_ENB_CLR_V 0x444 -#define CLK_OUT_ENB_NUM 5 - -#define RST_DEVICES_V_SWR_CPULP_RST_DIS (0x1 << 1) -#define CLK_OUT_ENB_V_CLK_ENB_CPULP_EN (0x1 << 1) - -#define PERIPH_CLK_TO_BIT(c) (1 << (c->u.periph.clk_num % 32)) -#define PERIPH_CLK_TO_RST_REG(c) \ - periph_clk_to_reg((c), RST_DEVICES_L, RST_DEVICES_V, 4) -#define PERIPH_CLK_TO_RST_SET_REG(c) \ - periph_clk_to_reg((c), RST_DEVICES_SET_L, RST_DEVICES_SET_V, 8) -#define PERIPH_CLK_TO_RST_CLR_REG(c) \ - periph_clk_to_reg((c), RST_DEVICES_CLR_L, RST_DEVICES_CLR_V, 8) - -#define PERIPH_CLK_TO_ENB_REG(c) \ - periph_clk_to_reg((c), CLK_OUT_ENB_L, CLK_OUT_ENB_V, 4) -#define PERIPH_CLK_TO_ENB_SET_REG(c) \ - periph_clk_to_reg((c), CLK_OUT_ENB_SET_L, CLK_OUT_ENB_SET_V, 8) -#define PERIPH_CLK_TO_ENB_CLR_REG(c) \ - periph_clk_to_reg((c), CLK_OUT_ENB_CLR_L, CLK_OUT_ENB_CLR_V, 8) - -#define CLK_MASK_ARM 0x44 -#define MISC_CLK_ENB 0x48 - -#define OSC_CTRL 0x50 -#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28) -#define OSC_CTRL_OSC_FREQ_13MHZ (0x0<<28) -#define OSC_CTRL_OSC_FREQ_19_2MHZ (0x4<<28) -#define OSC_CTRL_OSC_FREQ_12MHZ (0x8<<28) -#define OSC_CTRL_OSC_FREQ_26MHZ (0xC<<28) -#define OSC_CTRL_OSC_FREQ_16_8MHZ (0x1<<28) -#define OSC_CTRL_OSC_FREQ_38_4MHZ (0x5<<28) -#define OSC_CTRL_OSC_FREQ_48MHZ (0x9<<28) -#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) - -#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26) -#define OSC_CTRL_PLL_REF_DIV_1 (0<<26) -#define OSC_CTRL_PLL_REF_DIV_2 (1<<26) -#define OSC_CTRL_PLL_REF_DIV_4 (2<<26) - -#define OSC_FREQ_DET 0x58 -#define OSC_FREQ_DET_TRIG (1<<31) - -#define OSC_FREQ_DET_STATUS 0x5C -#define OSC_FREQ_DET_BUSY (1<<31) -#define OSC_FREQ_DET_CNT_MASK 0xFFFF - -#define PERIPH_CLK_SOURCE_I2S1 0x100 -#define PERIPH_CLK_SOURCE_EMC 0x19c -#define PERIPH_CLK_SOURCE_OSC 0x1fc -#define PERIPH_CLK_SOURCE_NUM1 \ - ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4) - -#define PERIPH_CLK_SOURCE_G3D2 0x3b0 -#define PERIPH_CLK_SOURCE_SE 0x42c -#define PERIPH_CLK_SOURCE_NUM2 \ - ((PERIPH_CLK_SOURCE_SE - PERIPH_CLK_SOURCE_G3D2) / 4 + 1) - -#define AUDIO_DLY_CLK 0x49c -#define AUDIO_SYNC_CLK_SPDIF 0x4b4 -#define PERIPH_CLK_SOURCE_NUM3 \ - ((AUDIO_SYNC_CLK_SPDIF - AUDIO_DLY_CLK) / 4 + 1) - -#define PERIPH_CLK_SOURCE_NUM (PERIPH_CLK_SOURCE_NUM1 + \ - PERIPH_CLK_SOURCE_NUM2 + \ - PERIPH_CLK_SOURCE_NUM3) - -#define CPU_SOFTRST_CTRL 0x380 - -#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF -#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF -#define PERIPH_CLK_SOURCE_DIV_SHIFT 0 -#define PERIPH_CLK_SOURCE_DIVIDLE_SHIFT 8 -#define PERIPH_CLK_SOURCE_DIVIDLE_VAL 50 -#define PERIPH_CLK_UART_DIV_ENB (1<<24) -#define PERIPH_CLK_VI_SEL_EX_SHIFT 24 -#define PERIPH_CLK_VI_SEL_EX_MASK (0x3<reg_shift - 24) * 4) - -#define PLL_BASE 0x0 -#define PLL_BASE_BYPASS (1<<31) -#define PLL_BASE_ENABLE (1<<30) -#define PLL_BASE_REF_ENABLE (1<<29) -#define PLL_BASE_OVERRIDE (1<<28) -#define PLL_BASE_LOCK (1<<27) -#define PLL_BASE_DIVP_MASK (0x7<<20) -#define PLL_BASE_DIVP_SHIFT 20 -#define PLL_BASE_DIVN_MASK (0x3FF<<8) -#define PLL_BASE_DIVN_SHIFT 8 -#define PLL_BASE_DIVM_MASK (0x1F) -#define PLL_BASE_DIVM_SHIFT 0 - -#define PLL_OUT_RATIO_MASK (0xFF<<8) -#define PLL_OUT_RATIO_SHIFT 8 -#define PLL_OUT_OVERRIDE (1<<2) -#define PLL_OUT_CLKEN (1<<1) -#define PLL_OUT_RESET_DISABLE (1<<0) - -#define PLL_MISC(c) \ - (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc) -#define PLL_MISC_LOCK_ENABLE(c) \ - (((c)->flags & (PLLU | PLLD)) ? (1<<22) : (1<<18)) - -#define PLL_MISC_DCCON_SHIFT 20 -#define PLL_MISC_CPCON_SHIFT 8 -#define PLL_MISC_CPCON_MASK (0xF<hw.clk; - - return clk_set_rate(clk, - (__clk_get_rate(__clk_get_parent(clk)) + n - 1) / n); -} - -static inline u32 periph_clk_to_reg( - struct clk_tegra *c, u32 reg_L, u32 reg_V, int offs) -{ - u32 reg = c->u.periph.clk_num / 32; - BUG_ON(reg >= RST_DEVICES_NUM); - if (reg < 3) - reg = reg_L + (reg * offs); - else - reg = reg_V + ((reg - 3) * offs); - return reg; -} - -static unsigned long clk_measure_input_freq(void) -{ - u32 clock_autodetect; - clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET); - do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY); - clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS); - if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) { - return 12000000; - } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) { - return 13000000; - } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) { - return 19200000; - } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) { - return 26000000; - } else if (clock_autodetect >= 1025 - 3 && clock_autodetect <= 1025 + 3) { - return 16800000; - } else if (clock_autodetect >= 2344 - 3 && clock_autodetect <= 2344 + 3) { - return 38400000; - } else if (clock_autodetect >= 2928 - 3 && clock_autodetect <= 2928 + 3) { - return 48000000; - } else { - pr_err("%s: Unexpected clock autodetect value %d", __func__, - clock_autodetect); - BUG(); - return 0; - } -} - -static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate, - u32 flags, u32 round_mode) -{ - s64 divider_u71 = parent_rate; - if (!rate) - return -EINVAL; - - if (!(flags & DIV_U71_INT)) - divider_u71 *= 2; - if (round_mode == ROUND_DIVIDER_UP) - divider_u71 += rate - 1; - do_div(divider_u71, rate); - if (flags & DIV_U71_INT) - divider_u71 *= 2; - - if (divider_u71 - 2 < 0) - return 0; - - if (divider_u71 - 2 > 255) - return -EINVAL; - - return divider_u71 - 2; -} - -static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) -{ - s64 divider_u16; - - divider_u16 = parent_rate; - if (!rate) - return -EINVAL; - divider_u16 += rate - 1; - do_div(divider_u16, rate); - - if (divider_u16 - 1 < 0) - return 0; - - if (divider_u16 - 1 > 0xFFFF) - return -EINVAL; - - return divider_u16 - 1; -} - -static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - return to_clk_tegra(hw)->fixed_rate; -} - -struct clk_ops tegra30_clk_32k_ops = { - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -/* clk_m functions */ -static unsigned long tegra30_clk_m_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - if (!to_clk_tegra(hw)->fixed_rate) - to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq(); - return to_clk_tegra(hw)->fixed_rate; -} - -static void tegra30_clk_m_init(struct clk_hw *hw) -{ - u32 osc_ctrl = clk_readl(OSC_CTRL); - u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK; - u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; - - switch (to_clk_tegra(hw)->fixed_rate) { - case 12000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 13000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 19200000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 26000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 16800000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_16_8MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - break; - case 38400000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_38_4MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2); - break; - case 48000000: - auto_clock_control |= OSC_CTRL_OSC_FREQ_48MHZ; - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4); - break; - default: - pr_err("%s: Unexpected clock rate %ld", __func__, - to_clk_tegra(hw)->fixed_rate); - BUG(); - } - clk_writel(auto_clock_control, OSC_CTRL); -} - -struct clk_ops tegra30_clk_m_ops = { - .init = tegra30_clk_m_init, - .recalc_rate = tegra30_clk_m_recalc_rate, -}; - -static unsigned long tegra30_clk_m_div_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra_clk_m_div_ops = { - .recalc_rate = tegra30_clk_m_div_recalc_rate, -}; - -/* PLL reference divider functions */ -static unsigned long tegra30_pll_ref_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long rate = parent_rate; - u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK; - - switch (pll_ref_div) { - case OSC_CTRL_PLL_REF_DIV_1: - c->div = 1; - break; - case OSC_CTRL_PLL_REF_DIV_2: - c->div = 2; - break; - case OSC_CTRL_PLL_REF_DIV_4: - c->div = 4; - break; - default: - pr_err("%s: Invalid pll ref divider %d", __func__, pll_ref_div); - BUG(); - } - c->mul = 1; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra_pll_ref_ops = { - .recalc_rate = tegra30_pll_ref_recalc_rate, -}; - -/* super clock functions */ -/* "super clocks" on tegra30 have two-stage muxes, fractional 7.1 divider and - * clock skipping super divider. We will ignore the clock skipping divider, - * since we can't lower the voltage when using the clock skip, but we can if - * we lower the PLL frequency. We will use 7.1 divider for CPU super-clock - * only when its parent is a fixed rate PLL, since we can't change PLL rate - * in this case. - */ -static void tegra30_super_clk_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk_tegra *p = - to_clk_tegra(__clk_get_hw(__clk_get_parent(hw->clk))); - - c->state = ON; - if (c->flags & DIV_U71) { - /* Init safe 7.1 divider value (does not affect PLLX path) */ - clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT, - c->reg + SUPER_CLK_DIVIDER); - c->mul = 2; - c->div = 2; - if (!(p->flags & PLLX)) - c->div += SUPER_CLOCK_DIV_U71_MIN; - } else - clk_writel(0, c->reg + SUPER_CLK_DIVIDER); -} - -static u8 tegra30_super_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - int source; - int shift; - - val = clk_readl(c->reg + SUPER_CLK_MUX); - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - source = (val >> shift) & SUPER_SOURCE_MASK; - if (c->flags & DIV_2) - source |= val & SUPER_LP_DIV2_BYPASS; - - return source; -} - -static int tegra30_super_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk_tegra *p = - to_clk_tegra(__clk_get_hw(clk_get_parent(hw->clk))); - u32 val; - int shift; - - val = clk_readl(c->reg + SUPER_CLK_MUX); - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - - /* For LP mode super-clock switch between PLLX direct - and divided-by-2 outputs is allowed only when other - than PLLX clock source is current parent */ - if ((c->flags & DIV_2) && (p->flags & PLLX) && - ((index ^ val) & SUPER_LP_DIV2_BYPASS)) { - if (p->flags & PLLX) - return -EINVAL; - val ^= SUPER_LP_DIV2_BYPASS; - clk_writel_delay(val, c->reg); - } - val &= ~(SUPER_SOURCE_MASK << shift); - val |= (index & SUPER_SOURCE_MASK) << shift; - - /* 7.1 divider for CPU super-clock does not affect - PLLX path */ - if (c->flags & DIV_U71) { - u32 div = 0; - if (!(p->flags & PLLX)) { - div = clk_readl(c->reg + - SUPER_CLK_DIVIDER); - div &= SUPER_CLOCK_DIV_U71_MASK; - div >>= SUPER_CLOCK_DIV_U71_SHIFT; - } - c->div = div + 2; - c->mul = 2; - } - clk_writel_delay(val, c->reg); - - return 0; -} - -/* - * Do not use super clocks "skippers", since dividing using a clock skipper - * does not allow the voltage to be scaled down. Instead adjust the rate of - * the parent clock. This requires that the parent of a super clock have no - * other children, otherwise the rate will change underneath the other - * children. Special case: if fixed rate PLL is CPU super clock parent the - * rate of this PLL can't be changed, and it has many other children. In - * this case use 7.1 fractional divider to adjust the super clock rate. - */ -static int tegra30_super_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk *parent = __clk_get_parent(hw->clk); - struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent)); - - if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) { - int div = clk_div71_get_divider(parent_rate, - rate, c->flags, ROUND_DIVIDER_DOWN); - div = max(div, SUPER_CLOCK_DIV_U71_MIN); - - clk_writel(div << SUPER_CLOCK_DIV_U71_SHIFT, - c->reg + SUPER_CLK_DIVIDER); - c->div = div + 2; - c->mul = 2; - return 0; - } - return 0; -} - -static unsigned long tegra30_super_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -static long tegra30_super_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk *parent = __clk_get_parent(hw->clk); - struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent)); - int mul = 2; - int div; - - if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) { - div = clk_div71_get_divider(*prate, - rate, c->flags, ROUND_DIVIDER_DOWN); - div = max(div, SUPER_CLOCK_DIV_U71_MIN) + 2; - rate = *prate * mul; - rate += div - 1; /* round up */ - do_div(rate, c->div); - - return rate; - } - return *prate; -} - -struct clk_ops tegra30_super_ops = { - .init = tegra30_super_clk_init, - .set_parent = tegra30_super_clk_set_parent, - .get_parent = tegra30_super_clk_get_parent, - .recalc_rate = tegra30_super_clk_recalc_rate, - .round_rate = tegra30_super_clk_round_rate, - .set_rate = tegra30_super_clk_set_rate, -}; - -static unsigned long tegra30_twd_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra30_twd_ops = { - .recalc_rate = tegra30_twd_clk_recalc_rate, -}; - -/* bus clock functions */ -static int tegra30_bus_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - - c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON; - return c->state; -} - -static int tegra30_bus_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg); - val &= ~(BUS_CLK_DISABLE << c->reg_shift); - clk_writel(val, c->reg); - - return 0; -} - -static void tegra30_bus_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg); - val |= BUS_CLK_DISABLE << c->reg_shift; - clk_writel(val, c->reg); -} - -static unsigned long tegra30_bus_clk_recalc_rate(struct clk_hw *hw, - unsigned long prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - u64 rate = prate; - - c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1; - c->mul = 1; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -static int tegra30_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - int ret = -EINVAL; - u32 val; - int i; - - val = clk_readl(c->reg); - for (i = 1; i <= 4; i++) { - if (rate == parent_rate / i) { - val &= ~(BUS_CLK_DIV_MASK << c->reg_shift); - val |= (i - 1) << c->reg_shift; - clk_writel(val, c->reg); - c->div = i; - c->mul = 1; - ret = 0; - break; - } - } - - return ret; -} - -static long tegra30_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - unsigned long parent_rate = *prate; - s64 divider; - - if (rate >= parent_rate) - return parent_rate; - - divider = parent_rate; - divider += rate - 1; - do_div(divider, rate); - - if (divider < 0) - return divider; - - if (divider > 4) - divider = 4; - do_div(parent_rate, divider); - - return parent_rate; -} - -struct clk_ops tegra30_bus_ops = { - .is_enabled = tegra30_bus_clk_is_enabled, - .enable = tegra30_bus_clk_enable, - .disable = tegra30_bus_clk_disable, - .set_rate = tegra30_bus_clk_set_rate, - .round_rate = tegra30_bus_clk_round_rate, - .recalc_rate = tegra30_bus_clk_recalc_rate, -}; - -/* Blink output functions */ -static int tegra30_blink_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = pmc_readl(PMC_CTRL); - c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF; - return c->state; -} - -static int tegra30_blink_clk_enable(struct clk_hw *hw) -{ - u32 val; - - val = pmc_readl(PMC_DPD_PADS_ORIDE); - pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); - - val = pmc_readl(PMC_CTRL); - pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL); - - return 0; -} - -static void tegra30_blink_clk_disable(struct clk_hw *hw) -{ - u32 val; - - val = pmc_readl(PMC_CTRL); - pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL); - - val = pmc_readl(PMC_DPD_PADS_ORIDE); - pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); -} - -static int tegra30_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (rate >= parent_rate) { - c->div = 1; - pmc_writel(0, c->reg); - } else { - unsigned int on_off; - u32 val; - - on_off = DIV_ROUND_UP(parent_rate / 8, rate); - c->div = on_off * 8; - - val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) << - PMC_BLINK_TIMER_DATA_ON_SHIFT; - on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val |= on_off; - val |= PMC_BLINK_TIMER_ENB; - pmc_writel(val, c->reg); - } - - return 0; -} - -static unsigned long tegra30_blink_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - u32 val; - u32 mul; - u32 div; - u32 on_off; - - mul = 1; - val = pmc_readl(c->reg); - - if (val & PMC_BLINK_TIMER_ENB) { - on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) & - PMC_BLINK_TIMER_DATA_ON_MASK; - val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off += val; - /* each tick in the blink timer is 4 32KHz clocks */ - div = on_off * 4; - } else { - div = 1; - } - - if (mul != 0 && div != 0) { - rate *= mul; - rate += div - 1; /* round up */ - do_div(rate, div); - } - return rate; -} - -static long tegra30_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - int div; - int mul; - long round_rate = *prate; - - mul = 1; - - if (rate >= *prate) { - div = 1; - } else { - div = DIV_ROUND_UP(*prate / 8, rate); - div *= 8; - } - - round_rate *= mul; - round_rate += div - 1; - do_div(round_rate, div); - - return round_rate; -} - -struct clk_ops tegra30_blink_clk_ops = { - .is_enabled = tegra30_blink_clk_is_enabled, - .enable = tegra30_blink_clk_enable, - .disable = tegra30_blink_clk_disable, - .recalc_rate = tegra30_blink_clk_recalc_rate, - .round_rate = tegra30_blink_clk_round_rate, - .set_rate = tegra30_blink_clk_set_rate, -}; - -static void tegra30_utmi_param_configure(struct clk_hw *hw) -{ - unsigned long main_rate = - __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk))); - u32 reg; - int i; - - for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { - if (main_rate == utmi_parameters[i].osc_frequency) - break; - } - - if (i >= ARRAY_SIZE(utmi_parameters)) { - pr_err("%s: Unexpected main rate %lu\n", __func__, main_rate); - return; - } - - reg = clk_readl(UTMIP_PLL_CFG2); - - /* Program UTMIP PLL stable and active counts */ - /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */ - reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); - reg |= UTMIP_PLL_CFG2_STABLE_COUNT( - utmi_parameters[i].stable_count); - - reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); - - reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT( - utmi_parameters[i].active_delay_count); - - /* Remove power downs from UTMIP PLL control bits */ - reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; - reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; - reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; - - clk_writel(reg, UTMIP_PLL_CFG2); - - /* Program UTMIP PLL delay and oscillator frequency counts */ - reg = clk_readl(UTMIP_PLL_CFG1); - reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); - - reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT( - utmi_parameters[i].enable_delay_count); - - reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); - reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT( - utmi_parameters[i].xtal_freq_count); - - /* Remove power downs from UTMIP PLL control bits */ - reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; - reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; - reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; - - clk_writel(reg, UTMIP_PLL_CFG1); -} - -/* PLL Functions */ -static int tegra30_pll_clk_wait_for_lock(struct clk_tegra *c, u32 lock_reg, - u32 lock_bit) -{ - int ret = 0; - -#if USE_PLL_LOCK_BITS - int i; - for (i = 0; i < c->u.pll.lock_delay; i++) { - if (clk_readl(lock_reg) & lock_bit) { - udelay(PLL_POST_LOCK_DELAY); - return 0; - } - udelay(2); /* timeout = 2 * lock time */ - } - pr_err("Timed out waiting for lock bit on pll %s", - __clk_get_name(hw->clk)); - ret = -1; -#else - udelay(c->u.pll.lock_delay); -#endif - return ret; -} - -static int tegra30_pll_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg + PLL_BASE); - - c->state = (val & PLL_BASE_ENABLE) ? ON : OFF; - return c->state; -} - -static void tegra30_pll_clk_init(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (c->flags & PLLU) - tegra30_utmi_param_configure(hw); -} - -static int tegra30_pll_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - -#if USE_PLL_LOCK_BITS - val = clk_readl(c->reg + PLL_MISC(c)); - val |= PLL_MISC_LOCK_ENABLE(c); - clk_writel(val, c->reg + PLL_MISC(c)); -#endif - val = clk_readl(c->reg + PLL_BASE); - val &= ~PLL_BASE_BYPASS; - val |= PLL_BASE_ENABLE; - clk_writel(val, c->reg + PLL_BASE); - - if (c->flags & PLLM) { - val = pmc_readl(PMC_PLLP_WB0_OVERRIDE); - val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; - pmc_writel(val, PMC_PLLP_WB0_OVERRIDE); - } - - tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_BASE, PLL_BASE_LOCK); - - return 0; -} - -static void tegra30_pll_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); - - val = clk_readl(c->reg); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); - clk_writel(val, c->reg); - - if (c->flags & PLLM) { - val = pmc_readl(PMC_PLLP_WB0_OVERRIDE); - val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; - pmc_writel(val, PMC_PLLP_WB0_OVERRIDE); - } -} - -static int tegra30_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val, p_div, old_base; - unsigned long input_rate; - const struct clk_pll_freq_table *sel; - struct clk_pll_freq_table cfg; - - if (c->flags & PLL_FIXED) { - int ret = 0; - if (rate != c->u.pll.fixed_rate) { - pr_err("%s: Can not change %s fixed rate %lu to %lu\n", - __func__, __clk_get_name(hw->clk), - c->u.pll.fixed_rate, rate); - ret = -EINVAL; - } - return ret; - } - - if (c->flags & PLLM) { - if (rate != __clk_get_rate(hw->clk)) { - pr_err("%s: Can not change memory %s rate in flight\n", - __func__, __clk_get_name(hw->clk)); - return -EINVAL; - } - } - - p_div = 0; - input_rate = parent_rate; - - /* Check if the target rate is tabulated */ - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && sel->output_rate == rate) { - if (c->flags & PLLU) { - BUG_ON(sel->p < 1 || sel->p > 2); - if (sel->p == 1) - p_div = PLLU_BASE_POST_DIV; - } else { - BUG_ON(sel->p < 1); - for (val = sel->p; val > 1; val >>= 1) - p_div++; - p_div <<= PLL_BASE_DIVP_SHIFT; - } - break; - } - } - - /* Configure out-of-table rate */ - if (sel->input_rate == 0) { - unsigned long cfreq; - BUG_ON(c->flags & PLLU); - sel = &cfg; - - switch (input_rate) { - case 12000000: - case 26000000: - cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; - break; - case 13000000: - cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; - break; - case 16800000: - case 19200000: - cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; - break; - default: - pr_err("%s: Unexpected reference rate %lu\n", - __func__, input_rate); - BUG(); - } - - /* Raise VCO to guarantee 0.5% accuracy */ - for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq; - cfg.output_rate <<= 1) - p_div++; - - cfg.p = 0x1 << p_div; - cfg.m = input_rate / cfreq; - cfg.n = cfg.output_rate / cfreq; - cfg.cpcon = OUT_OF_TABLE_CPCON; - - if ((cfg.m > (PLL_BASE_DIVM_MASK >> PLL_BASE_DIVM_SHIFT)) || - (cfg.n > (PLL_BASE_DIVN_MASK >> PLL_BASE_DIVN_SHIFT)) || - (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) || - (cfg.output_rate > c->u.pll.vco_max)) { - pr_err("%s: Failed to set %s out-of-table rate %lu\n", - __func__, __clk_get_name(hw->clk), rate); - return -EINVAL; - } - p_div <<= PLL_BASE_DIVP_SHIFT; - } - - c->mul = sel->n; - c->div = sel->m * sel->p; - - old_base = val = clk_readl(c->reg + PLL_BASE); - val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK | - ((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK)); - val |= (sel->m << PLL_BASE_DIVM_SHIFT) | - (sel->n << PLL_BASE_DIVN_SHIFT) | p_div; - if (val == old_base) - return 0; - - if (c->state == ON) { - tegra30_pll_clk_disable(hw); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); - } - clk_writel(val, c->reg + PLL_BASE); - - if (c->flags & PLL_HAS_CPCON) { - val = clk_readl(c->reg + PLL_MISC(c)); - val &= ~PLL_MISC_CPCON_MASK; - val |= sel->cpcon << PLL_MISC_CPCON_SHIFT; - if (c->flags & (PLLU | PLLD)) { - val &= ~PLL_MISC_LFCON_MASK; - if (sel->n >= PLLDU_LFCON_SET_DIVN) - val |= 0x1 << PLL_MISC_LFCON_SHIFT; - } else if (c->flags & (PLLX | PLLM)) { - val &= ~(0x1 << PLL_MISC_DCCON_SHIFT); - if (rate >= (c->u.pll.vco_max >> 1)) - val |= 0x1 << PLL_MISC_DCCON_SHIFT; - } - clk_writel(val, c->reg + PLL_MISC(c)); - } - - if (c->state == ON) - tegra30_pll_clk_enable(hw); - - c->u.pll.fixed_rate = rate; - - return 0; -} - -static long tegra30_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long input_rate = *prate; - u64 output_rate = *prate; - const struct clk_pll_freq_table *sel; - struct clk_pll_freq_table cfg; - int mul; - int div; - u32 p_div; - u32 val; - - if (c->flags & PLL_FIXED) - return c->u.pll.fixed_rate; - - if (c->flags & PLLM) - return __clk_get_rate(hw->clk); - - p_div = 0; - /* Check if the target rate is tabulated */ - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && sel->output_rate == rate) { - if (c->flags & PLLU) { - BUG_ON(sel->p < 1 || sel->p > 2); - if (sel->p == 1) - p_div = PLLU_BASE_POST_DIV; - } else { - BUG_ON(sel->p < 1); - for (val = sel->p; val > 1; val >>= 1) - p_div++; - p_div <<= PLL_BASE_DIVP_SHIFT; - } - break; - } - } - - if (sel->input_rate == 0) { - unsigned long cfreq; - BUG_ON(c->flags & PLLU); - sel = &cfg; - - switch (input_rate) { - case 12000000: - case 26000000: - cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; - break; - case 13000000: - cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; - break; - case 16800000: - case 19200000: - cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; - break; - default: - pr_err("%s: Unexpected reference rate %lu\n", - __func__, input_rate); - BUG(); - } - - /* Raise VCO to guarantee 0.5% accuracy */ - for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq; - cfg.output_rate <<= 1) - p_div++; - - cfg.p = 0x1 << p_div; - cfg.m = input_rate / cfreq; - cfg.n = cfg.output_rate / cfreq; - } - - mul = sel->n; - div = sel->m * sel->p; - - output_rate *= mul; - output_rate += div - 1; /* round up */ - do_div(output_rate, div); - - return output_rate; -} - -static unsigned long tegra30_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - u32 val = clk_readl(c->reg + PLL_BASE); - - if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) { - const struct clk_pll_freq_table *sel; - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == parent_rate && - sel->output_rate == c->u.pll.fixed_rate) { - c->mul = sel->n; - c->div = sel->m * sel->p; - break; - } - } - pr_err("Clock %s has unknown fixed frequency\n", - __clk_get_name(hw->clk)); - BUG(); - } else if (val & PLL_BASE_BYPASS) { - c->mul = 1; - c->div = 1; - } else { - c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT; - c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT; - if (c->flags & PLLU) - c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2; - else - c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >> - PLL_BASE_DIVP_SHIFT)); - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -struct clk_ops tegra30_pll_ops = { - .is_enabled = tegra30_pll_clk_is_enabled, - .init = tegra30_pll_clk_init, - .enable = tegra30_pll_clk_enable, - .disable = tegra30_pll_clk_disable, - .recalc_rate = tegra30_pll_recalc_rate, - .round_rate = tegra30_pll_round_rate, - .set_rate = tegra30_pll_clk_set_rate, -}; - -int tegra30_plld_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val, mask, reg; - - switch (p) { - case TEGRA_CLK_PLLD_CSI_OUT_ENB: - mask = PLLD_BASE_CSI_CLKENABLE; - reg = c->reg + PLL_BASE; - break; - case TEGRA_CLK_PLLD_DSI_OUT_ENB: - mask = PLLD_MISC_DSI_CLKENABLE; - reg = c->reg + PLL_MISC(c); - break; - case TEGRA_CLK_PLLD_MIPI_MUX_SEL: - if (!(c->flags & PLL_ALT_MISC_REG)) { - mask = PLLD_BASE_DSIB_MUX_MASK; - reg = c->reg + PLL_BASE; - break; - } - /* fall through - error since PLLD2 does not have MUX_SEL control */ - default: - return -EINVAL; - } - - val = clk_readl(reg); - if (setting) - val |= mask; - else - val &= ~mask; - clk_writel(val, reg); - return 0; -} - -static int tegra30_plle_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg + PLL_BASE); - c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF; - return c->state; -} - -static void tegra30_plle_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg + PLL_BASE); - val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE); - clk_writel(val, c->reg + PLL_BASE); -} - -static void tegra30_plle_training(struct clk_tegra *c) -{ - u32 val; - - /* PLLE is already disabled, and setup cleared; - * create falling edge on PLLE IDDQ input */ - val = pmc_readl(PMC_SATA_PWRGT); - val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; - pmc_writel(val, PMC_SATA_PWRGT); - - val = pmc_readl(PMC_SATA_PWRGT); - val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; - pmc_writel(val, PMC_SATA_PWRGT); - - val = pmc_readl(PMC_SATA_PWRGT); - val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; - pmc_writel(val, PMC_SATA_PWRGT); - - do { - val = clk_readl(c->reg + PLL_MISC(c)); - } while (!(val & PLLE_MISC_READY)); -} - -static int tegra30_plle_configure(struct clk_hw *hw, bool force_training) -{ - struct clk_tegra *c = to_clk_tegra(hw); - struct clk *parent = __clk_get_parent(hw->clk); - const struct clk_pll_freq_table *sel; - u32 val; - - unsigned long rate = c->u.pll.fixed_rate; - unsigned long input_rate = __clk_get_rate(parent); - - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && sel->output_rate == rate) - break; - } - - if (sel->input_rate == 0) - return -ENOSYS; - - /* disable PLLE, clear setup fiels */ - tegra30_plle_clk_disable(hw); - - val = clk_readl(c->reg + PLL_MISC(c)); - val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); - clk_writel(val, c->reg + PLL_MISC(c)); - - /* training */ - val = clk_readl(c->reg + PLL_MISC(c)); - if (force_training || (!(val & PLLE_MISC_READY))) - tegra30_plle_training(c); - - /* configure dividers, setup, disable SS */ - val = clk_readl(c->reg + PLL_BASE); - val &= ~PLLE_BASE_DIV_MASK; - val |= PLLE_BASE_DIV(sel->m, sel->n, sel->p, sel->cpcon); - clk_writel(val, c->reg + PLL_BASE); - c->mul = sel->n; - c->div = sel->m * sel->p; - - val = clk_readl(c->reg + PLL_MISC(c)); - val |= PLLE_MISC_SETUP_VALUE; - val |= PLLE_MISC_LOCK_ENABLE; - clk_writel(val, c->reg + PLL_MISC(c)); - - val = clk_readl(PLLE_SS_CTRL); - val |= PLLE_SS_DISABLE; - clk_writel(val, PLLE_SS_CTRL); - - /* enable and lock PLLE*/ - val = clk_readl(c->reg + PLL_BASE); - val |= (PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE); - clk_writel(val, c->reg + PLL_BASE); - - tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_MISC(c), PLLE_MISC_LOCK); - - return 0; -} - -static int tegra30_plle_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - return tegra30_plle_configure(hw, !c->set); -} - -static unsigned long tegra30_plle_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long rate = parent_rate; - u32 val; - - val = clk_readl(c->reg + PLL_BASE); - c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT; - c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT; - c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -struct clk_ops tegra30_plle_ops = { - .is_enabled = tegra30_plle_clk_is_enabled, - .enable = tegra30_plle_clk_enable, - .disable = tegra30_plle_clk_disable, - .recalc_rate = tegra30_plle_clk_recalc_rate, -}; - -/* Clock divider ops */ -static int tegra30_pll_div_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (c->flags & DIV_U71) { - u32 val = clk_readl(c->reg); - val >>= c->reg_shift; - c->state = (val & PLL_OUT_CLKEN) ? ON : OFF; - if (!(val & PLL_OUT_RESET_DISABLE)) - c->state = OFF; - } else { - c->state = ON; - } - return c->state; -} - -static int tegra30_pll_div_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - u32 new_val; - - pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); - if (c->flags & DIV_U71) { - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - - new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE; - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel_delay(val, c->reg); - return 0; - } else if (c->flags & DIV_2) { - return 0; - } - return -EINVAL; -} - -static void tegra30_pll_div_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - u32 new_val; - - pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); - if (c->flags & DIV_U71) { - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - - new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE); - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel_delay(val, c->reg); - } -} - -static int tegra30_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - u32 new_val; - int divider_u71; - - if (c->flags & DIV_U71) { - divider_u71 = clk_div71_get_divider( - parent_rate, rate, c->flags, ROUND_DIVIDER_UP); - if (divider_u71 >= 0) { - val = clk_readl(c->reg); - new_val = val >> c->reg_shift; - new_val &= 0xFFFF; - if (c->flags & DIV_U71_FIXED) - new_val |= PLL_OUT_OVERRIDE; - new_val &= ~PLL_OUT_RATIO_MASK; - new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT; - - val &= ~(0xFFFF << c->reg_shift); - val |= new_val << c->reg_shift; - clk_writel_delay(val, c->reg); - c->div = divider_u71 + 2; - c->mul = 2; - c->fixed_rate = rate; - return 0; - } - } else if (c->flags & DIV_2) { - c->fixed_rate = rate; - return 0; - } - - return -EINVAL; -} - -static unsigned long tegra30_pll_div_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - if (c->flags & DIV_U71) { - u32 divu71; - u32 val = clk_readl(c->reg); - val >>= c->reg_shift; - - divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT; - c->div = (divu71 + 2); - c->mul = 2; - } else if (c->flags & DIV_2) { - if (c->flags & (PLLD | PLLX)) { - c->div = 2; - c->mul = 1; - } else - BUG(); - } else { - c->div = 1; - c->mul = 1; - } - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -static long tegra30_pll_div_clk_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); - int divider; - - if (prate) - parent_rate = *prate; - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider( - parent_rate, rate, c->flags, ROUND_DIVIDER_UP); - if (divider < 0) - return divider; - return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_2) { - *prate = rate * 2; - return rate; - } - - return -EINVAL; -} - -struct clk_ops tegra30_pll_div_ops = { - .is_enabled = tegra30_pll_div_clk_is_enabled, - .enable = tegra30_pll_div_clk_enable, - .disable = tegra30_pll_div_clk_disable, - .set_rate = tegra30_pll_div_clk_set_rate, - .recalc_rate = tegra30_pll_div_clk_recalc_rate, - .round_rate = tegra30_pll_div_clk_round_rate, -}; - -/* Periph clk ops */ -static inline u32 periph_clk_source_mask(struct clk_tegra *c) -{ - if (c->flags & MUX8) - return 7 << 29; - else if (c->flags & MUX_PWM) - return 3 << 28; - else if (c->flags & MUX_CLK_OUT) - return 3 << (c->u.periph.clk_num + 4); - else if (c->flags & PLLD) - return PLLD_BASE_DSIB_MUX_MASK; - else - return 3 << 30; -} - -static inline u32 periph_clk_source_shift(struct clk_tegra *c) -{ - if (c->flags & MUX8) - return 29; - else if (c->flags & MUX_PWM) - return 28; - else if (c->flags & MUX_CLK_OUT) - return c->u.periph.clk_num + 4; - else if (c->flags & PLLD) - return PLLD_BASE_DSIB_MUX_SHIFT; - else - return 30; -} - -static int tegra30_periph_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - c->state = ON; - if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c))) - c->state = OFF; - if (!(c->flags & PERIPH_NO_RESET)) - if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c)) - c->state = OFF; - return c->state; -} - -static int tegra30_periph_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1) - return 0; - - clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_SET_REG(c)); - if (!(c->flags & PERIPH_NO_RESET) && - !(c->flags & PERIPH_MANUAL_RESET)) { - if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & - PERIPH_CLK_TO_BIT(c)) { - udelay(5); /* reset propagation delay */ - clk_writel(PERIPH_CLK_TO_BIT(c), - PERIPH_CLK_TO_RST_CLR_REG(c)); - } - } - return 0; -} - -static void tegra30_periph_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long val; - - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; - - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0) - return; - - /* If peripheral is in the APB bus then read the APB bus to - * flush the write operation in apb bus. This will avoid the - * peripheral access after disabling clock*/ - if (c->flags & PERIPH_ON_APB) - val = chipid_readl(); - - clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c)); -} - -void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long val; - - if (!(c->flags & PERIPH_NO_RESET)) { - if (assert) { - /* If peripheral is in the APB bus then read the APB - * bus to flush the write operation in apb bus. This - * will avoid the peripheral access after disabling - * clock */ - if (c->flags & PERIPH_ON_APB) - val = chipid_readl(); - - clk_writel(PERIPH_CLK_TO_BIT(c), - PERIPH_CLK_TO_RST_SET_REG(c)); - } else - clk_writel(PERIPH_CLK_TO_BIT(c), - PERIPH_CLK_TO_RST_CLR_REG(c)); - } -} - -static int tegra30_periph_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - if (!(c->flags & MUX)) - return (index == 0) ? 0 : (-EINVAL); - - val = clk_readl(c->reg); - val &= ~periph_clk_source_mask(c); - val |= (index << periph_clk_source_shift(c)); - clk_writel_delay(val, c->reg); - return 0; -} - -static u8 tegra30_periph_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - int source = (val & periph_clk_source_mask(c)) >> - periph_clk_source_shift(c); - - if (!(c->flags & MUX)) - return 0; - - return source; -} - -static int tegra30_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - int divider; - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider( - parent_rate, rate, c->flags, ROUND_DIVIDER_UP); - if (divider >= 0) { - val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; - val |= divider; - if (c->flags & DIV_U71_UART) { - if (divider) - val |= PERIPH_CLK_UART_DIV_ENB; - else - val &= ~PERIPH_CLK_UART_DIV_ENB; - } - clk_writel_delay(val, c->reg); - c->div = divider + 2; - c->mul = 2; - return 0; - } - } else if (c->flags & DIV_U16) { - divider = clk_div16_get_divider(parent_rate, rate); - if (divider >= 0) { - val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; - val |= divider; - clk_writel_delay(val, c->reg); - c->div = divider + 1; - c->mul = 1; - return 0; - } - } else if (parent_rate <= rate) { - c->div = 1; - c->mul = 1; - return 0; - } - return -EINVAL; -} - -static long tegra30_periph_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); - int divider; - - if (prate) - parent_rate = *prate; - - if (c->flags & DIV_U71) { - divider = clk_div71_get_divider( - parent_rate, rate, c->flags, ROUND_DIVIDER_UP); - if (divider < 0) - return divider; - - return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_U16) { - divider = clk_div16_get_divider(parent_rate, rate); - if (divider < 0) - return divider; - return DIV_ROUND_UP(parent_rate, divider + 1); - } - return -EINVAL; -} - -static unsigned long tegra30_periph_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - u32 val = clk_readl(c->reg); - - if (c->flags & DIV_U71) { - u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; - if ((c->flags & DIV_U71_UART) && - (!(val & PERIPH_CLK_UART_DIV_ENB))) { - divu71 = 0; - } - if (c->flags & DIV_U71_IDLE) { - val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK << - PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); - val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL << - PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); - clk_writel(val, c->reg); - } - c->div = divu71 + 2; - c->mul = 2; - } else if (c->flags & DIV_U16) { - u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; - c->div = divu16 + 1; - c->mul = 1; - } else { - c->div = 1; - c->mul = 1; - } - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - return rate; -} - -struct clk_ops tegra30_periph_clk_ops = { - .is_enabled = tegra30_periph_clk_is_enabled, - .enable = tegra30_periph_clk_enable, - .disable = tegra30_periph_clk_disable, - .set_parent = tegra30_periph_clk_set_parent, - .get_parent = tegra30_periph_clk_get_parent, - .set_rate = tegra30_periph_clk_set_rate, - .round_rate = tegra30_periph_clk_round_rate, - .recalc_rate = tegra30_periph_clk_recalc_rate, -}; - -static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk *d = clk_get_sys(NULL, "pll_d"); - /* The DSIB parent selection bit is in PLLD base register */ - tegra_clk_cfg_ex( - d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index); - - return 0; -} - -struct clk_ops tegra30_dsib_clk_ops = { - .is_enabled = tegra30_periph_clk_is_enabled, - .enable = &tegra30_periph_clk_enable, - .disable = &tegra30_periph_clk_disable, - .set_parent = &tegra30_dsib_clk_set_parent, - .get_parent = &tegra30_periph_clk_get_parent, - .set_rate = &tegra30_periph_clk_set_rate, - .round_rate = &tegra30_periph_clk_round_rate, - .recalc_rate = &tegra30_periph_clk_recalc_rate, -}; - -/* Periph extended clock configuration ops */ -int tegra30_vi_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (p == TEGRA_CLK_VI_INP_SEL) { - u32 val = clk_readl(c->reg); - val &= ~PERIPH_CLK_VI_SEL_EX_MASK; - val |= (setting << PERIPH_CLK_VI_SEL_EX_SHIFT) & - PERIPH_CLK_VI_SEL_EX_MASK; - clk_writel(val, c->reg); - return 0; - } - return -EINVAL; -} - -int tegra30_nand_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) { - u32 val = clk_readl(c->reg); - if (setting) - val |= PERIPH_CLK_NAND_DIV_EX_ENB; - else - val &= ~PERIPH_CLK_NAND_DIV_EX_ENB; - clk_writel(val, c->reg); - return 0; - } - return -EINVAL; -} - -int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - if (p == TEGRA_CLK_DTV_INVERT) { - u32 val = clk_readl(c->reg); - if (setting) - val |= PERIPH_CLK_DTV_POLARITY_INV; - else - val &= ~PERIPH_CLK_DTV_POLARITY_INV; - clk_writel(val, c->reg); - return 0; - } - return -EINVAL; -} - -/* Output clock ops */ - -static DEFINE_SPINLOCK(clk_out_lock); - -static int tegra30_clk_out_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = pmc_readl(c->reg); - - c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF; - c->mul = 1; - c->div = 1; - return c->state; -} - -static int tegra30_clk_out_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - unsigned long flags; - - spin_lock_irqsave(&clk_out_lock, flags); - val = pmc_readl(c->reg); - val |= (0x1 << c->u.periph.clk_num); - pmc_writel(val, c->reg); - spin_unlock_irqrestore(&clk_out_lock, flags); - - return 0; -} - -static void tegra30_clk_out_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - unsigned long flags; - - spin_lock_irqsave(&clk_out_lock, flags); - val = pmc_readl(c->reg); - val &= ~(0x1 << c->u.periph.clk_num); - pmc_writel(val, c->reg); - spin_unlock_irqrestore(&clk_out_lock, flags); -} - -static int tegra30_clk_out_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - unsigned long flags; - - spin_lock_irqsave(&clk_out_lock, flags); - val = pmc_readl(c->reg); - val &= ~periph_clk_source_mask(c); - val |= (index << periph_clk_source_shift(c)); - pmc_writel(val, c->reg); - spin_unlock_irqrestore(&clk_out_lock, flags); - - return 0; -} - -static u8 tegra30_clk_out_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = pmc_readl(c->reg); - int source; - - source = (val & periph_clk_source_mask(c)) >> - periph_clk_source_shift(c); - return source; -} - -struct clk_ops tegra_clk_out_ops = { - .is_enabled = tegra30_clk_out_is_enabled, - .enable = tegra30_clk_out_enable, - .disable = tegra30_clk_out_disable, - .set_parent = tegra30_clk_out_set_parent, - .get_parent = tegra30_clk_out_get_parent, - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -/* Clock doubler ops */ -static int tegra30_clk_double_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - c->state = ON; - if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c))) - c->state = OFF; - return c->state; -}; - -static int tegra30_clk_double_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - if (rate == parent_rate) { - val = clk_readl(c->reg) | (0x1 << c->reg_shift); - clk_writel(val, c->reg); - c->mul = 1; - c->div = 1; - return 0; - } else if (rate == 2 * parent_rate) { - val = clk_readl(c->reg) & (~(0x1 << c->reg_shift)); - clk_writel(val, c->reg); - c->mul = 2; - c->div = 1; - return 0; - } - return -EINVAL; -} - -static unsigned long tegra30_clk_double_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u64 rate = parent_rate; - - u32 val = clk_readl(c->reg); - c->mul = val & (0x1 << c->reg_shift) ? 1 : 2; - c->div = 1; - - if (c->mul != 0 && c->div != 0) { - rate *= c->mul; - rate += c->div - 1; /* round up */ - do_div(rate, c->div); - } - - return rate; -} - -static long tegra30_clk_double_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - unsigned long output_rate = *prate; - - do_div(output_rate, 2); - return output_rate; -} - -struct clk_ops tegra30_clk_double_ops = { - .is_enabled = tegra30_clk_double_is_enabled, - .enable = tegra30_periph_clk_enable, - .disable = tegra30_periph_clk_disable, - .recalc_rate = tegra30_clk_double_recalc_rate, - .round_rate = tegra30_clk_double_round_rate, - .set_rate = tegra30_clk_double_set_rate, -}; - -/* Audio sync clock ops */ -struct clk_ops tegra_sync_source_ops = { - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -static int tegra30_audio_sync_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON; - return c->state; -} - -static int tegra30_audio_sync_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg); - return 0; -} - -static void tegra30_audio_sync_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg); -} - -static int tegra30_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val; - - val = clk_readl(c->reg); - val &= ~AUDIO_SYNC_SOURCE_MASK; - val |= index; - - clk_writel(val, c->reg); - return 0; -} - -static u8 tegra30_audio_sync_clk_get_parent(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - int source; - - source = val & AUDIO_SYNC_SOURCE_MASK; - return source; -} - -struct clk_ops tegra30_audio_sync_clk_ops = { - .is_enabled = tegra30_audio_sync_clk_is_enabled, - .enable = tegra30_audio_sync_clk_enable, - .disable = tegra30_audio_sync_clk_disable, - .set_parent = tegra30_audio_sync_clk_set_parent, - .get_parent = tegra30_audio_sync_clk_get_parent, - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -/* cml0 (pcie), and cml1 (sata) clock ops */ -static int tegra30_cml_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - u32 val = clk_readl(c->reg); - c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF; - return c->state; -} - -static int tegra30_cml_clk_enable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - u32 val = clk_readl(c->reg); - val |= (0x1 << c->u.periph.clk_num); - clk_writel(val, c->reg); - - return 0; -} - -static void tegra30_cml_clk_disable(struct clk_hw *hw) -{ - struct clk_tegra *c = to_clk_tegra(hw); - - u32 val = clk_readl(c->reg); - val &= ~(0x1 << c->u.periph.clk_num); - clk_writel(val, c->reg); -} - -struct clk_ops tegra_cml_clk_ops = { - .is_enabled = tegra30_cml_clk_is_enabled, - .enable = tegra30_cml_clk_enable, - .disable = tegra30_cml_clk_disable, - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -struct clk_ops tegra_pciex_clk_ops = { - .recalc_rate = tegra30_clk_fixed_recalc_rate, -}; - -/* Tegra30 CPU clock and reset control functions */ -static void tegra30_wait_cpu_in_reset(u32 cpu) -{ - unsigned int reg; - - do { - reg = readl(reg_clk_base + - TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); - cpu_relax(); - } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ - - return; -} - -static void tegra30_put_cpu_in_reset(u32 cpu) -{ - writel(CPU_RESET(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); - dmb(); -} - -static void tegra30_cpu_out_of_reset(u32 cpu) -{ - writel(CPU_RESET(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); - wmb(); -} - -static void tegra30_enable_cpu_clock(u32 cpu) -{ - unsigned int reg; - - writel(CPU_CLOCK(cpu), - reg_clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); - reg = readl(reg_clk_base + - TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); -} - -static void tegra30_disable_cpu_clock(u32 cpu) -{ - - unsigned int reg; - - reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - writel(reg | CPU_CLOCK(cpu), - reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); -} - -#ifdef CONFIG_PM_SLEEP -static bool tegra30_cpu_rail_off_ready(void) -{ - unsigned int cpu_rst_status; - int cpu_pwr_status; - - cpu_rst_status = readl(reg_clk_base + - TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); - cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) || - tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) || - tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3); - - if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status) - return false; - - return true; -} - -static void tegra30_cpu_clock_suspend(void) -{ - /* switch coresite to clk_m, save off original source */ - tegra30_cpu_clk_sctx.clk_csite_src = - readl(reg_clk_base + CLK_RESET_SOURCE_CSITE); - writel(3<<30, reg_clk_base + CLK_RESET_SOURCE_CSITE); - - tegra30_cpu_clk_sctx.cpu_burst = - readl(reg_clk_base + CLK_RESET_CCLK_BURST); - tegra30_cpu_clk_sctx.pllx_base = - readl(reg_clk_base + CLK_RESET_PLLX_BASE); - tegra30_cpu_clk_sctx.pllx_misc = - readl(reg_clk_base + CLK_RESET_PLLX_MISC); - tegra30_cpu_clk_sctx.cclk_divider = - readl(reg_clk_base + CLK_RESET_CCLK_DIVIDER); -} - -static void tegra30_cpu_clock_resume(void) -{ - unsigned int reg, policy; - - /* Is CPU complex already running on PLLX? */ - reg = readl(reg_clk_base + CLK_RESET_CCLK_BURST); - policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF; - - if (policy == CLK_RESET_CCLK_IDLE_POLICY) - reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF; - else if (policy == CLK_RESET_CCLK_RUN_POLICY) - reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF; - else - BUG(); - - if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) { - /* restore PLLX settings if CPU is on different PLL */ - writel(tegra30_cpu_clk_sctx.pllx_misc, - reg_clk_base + CLK_RESET_PLLX_MISC); - writel(tegra30_cpu_clk_sctx.pllx_base, - reg_clk_base + CLK_RESET_PLLX_BASE); - - /* wait for PLL stabilization if PLLX was enabled */ - if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30)) - udelay(300); - } - - /* - * Restore original burst policy setting for calls resulting from CPU - * LP2 in idle or system suspend. - */ - writel(tegra30_cpu_clk_sctx.cclk_divider, - reg_clk_base + CLK_RESET_CCLK_DIVIDER); - writel(tegra30_cpu_clk_sctx.cpu_burst, - reg_clk_base + CLK_RESET_CCLK_BURST); - - writel(tegra30_cpu_clk_sctx.clk_csite_src, - reg_clk_base + CLK_RESET_SOURCE_CSITE); -} -#endif - -static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { - .wait_for_reset = tegra30_wait_cpu_in_reset, - .put_in_reset = tegra30_put_cpu_in_reset, - .out_of_reset = tegra30_cpu_out_of_reset, - .enable_clock = tegra30_enable_cpu_clock, - .disable_clock = tegra30_disable_cpu_clock, -#ifdef CONFIG_PM_SLEEP - .rail_off_ready = tegra30_cpu_rail_off_ready, - .suspend = tegra30_cpu_clock_suspend, - .resume = tegra30_cpu_clock_resume, -#endif -}; - -void __init tegra30_cpu_car_ops_init(void) -{ - tegra_cpu_car_ops = &tegra30_cpu_car_ops; -} diff --git a/arch/arm/mach-tegra/tegra30_clocks.h b/arch/arm/mach-tegra/tegra30_clocks.h deleted file mode 100644 index 7a34adb2f72d..000000000000 --- a/arch/arm/mach-tegra/tegra30_clocks.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __MACH_TEGRA30_CLOCK_H -#define __MACH_TEGRA30_CLOCK_H - -extern struct clk_ops tegra30_clk_32k_ops; -extern struct clk_ops tegra30_clk_m_ops; -extern struct clk_ops tegra_clk_m_div_ops; -extern struct clk_ops tegra_pll_ref_ops; -extern struct clk_ops tegra30_pll_ops; -extern struct clk_ops tegra30_pll_div_ops; -extern struct clk_ops tegra_plld_ops; -extern struct clk_ops tegra30_plle_ops; -extern struct clk_ops tegra_cml_clk_ops; -extern struct clk_ops tegra_pciex_clk_ops; -extern struct clk_ops tegra_sync_source_ops; -extern struct clk_ops tegra30_audio_sync_clk_ops; -extern struct clk_ops tegra30_clk_double_ops; -extern struct clk_ops tegra_clk_out_ops; -extern struct clk_ops tegra30_super_ops; -extern struct clk_ops tegra30_blink_clk_ops; -extern struct clk_ops tegra30_twd_ops; -extern struct clk_ops tegra30_bus_ops; -extern struct clk_ops tegra30_periph_clk_ops; -extern struct clk_ops tegra30_dsib_clk_ops; -extern struct clk_ops tegra_nand_clk_ops; -extern struct clk_ops tegra_vi_clk_ops; -extern struct clk_ops tegra_dtv_clk_ops; -extern struct clk_ops tegra_clk_shared_bus_ops; - -int tegra30_plld_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting); -void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert); -int tegra30_vi_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting); -int tegra30_nand_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting); -int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw, - enum tegra_clk_ex_param p, u32 setting); -#endif diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c deleted file mode 100644 index 9bfaa490cff6..000000000000 --- a/arch/arm/mach-tegra/tegra30_clocks_data.c +++ /dev/null @@ -1,1425 +0,0 @@ -/* - * arch/arm/mach-tegra/tegra30_clocks.c - * - * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "clock.h" -#include "fuse.h" -#include "tegra30_clocks.h" - -#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ - _parent_names, _parents, _parent) \ - static struct clk tegra_##_name = { \ - .hw = &tegra_##_name##_hw.hw, \ - .name = #_name, \ - .rate = _rate, \ - .ops = _ops, \ - .flags = _flags, \ - .parent_names = _parent_names, \ - .parents = _parents, \ - .num_parents = ARRAY_SIZE(_parent_names), \ - .parent = _parent, \ - }; - -static struct clk tegra_clk_32k; -static struct clk_tegra tegra_clk_32k_hw = { - .hw = { - .clk = &tegra_clk_32k, - }, - .fixed_rate = 32768, -}; -static struct clk tegra_clk_32k = { - .name = "clk_32k", - .hw = &tegra_clk_32k_hw.hw, - .ops = &tegra30_clk_32k_ops, - .flags = CLK_IS_ROOT, -}; - -static struct clk tegra_clk_m; -static struct clk_tegra tegra_clk_m_hw = { - .hw = { - .clk = &tegra_clk_m, - }, - .flags = ENABLE_ON_INIT, - .reg = 0x1fc, - .reg_shift = 28, - .max_rate = 48000000, -}; -static struct clk tegra_clk_m = { - .name = "clk_m", - .hw = &tegra_clk_m_hw.hw, - .ops = &tegra30_clk_m_ops, - .flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED, -}; - -static const char *clk_m_div_parent_names[] = { - "clk_m", -}; - -static struct clk *clk_m_div_parents[] = { - &tegra_clk_m, -}; - -static struct clk tegra_clk_m_div2; -static struct clk_tegra tegra_clk_m_div2_hw = { - .hw = { - .clk = &tegra_clk_m_div2, - }, - .mul = 1, - .div = 2, - .max_rate = 24000000, -}; -DEFINE_CLK_TEGRA(clk_m_div2, 0, &tegra_clk_m_div_ops, 0, - clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m); - -static struct clk tegra_clk_m_div4; -static struct clk_tegra tegra_clk_m_div4_hw = { - .hw = { - .clk = &tegra_clk_m_div4, - }, - .mul = 1, - .div = 4, - .max_rate = 12000000, -}; -DEFINE_CLK_TEGRA(clk_m_div4, 0, &tegra_clk_m_div_ops, 0, - clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m); - -static struct clk tegra_pll_ref; -static struct clk_tegra tegra_pll_ref_hw = { - .hw = { - .clk = &tegra_pll_ref, - }, - .flags = ENABLE_ON_INIT, - .max_rate = 26000000, -}; -DEFINE_CLK_TEGRA(pll_ref, 0, &tegra_pll_ref_ops, 0, clk_m_div_parent_names, - clk_m_div_parents, &tegra_clk_m); - -#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \ - _input_max, _cf_min, _cf_max, _vco_min, \ - _vco_max, _freq_table, _lock_delay, _ops, \ - _fixed_rate, _clk_cfg_ex, _parent) \ - static struct clk tegra_##_name; \ - static const char *_name##_parent_names[] = { \ - #_parent, \ - }; \ - static struct clk *_name##_parents[] = { \ - &tegra_##_parent, \ - }; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .flags = _flags, \ - .reg = _reg, \ - .max_rate = _max_rate, \ - .u.pll = { \ - .input_min = _input_min, \ - .input_max = _input_max, \ - .cf_min = _cf_min, \ - .cf_max = _cf_max, \ - .vco_min = _vco_min, \ - .vco_max = _vco_max, \ - .freq_table = _freq_table, \ - .lock_delay = _lock_delay, \ - .fixed_rate = _fixed_rate, \ - }, \ - .clk_cfg_ex = _clk_cfg_ex, \ - }; \ - DEFINE_CLK_TEGRA(_name, 0, &_ops, CLK_IGNORE_UNUSED, \ - _name##_parent_names, _name##_parents, \ - &tegra_##_parent); - -#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \ - _max_rate, _ops, _parent, _clk_flags) \ - static const char *_name##_parent_names[] = { \ - #_parent, \ - }; \ - static struct clk *_name##_parents[] = { \ - &tegra_##_parent, \ - }; \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .flags = _flags, \ - .reg = _reg, \ - .max_rate = _max_rate, \ - .reg_shift = _reg_shift, \ - }; \ - DEFINE_CLK_TEGRA(_name, 0, &tegra30_pll_div_ops, \ - _clk_flags, _name##_parent_names, \ - _name##_parents, &tegra_##_parent); - -static struct clk_pll_freq_table tegra_pll_c_freq_table[] = { - { 12000000, 1040000000, 520, 6, 1, 8}, - { 13000000, 1040000000, 480, 6, 1, 8}, - { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */ - { 19200000, 1040000000, 325, 6, 1, 6}, - { 26000000, 1040000000, 520, 13, 1, 8}, - - { 12000000, 832000000, 416, 6, 1, 8}, - { 13000000, 832000000, 832, 13, 1, 8}, - { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */ - { 19200000, 832000000, 260, 6, 1, 8}, - { 26000000, 832000000, 416, 13, 1, 8}, - - { 12000000, 624000000, 624, 12, 1, 8}, - { 13000000, 624000000, 624, 13, 1, 8}, - { 16800000, 600000000, 520, 14, 1, 8}, - { 19200000, 624000000, 520, 16, 1, 8}, - { 26000000, 624000000, 624, 26, 1, 8}, - - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 16800000, 600000000, 500, 14, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, - - { 12000000, 520000000, 520, 12, 1, 8}, - { 13000000, 520000000, 520, 13, 1, 8}, - { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */ - { 19200000, 520000000, 325, 12, 1, 6}, - { 26000000, 520000000, 520, 26, 1, 8}, - - { 12000000, 416000000, 416, 12, 1, 8}, - { 13000000, 416000000, 416, 13, 1, 8}, - { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */ - { 19200000, 416000000, 260, 12, 1, 6}, - { 26000000, 416000000, 416, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 1400000000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300, - tegra30_pll_ops, 0, NULL, pll_ref); - -DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 700000000, - tegra30_pll_div_ops, pll_c, CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_m_freq_table[] = { - { 12000000, 666000000, 666, 12, 1, 8}, - { 13000000, 666000000, 666, 13, 1, 8}, - { 16800000, 666000000, 555, 14, 1, 8}, - { 19200000, 666000000, 555, 16, 1, 8}, - { 26000000, 666000000, 666, 26, 1, 8}, - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 16800000, 600000000, 500, 14, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_m, PLL_HAS_CPCON | PLLM, 0x90, 800000000, 2000000, 31000000, - 1000000, 6000000, 20000000, 1200000000, tegra_pll_m_freq_table, - 300, tegra30_pll_ops, 0, NULL, pll_ref); - -DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000, - tegra30_pll_div_ops, pll_m, CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_p_freq_table[] = { - { 12000000, 216000000, 432, 12, 2, 8}, - { 13000000, 216000000, 432, 13, 2, 8}, - { 16800000, 216000000, 360, 14, 2, 8}, - { 19200000, 216000000, 360, 16, 2, 8}, - { 26000000, 216000000, 432, 26, 2, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000, - 2000000, 31000000, 1000000, 6000000, 20000000, 1400000000, - tegra_pll_p_freq_table, 300, tegra30_pll_ops, 408000000, NULL, - pll_ref); - -DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, - 0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED); -DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, - 16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED); -DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, - 0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED); -DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, - 16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_a_freq_table[] = { - { 9600000, 564480000, 294, 5, 1, 4}, - { 9600000, 552960000, 288, 5, 1, 4}, - { 9600000, 24000000, 5, 2, 1, 1}, - - { 28800000, 56448000, 49, 25, 1, 1}, - { 28800000, 73728000, 64, 25, 1, 1}, - { 28800000, 24000000, 5, 6, 1, 1}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 700000000, 2000000, 31000000, 1000000, - 6000000, 20000000, 1400000000, tegra_pll_a_freq_table, - 300, tegra30_pll_ops, 0, NULL, pll_p_out1); - -DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 100000000, tegra30_pll_div_ops, - pll_a, CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_d_freq_table[] = { - { 12000000, 216000000, 216, 12, 1, 4}, - { 13000000, 216000000, 216, 13, 1, 4}, - { 16800000, 216000000, 180, 14, 1, 4}, - { 19200000, 216000000, 180, 16, 1, 4}, - { 26000000, 216000000, 216, 26, 1, 4}, - - { 12000000, 594000000, 594, 12, 1, 8}, - { 13000000, 594000000, 594, 13, 1, 8}, - { 16800000, 594000000, 495, 14, 1, 8}, - { 19200000, 594000000, 495, 16, 1, 8}, - { 26000000, 594000000, 594, 26, 1, 8}, - - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000, - 1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table, - 1000, tegra30_pll_ops, 0, tegra30_plld_clk_cfg_ex, pll_ref); - -DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops, - pll_d, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); - -DEFINE_PLL(pll_d2, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD, 0x4b8, 1000000000, - 2000000, 40000000, 1000000, 6000000, 40000000, 1000000000, - tegra_pll_d_freq_table, 1000, tegra30_pll_ops, 0, NULL, - pll_ref); - -DEFINE_PLL_OUT(pll_d2_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops, - pll_d2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 2, 12}, - { 13000000, 480000000, 960, 13, 2, 12}, - { 16800000, 480000000, 400, 7, 2, 5}, - { 19200000, 480000000, 200, 4, 2, 3}, - { 26000000, 480000000, 960, 26, 2, 12}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_u, PLL_HAS_CPCON | PLLU, 0xc0, 480000000, 2000000, 40000000, - 1000000, 6000000, 48000000, 960000000, tegra_pll_u_freq_table, - 1000, tegra30_pll_ops, 0, NULL, pll_ref); - -static struct clk_pll_freq_table tegra_pll_x_freq_table[] = { - /* 1.7 GHz */ - { 12000000, 1700000000, 850, 6, 1, 8}, - { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */ - { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */ - { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */ - { 26000000, 1700000000, 850, 13, 1, 8}, - - /* 1.6 GHz */ - { 12000000, 1600000000, 800, 6, 1, 8}, - { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */ - { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */ - { 19200000, 1600000000, 500, 6, 1, 8}, - { 26000000, 1600000000, 800, 13, 1, 8}, - - /* 1.5 GHz */ - { 12000000, 1500000000, 750, 6, 1, 8}, - { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */ - { 16800000, 1500000000, 625, 7, 1, 8}, - { 19200000, 1500000000, 625, 8, 1, 8}, - { 26000000, 1500000000, 750, 13, 1, 8}, - - /* 1.4 GHz */ - { 12000000, 1400000000, 700, 6, 1, 8}, - { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */ - { 16800000, 1400000000, 1000, 12, 1, 8}, - { 19200000, 1400000000, 875, 12, 1, 8}, - { 26000000, 1400000000, 700, 13, 1, 8}, - - /* 1.3 GHz */ - { 12000000, 1300000000, 975, 9, 1, 8}, - { 13000000, 1300000000, 1000, 10, 1, 8}, - { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */ - { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */ - { 26000000, 1300000000, 650, 13, 1, 8}, - - /* 1.2 GHz */ - { 12000000, 1200000000, 1000, 10, 1, 8}, - { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */ - { 16800000, 1200000000, 1000, 14, 1, 8}, - { 19200000, 1200000000, 1000, 16, 1, 8}, - { 26000000, 1200000000, 600, 13, 1, 8}, - - /* 1.1 GHz */ - { 12000000, 1100000000, 825, 9, 1, 8}, - { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */ - { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */ - { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */ - { 26000000, 1100000000, 550, 13, 1, 8}, - - /* 1 GHz */ - { 12000000, 1000000000, 1000, 12, 1, 8}, - { 13000000, 1000000000, 1000, 13, 1, 8}, - { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */ - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 8}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX, 0xe0, 1700000000, - 2000000, 31000000, 1000000, 6000000, 20000000, 1700000000, - tegra_pll_x_freq_table, 300, tegra30_pll_ops, 0, NULL, pll_ref); - -DEFINE_PLL_OUT(pll_x_out0, DIV_2 | PLLX, 0, 0, 850000000, tegra30_pll_div_ops, - pll_x, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); - -static struct clk_pll_freq_table tegra_pll_e_freq_table[] = { - /* PLLE special case: use cpcon field to store cml divider value */ - { 12000000, 100000000, 150, 1, 18, 11}, - { 216000000, 100000000, 200, 18, 24, 13}, - { 0, 0, 0, 0, 0, 0 }, -}; - -DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 2000000, 216000000, - 12000000, 12000000, 1200000000, 2400000000U, - tegra_pll_e_freq_table, 300, tegra30_plle_ops, 100000000, NULL, - pll_ref); - -static const char *mux_plle[] = { - "pll_e", -}; - -static struct clk *mux_plle_p[] = { - &tegra_pll_e, -}; - -static struct clk tegra_cml0; -static struct clk_tegra tegra_cml0_hw = { - .hw = { - .clk = &tegra_cml0, - }, - .reg = 0x48c, - .fixed_rate = 100000000, - .u.periph = { - .clk_num = 0, - }, -}; -DEFINE_CLK_TEGRA(cml0, 0, &tegra_cml_clk_ops, 0, mux_plle, - mux_plle_p, &tegra_pll_e); - -static struct clk tegra_cml1; -static struct clk_tegra tegra_cml1_hw = { - .hw = { - .clk = &tegra_cml1, - }, - .reg = 0x48c, - .fixed_rate = 100000000, - .u.periph = { - .clk_num = 1, - }, -}; -DEFINE_CLK_TEGRA(cml1, 0, &tegra_cml_clk_ops, 0, mux_plle, - mux_plle_p, &tegra_pll_e); - -static struct clk tegra_pciex; -static struct clk_tegra tegra_pciex_hw = { - .hw = { - .clk = &tegra_pciex, - }, - .reg = 0x48c, - .fixed_rate = 100000000, - .reset = tegra30_periph_clk_reset, - .u.periph = { - .clk_num = 74, - }, -}; -DEFINE_CLK_TEGRA(pciex, 0, &tegra_pciex_clk_ops, 0, mux_plle, - mux_plle_p, &tegra_pll_e); - -#define SYNC_SOURCE(_name) \ - static struct clk tegra_##_name##_sync; \ - static struct clk_tegra tegra_##_name##_sync_hw = { \ - .hw = { \ - .clk = &tegra_##_name##_sync, \ - }, \ - .max_rate = 24000000, \ - .fixed_rate = 24000000, \ - }; \ - static struct clk tegra_##_name##_sync = { \ - .name = #_name "_sync", \ - .hw = &tegra_##_name##_sync_hw.hw, \ - .ops = &tegra_sync_source_ops, \ - .flags = CLK_IS_ROOT, \ - }; - -SYNC_SOURCE(spdif_in); -SYNC_SOURCE(i2s0); -SYNC_SOURCE(i2s1); -SYNC_SOURCE(i2s2); -SYNC_SOURCE(i2s3); -SYNC_SOURCE(i2s4); -SYNC_SOURCE(vimclk); - -static struct clk *tegra_sync_source_list[] = { - &tegra_spdif_in_sync, - &tegra_i2s0_sync, - &tegra_i2s1_sync, - &tegra_i2s2_sync, - &tegra_i2s3_sync, - &tegra_i2s4_sync, - &tegra_vimclk_sync, -}; - -static const char *mux_audio_sync_clk[] = { - "spdif_in_sync", - "i2s0_sync", - "i2s1_sync", - "i2s2_sync", - "i2s3_sync", - "i2s4_sync", - "vimclk_sync", -}; - -#define AUDIO_SYNC_CLK(_name, _index) \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .max_rate = 24000000, \ - .reg = 0x4A0 + (_index) * 4, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra30_audio_sync_clk_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent_names = mux_audio_sync_clk, \ - .parents = tegra_sync_source_list, \ - .num_parents = ARRAY_SIZE(mux_audio_sync_clk), \ - }; - -AUDIO_SYNC_CLK(audio0, 0); -AUDIO_SYNC_CLK(audio1, 1); -AUDIO_SYNC_CLK(audio2, 2); -AUDIO_SYNC_CLK(audio3, 3); -AUDIO_SYNC_CLK(audio4, 4); -AUDIO_SYNC_CLK(audio5, 5); - -static struct clk *tegra_clk_audio_list[] = { - &tegra_audio0, - &tegra_audio1, - &tegra_audio2, - &tegra_audio3, - &tegra_audio4, - &tegra_audio5, /* SPDIF */ -}; - -#define AUDIO_SYNC_2X_CLK(_name, _index) \ - static const char *_name##_parent_names[] = { \ - "tegra_" #_name, \ - }; \ - static struct clk *_name##_parents[] = { \ - &tegra_##_name, \ - }; \ - static struct clk tegra_##_name##_2x; \ - static struct clk_tegra tegra_##_name##_2x_hw = { \ - .hw = { \ - .clk = &tegra_##_name##_2x, \ - }, \ - .flags = PERIPH_NO_RESET, \ - .max_rate = 48000000, \ - .reg = 0x49C, \ - .reg_shift = 24 + (_index), \ - .u.periph = { \ - .clk_num = 113 + (_index), \ - }, \ - }; \ - static struct clk tegra_##_name##_2x = { \ - .name = #_name "_2x", \ - .ops = &tegra30_clk_double_ops, \ - .hw = &tegra_##_name##_2x_hw.hw, \ - .parent_names = _name##_parent_names, \ - .parents = _name##_parents, \ - .parent = &tegra_##_name, \ - .num_parents = 1, \ - }; - -AUDIO_SYNC_2X_CLK(audio0, 0); -AUDIO_SYNC_2X_CLK(audio1, 1); -AUDIO_SYNC_2X_CLK(audio2, 2); -AUDIO_SYNC_2X_CLK(audio3, 3); -AUDIO_SYNC_2X_CLK(audio4, 4); -AUDIO_SYNC_2X_CLK(audio5, 5); /* SPDIF */ - -static struct clk *tegra_clk_audio_2x_list[] = { - &tegra_audio0_2x, - &tegra_audio1_2x, - &tegra_audio2_2x, - &tegra_audio3_2x, - &tegra_audio4_2x, - &tegra_audio5_2x, /* SPDIF */ -}; - -#define MUX_I2S_SPDIF(_id) \ -static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { \ - "pll_a_out0", \ - #_id "_2x", \ - "pll_p", \ - "clk_m", \ -}; \ -static struct clk *mux_pllaout0_##_id##_2x_pllp_clkm_p[] = { \ - &tegra_pll_a_out0, \ - &tegra_##_id##_2x, \ - &tegra_pll_p, \ - &tegra_clk_m, \ -}; - -MUX_I2S_SPDIF(audio0); -MUX_I2S_SPDIF(audio1); -MUX_I2S_SPDIF(audio2); -MUX_I2S_SPDIF(audio3); -MUX_I2S_SPDIF(audio4); -MUX_I2S_SPDIF(audio5); /* SPDIF */ - -static struct clk tegra_extern1; -static struct clk tegra_extern2; -static struct clk tegra_extern3; - -/* External clock outputs (through PMC) */ -#define MUX_EXTERN_OUT(_id) \ -static const char *mux_clkm_clkm2_clkm4_extern##_id[] = { \ - "clk_m", \ - "clk_m_div2", \ - "clk_m_div4", \ - "extern" #_id, \ -}; \ -static struct clk *mux_clkm_clkm2_clkm4_extern##_id##_p[] = { \ - &tegra_clk_m, \ - &tegra_clk_m_div2, \ - &tegra_clk_m_div4, \ - &tegra_extern##_id, \ -}; - -MUX_EXTERN_OUT(1); -MUX_EXTERN_OUT(2); -MUX_EXTERN_OUT(3); - -#define CLK_OUT_CLK(_name, _index) \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .lookup = { \ - .dev_id = #_name, \ - .con_id = "extern" #_index, \ - }, \ - .flags = MUX_CLK_OUT, \ - .fixed_rate = 216000000, \ - .reg = 0x1a8, \ - .u.periph = { \ - .clk_num = (_index - 1) * 8 + 2, \ - }, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra_clk_out_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent_names = mux_clkm_clkm2_clkm4_extern##_index, \ - .parents = mux_clkm_clkm2_clkm4_extern##_index##_p, \ - .num_parents = ARRAY_SIZE(mux_clkm_clkm2_clkm4_extern##_index),\ - }; - -CLK_OUT_CLK(clk_out_1, 1); -CLK_OUT_CLK(clk_out_2, 2); -CLK_OUT_CLK(clk_out_3, 3); - -static struct clk *tegra_clk_out_list[] = { - &tegra_clk_out_1, - &tegra_clk_out_2, - &tegra_clk_out_3, -}; - -static const char *mux_sclk[] = { - "clk_m", - "pll_c_out1", - "pll_p_out4", - "pll_p_out3", - "pll_p_out2", - "dummy", - "clk_32k", - "pll_m_out1", -}; - -static struct clk *mux_sclk_p[] = { - &tegra_clk_m, - &tegra_pll_c_out1, - &tegra_pll_p_out4, - &tegra_pll_p_out3, - &tegra_pll_p_out2, - NULL, - &tegra_clk_32k, - &tegra_pll_m_out1, -}; - -static struct clk tegra_clk_sclk; -static struct clk_tegra tegra_clk_sclk_hw = { - .hw = { - .clk = &tegra_clk_sclk, - }, - .reg = 0x28, - .max_rate = 334000000, - .min_rate = 40000000, -}; - -static struct clk tegra_clk_sclk = { - .name = "sclk", - .ops = &tegra30_super_ops, - .hw = &tegra_clk_sclk_hw.hw, - .parent_names = mux_sclk, - .parents = mux_sclk_p, - .num_parents = ARRAY_SIZE(mux_sclk), -}; - -static const char *tegra_hclk_parent_names[] = { - "tegra_sclk", -}; - -static struct clk *tegra_hclk_parents[] = { - &tegra_clk_sclk, -}; - -static struct clk tegra_hclk; -static struct clk_tegra tegra_hclk_hw = { - .hw = { - .clk = &tegra_hclk, - }, - .flags = DIV_BUS, - .reg = 0x30, - .reg_shift = 4, - .max_rate = 378000000, - .min_rate = 12000000, -}; -DEFINE_CLK_TEGRA(hclk, 0, &tegra30_bus_ops, 0, tegra_hclk_parent_names, - tegra_hclk_parents, &tegra_clk_sclk); - -static const char *tegra_pclk_parent_names[] = { - "tegra_hclk", -}; - -static struct clk *tegra_pclk_parents[] = { - &tegra_hclk, -}; - -static struct clk tegra_pclk; -static struct clk_tegra tegra_pclk_hw = { - .hw = { - .clk = &tegra_pclk, - }, - .flags = DIV_BUS, - .reg = 0x30, - .reg_shift = 0, - .max_rate = 167000000, - .min_rate = 12000000, -}; -DEFINE_CLK_TEGRA(pclk, 0, &tegra30_bus_ops, 0, tegra_pclk_parent_names, - tegra_pclk_parents, &tegra_hclk); - -static const char *mux_blink[] = { - "clk_32k", -}; - -static struct clk *mux_blink_p[] = { - &tegra_clk_32k, -}; - -static struct clk tegra_clk_blink; -static struct clk_tegra tegra_clk_blink_hw = { - .hw = { - .clk = &tegra_clk_blink, - }, - .reg = 0x40, - .max_rate = 32768, -}; -static struct clk tegra_clk_blink = { - .name = "blink", - .ops = &tegra30_blink_clk_ops, - .hw = &tegra_clk_blink_hw.hw, - .parent = &tegra_clk_32k, - .parent_names = mux_blink, - .parents = mux_blink_p, - .num_parents = ARRAY_SIZE(mux_blink), -}; - -static const char *mux_pllm_pllc_pllp_plla[] = { - "pll_m", - "pll_c", - "pll_p", - "pll_a_out0", -}; - -static const char *mux_pllp_pllc_pllm_clkm[] = { - "pll_p", - "pll_c", - "pll_m", - "clk_m", -}; - -static const char *mux_pllp_clkm[] = { - "pll_p", - "dummy", - "dummy", - "clk_m", -}; - -static const char *mux_pllp_plld_pllc_clkm[] = { - "pll_p", - "pll_d_out0", - "pll_c", - "clk_m", -}; - -static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = { - "pll_p", - "pll_m", - "pll_d_out0", - "pll_a_out0", - "pll_c", - "pll_d2_out0", - "clk_m", -}; - -static const char *mux_plla_pllc_pllp_clkm[] = { - "pll_a_out0", - "dummy", - "pll_p", - "clk_m" -}; - -static const char *mux_pllp_pllc_clk32_clkm[] = { - "pll_p", - "pll_c", - "clk_32k", - "clk_m", -}; - -static const char *mux_pllp_pllc_clkm_clk32[] = { - "pll_p", - "pll_c", - "clk_m", - "clk_32k", -}; - -static const char *mux_pllp_pllc_pllm[] = { - "pll_p", - "pll_c", - "pll_m", -}; - -static const char *mux_clk_m[] = { - "clk_m", -}; - -static const char *mux_pllp_out3[] = { - "pll_p_out3", -}; - -static const char *mux_plld_out0[] = { - "pll_d_out0", -}; - -static const char *mux_plld_out0_plld2_out0[] = { - "pll_d_out0", - "pll_d2_out0", -}; - -static const char *mux_clk_32k[] = { - "clk_32k", -}; - -static const char *mux_plla_clk32_pllp_clkm_plle[] = { - "pll_a_out0", - "clk_32k", - "pll_p", - "clk_m", - "pll_e", -}; - -static const char *mux_cclk_g[] = { - "clk_m", - "pll_c", - "clk_32k", - "pll_m", - "pll_p", - "pll_p_out4", - "pll_p_out3", - "dummy", - "pll_x", -}; - -static struct clk *mux_pllm_pllc_pllp_plla_p[] = { - &tegra_pll_m, - &tegra_pll_c, - &tegra_pll_p, - &tegra_pll_a_out0, -}; - -static struct clk *mux_pllp_pllc_pllm_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_pll_m, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_clkm_p[] = { - &tegra_pll_p, - NULL, - NULL, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_plld_pllc_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_d_out0, - &tegra_pll_c, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_pllm_plld_plla_pllc_plld2_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_m, - &tegra_pll_d_out0, - &tegra_pll_a_out0, - &tegra_pll_c, - &tegra_pll_d2_out0, - &tegra_clk_m, -}; - -static struct clk *mux_plla_pllc_pllp_clkm_p[] = { - &tegra_pll_a_out0, - NULL, - &tegra_pll_p, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_pllc_clk32_clkm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_clk_32k, - &tegra_clk_m, -}; - -static struct clk *mux_pllp_pllc_clkm_clk32_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_clk_m, - &tegra_clk_32k, -}; - -static struct clk *mux_pllp_pllc_pllm_p[] = { - &tegra_pll_p, - &tegra_pll_c, - &tegra_pll_m, -}; - -static struct clk *mux_clk_m_p[] = { - &tegra_clk_m, -}; - -static struct clk *mux_pllp_out3_p[] = { - &tegra_pll_p_out3, -}; - -static struct clk *mux_plld_out0_p[] = { - &tegra_pll_d_out0, -}; - -static struct clk *mux_plld_out0_plld2_out0_p[] = { - &tegra_pll_d_out0, - &tegra_pll_d2_out0, -}; - -static struct clk *mux_clk_32k_p[] = { - &tegra_clk_32k, -}; - -static struct clk *mux_plla_clk32_pllp_clkm_plle_p[] = { - &tegra_pll_a_out0, - &tegra_clk_32k, - &tegra_pll_p, - &tegra_clk_m, - &tegra_pll_e, -}; - -static struct clk *mux_cclk_g_p[] = { - &tegra_clk_m, - &tegra_pll_c, - &tegra_clk_32k, - &tegra_pll_m, - &tegra_pll_p, - &tegra_pll_p_out4, - &tegra_pll_p_out3, - NULL, - &tegra_pll_x, -}; - -static struct clk tegra_clk_cclk_g; -static struct clk_tegra tegra_clk_cclk_g_hw = { - .hw = { - .clk = &tegra_clk_cclk_g, - }, - .flags = DIV_U71 | DIV_U71_INT, - .reg = 0x368, - .max_rate = 1700000000, -}; -static struct clk tegra_clk_cclk_g = { - .name = "cclk_g", - .ops = &tegra30_super_ops, - .hw = &tegra_clk_cclk_g_hw.hw, - .parent_names = mux_cclk_g, - .parents = mux_cclk_g_p, - .num_parents = ARRAY_SIZE(mux_cclk_g), -}; - -static const char *mux_twd[] = { - "cclk_g", -}; - -static struct clk *mux_twd_p[] = { - &tegra_clk_cclk_g, -}; - -static struct clk tegra30_clk_twd; -static struct clk_tegra tegra30_clk_twd_hw = { - .hw = { - .clk = &tegra30_clk_twd, - }, - .max_rate = 1400000000, - .mul = 1, - .div = 2, -}; - -static struct clk tegra30_clk_twd = { - .name = "twd", - .ops = &tegra30_twd_ops, - .hw = &tegra30_clk_twd_hw.hw, - .parent = &tegra_clk_cclk_g, - .parent_names = mux_twd, - .parents = mux_twd_p, - .num_parents = ARRAY_SIZE(mux_twd), -}; - -#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \ - _max, _inputs, _flags) \ - static struct clk tegra_##_name; \ - static struct clk_tegra tegra_##_name##_hw = { \ - .hw = { \ - .clk = &tegra_##_name, \ - }, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - .reg = _reg, \ - .flags = _flags, \ - .max_rate = _max, \ - .u.periph = { \ - .clk_num = _clk_num, \ - }, \ - .reset = &tegra30_periph_clk_reset, \ - }; \ - static struct clk tegra_##_name = { \ - .name = #_name, \ - .ops = &tegra30_periph_clk_ops, \ - .hw = &tegra_##_name##_hw.hw, \ - .parent_names = _inputs, \ - .parents = _inputs##_p, \ - .num_parents = ARRAY_SIZE(_inputs), \ - }; - -PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB); -PERIPH_CLK(kbc, "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB); -PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(kfuse, "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(fuse, "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB); -PERIPH_CLK(fuse_burn, "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB); -PERIPH_CLK(apbif, "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0); -PERIPH_CLK(i2s0, "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(i2s1, "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(i2s2, "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(i2s3, "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(i2s4, "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(spdif_out, "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio5_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(spdif_in, "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(d_audio, "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(dam0, "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(dam1, "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(dam2, "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71); -PERIPH_CLK(hda, "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(hda2codec_2x, "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(hda2hdmi, "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0); -PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc5, "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sbc6, "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sata_oob, "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sata, "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(sata_cold, "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0); -PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(ndspeed, "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(vde, "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */ -PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); -PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); /* scales with voltage */ -PERIPH_CLK(i2c1, "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c2, "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c3, "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c4, "tegra-i2c.3", "div-clk", 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c5, "tegra-i2c.4", "div-clk", 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); -PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET); -PERIPH_CLK(3d2, "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET); -PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE); -PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET); -PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT); -PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(dtv, "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0); -PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71); -PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */ -PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8); -PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8); -PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */ -PERIPH_CLK(dsia, "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0); -PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0); -PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */ -PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET); -PERIPH_CLK(tsensor, "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71); -PERIPH_CLK(actmon, "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71); -PERIPH_CLK(extern1, "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71); -PERIPH_CLK(extern2, "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71); -PERIPH_CLK(extern3, "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71); -PERIPH_CLK(i2cslow, "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB); -PERIPH_CLK(pcie, "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(afi, "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0); -PERIPH_CLK(se, "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT); - -static struct clk tegra_dsib; -static struct clk_tegra tegra_dsib_hw = { - .hw = { - .clk = &tegra_dsib, - }, - .lookup = { - .dev_id = "tegradc.1", - .con_id = "dsib", - }, - .reg = 0xd0, - .flags = MUX | PLLD, - .max_rate = 500000000, - .u.periph = { - .clk_num = 82, - }, - .reset = &tegra30_periph_clk_reset, -}; -static struct clk tegra_dsib = { - .name = "dsib", - .ops = &tegra30_dsib_clk_ops, - .hw = &tegra_dsib_hw.hw, - .parent_names = mux_plld_out0_plld2_out0, - .parents = mux_plld_out0_plld2_out0_p, - .num_parents = ARRAY_SIZE(mux_plld_out0_plld2_out0), -}; - -static struct clk *tegra_list_clks[] = { - &tegra_apbdma, - &tegra_rtc, - &tegra_kbc, - &tegra_timer, - &tegra_kfuse, - &tegra_fuse, - &tegra_fuse_burn, - &tegra_apbif, - &tegra_i2s0, - &tegra_i2s1, - &tegra_i2s2, - &tegra_i2s3, - &tegra_i2s4, - &tegra_spdif_out, - &tegra_spdif_in, - &tegra_pwm, - &tegra_d_audio, - &tegra_dam0, - &tegra_dam1, - &tegra_dam2, - &tegra_hda, - &tegra_hda2codec_2x, - &tegra_hda2hdmi, - &tegra_sbc1, - &tegra_sbc2, - &tegra_sbc3, - &tegra_sbc4, - &tegra_sbc5, - &tegra_sbc6, - &tegra_sata_oob, - &tegra_sata, - &tegra_sata_cold, - &tegra_ndflash, - &tegra_ndspeed, - &tegra_vfir, - &tegra_sdmmc1, - &tegra_sdmmc2, - &tegra_sdmmc3, - &tegra_sdmmc4, - &tegra_vcp, - &tegra_bsea, - &tegra_bsev, - &tegra_vde, - &tegra_csite, - &tegra_la, - &tegra_owr, - &tegra_nor, - &tegra_mipi, - &tegra_i2c1, - &tegra_i2c2, - &tegra_i2c3, - &tegra_i2c4, - &tegra_i2c5, - &tegra_uarta, - &tegra_uartb, - &tegra_uartc, - &tegra_uartd, - &tegra_uarte, - &tegra_vi, - &tegra_3d, - &tegra_3d2, - &tegra_2d, - &tegra_vi_sensor, - &tegra_epp, - &tegra_mpe, - &tegra_host1x, - &tegra_cve, - &tegra_tvo, - &tegra_dtv, - &tegra_hdmi, - &tegra_tvdac, - &tegra_disp1, - &tegra_disp2, - &tegra_usbd, - &tegra_usb2, - &tegra_usb3, - &tegra_dsia, - &tegra_dsib, - &tegra_csi, - &tegra_isp, - &tegra_csus, - &tegra_tsensor, - &tegra_actmon, - &tegra_extern1, - &tegra_extern2, - &tegra_extern3, - &tegra_i2cslow, - &tegra_pcie, - &tegra_afi, - &tegra_se, -}; - -#define CLK_DUPLICATE(_name, _dev, _con) \ - { \ - .name = _name, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - } - -/* Some clocks may be used by different drivers depending on the board - * configuration. List those here to register them twice in the clock lookup - * table under two names. - */ -static struct clk_duplicate tegra_clk_duplicates[] = { - CLK_DUPLICATE("uarta", "serial8250.0", NULL), - CLK_DUPLICATE("uartb", "serial8250.1", NULL), - CLK_DUPLICATE("uartc", "serial8250.2", NULL), - CLK_DUPLICATE("uartd", "serial8250.3", NULL), - CLK_DUPLICATE("uarte", "serial8250.4", NULL), - CLK_DUPLICATE("usbd", "utmip-pad", NULL), - CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL), - CLK_DUPLICATE("usbd", "tegra-otg", NULL), - CLK_DUPLICATE("dsib", "tegradc.0", "dsib"), - CLK_DUPLICATE("dsia", "tegradc.1", "dsia"), - CLK_DUPLICATE("bsev", "tegra-avp", "bsev"), - CLK_DUPLICATE("bsev", "nvavp", "bsev"), - CLK_DUPLICATE("vde", "tegra-aes", "vde"), - CLK_DUPLICATE("bsea", "tegra-aes", "bsea"), - CLK_DUPLICATE("bsea", "nvavp", "bsea"), - CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL), - CLK_DUPLICATE("cml0", "tegra_pcie", "cml"), - CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"), - CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL), - CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL), - CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL), - CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL), - CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL), - CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL), - CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL), - CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL), - CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL), - CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL), - CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL), - CLK_DUPLICATE("twd", "smp_twd", NULL), - CLK_DUPLICATE("vcp", "nvavp", "vcp"), - CLK_DUPLICATE("i2s0", NULL, "i2s0"), - CLK_DUPLICATE("i2s1", NULL, "i2s1"), - CLK_DUPLICATE("i2s2", NULL, "i2s2"), - CLK_DUPLICATE("i2s3", NULL, "i2s3"), - CLK_DUPLICATE("i2s4", NULL, "i2s4"), - CLK_DUPLICATE("dam0", NULL, "dam0"), - CLK_DUPLICATE("dam1", NULL, "dam1"), - CLK_DUPLICATE("dam2", NULL, "dam2"), - CLK_DUPLICATE("spdif_in", NULL, "spdif_in"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), - CLK_DUPLICATE("pll_p_out3", "tegra-i2c.4", "fast-clk"), - CLK_DUPLICATE("pll_p", "tegradc.0", "parent"), - CLK_DUPLICATE("pll_p", "tegradc.1", "parent"), - CLK_DUPLICATE("pll_d2_out0", "hdmi", "parent"), -}; - -static struct clk *tegra_ptr_clks[] = { - &tegra_clk_32k, - &tegra_clk_m, - &tegra_clk_m_div2, - &tegra_clk_m_div4, - &tegra_pll_ref, - &tegra_pll_m, - &tegra_pll_m_out1, - &tegra_pll_c, - &tegra_pll_c_out1, - &tegra_pll_p, - &tegra_pll_p_out1, - &tegra_pll_p_out2, - &tegra_pll_p_out3, - &tegra_pll_p_out4, - &tegra_pll_a, - &tegra_pll_a_out0, - &tegra_pll_d, - &tegra_pll_d_out0, - &tegra_pll_d2, - &tegra_pll_d2_out0, - &tegra_pll_u, - &tegra_pll_x, - &tegra_pll_x_out0, - &tegra_pll_e, - &tegra_clk_cclk_g, - &tegra_cml0, - &tegra_cml1, - &tegra_pciex, - &tegra_clk_sclk, - &tegra_hclk, - &tegra_pclk, - &tegra_clk_blink, - &tegra30_clk_twd, -}; - -static void tegra30_init_one_clock(struct clk *c) -{ - struct clk_tegra *clk = to_clk_tegra(c->hw); - __clk_init(NULL, c); - INIT_LIST_HEAD(&clk->shared_bus_list); - if (!clk->lookup.dev_id && !clk->lookup.con_id) - clk->lookup.con_id = c->name; - clk->lookup.clk = c; - clkdev_add(&clk->lookup); - tegra_clk_add(c); -} - -void __init tegra30_init_clocks(void) -{ - int i; - struct clk *c; - - for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++) - tegra30_init_one_clock(tegra_ptr_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++) - tegra30_init_one_clock(tegra_list_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) { - c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name); - if (!c) { - pr_err("%s: Unknown duplicate clock %s\n", __func__, - tegra_clk_duplicates[i].name); - continue; - } - - tegra_clk_duplicates[i].lookup.clk = c; - clkdev_add(&tegra_clk_duplicates[i].lookup); - } - - for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++) - tegra30_init_one_clock(tegra_sync_source_list[i]); - for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++) - tegra30_init_one_clock(tegra_clk_audio_list[i]); - for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++) - tegra30_init_one_clock(tegra_clk_audio_2x_list[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) - tegra30_init_one_clock(tegra_clk_out_list[i]); - - tegra30_cpu_car_ops_init(); -} diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index a7e5a3999099..404d6f940872 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -120,8 +120,6 @@ static inline void tegra_cpu_clock_resume(void) } #endif -void tegra20_cpu_car_ops_init(void); -void tegra30_cpu_car_ops_init(void); void tegra_periph_reset_deassert(struct clk *c); void tegra_periph_reset_assert(struct clk *c); void tegra_clocks_init(void); From 3cb919022a7ab7628fcd69c28d475d2dbb1cb150 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:20 +0530 Subject: [PATCH 062/148] spi: tegra: do not use clock name to get clock Since Tegra spi devices do not have multiple clocks, no need to use clock name to get the clock. Signed-off-by: Prashant Gaikwad Acked-by: Grant Likely Signed-off-by: Stephen Warren --- drivers/spi/spi-tegra20-sflash.c | 2 +- drivers/spi/spi-tegra20-slink.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 02feaa51a0fa..e5dce91b74ca 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -525,7 +525,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) goto exit_free_master; } - tsd->clk = devm_clk_get(&pdev->dev, "spi"); + tsd->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(tsd->clk)) { dev_err(&pdev->dev, "can not get clock\n"); ret = PTR_ERR(tsd->clk); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index fa208a5cc612..e255e7a35678 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1191,7 +1191,7 @@ static int tegra_slink_probe(struct platform_device *pdev) goto exit_free_master; } - tspi->clk = devm_clk_get(&pdev->dev, "slink"); + tspi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(tspi->clk)) { dev_err(&pdev->dev, "can not get clock\n"); ret = PTR_ERR(tspi->clk); From 8d8b43dae3b714582cbdb99d88847cc1757952ee Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:21 +0530 Subject: [PATCH 063/148] ARM: tegra: add clock properties to Tegra20 DT Add clock information to device nodes. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra20.dtsi | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 5b104f1d5003..d665a67d4358 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -9,6 +9,7 @@ reg = <0x50000000 0x00024000>; interrupts = <0 65 0x04 /* mpcore syncpt */ 0 67 0x04>; /* mpcore general */ + clocks = <&tegra_car 28>; #address-cells = <1>; #size-cells = <1>; @@ -19,41 +20,49 @@ compatible = "nvidia,tegra20-mpe"; reg = <0x54040000 0x00040000>; interrupts = <0 68 0x04>; + clocks = <&tegra_car 60>; }; vi { compatible = "nvidia,tegra20-vi"; reg = <0x54080000 0x00040000>; interrupts = <0 69 0x04>; + clocks = <&tegra_car 100>; }; epp { compatible = "nvidia,tegra20-epp"; reg = <0x540c0000 0x00040000>; interrupts = <0 70 0x04>; + clocks = <&tegra_car 19>; }; isp { compatible = "nvidia,tegra20-isp"; reg = <0x54100000 0x00040000>; interrupts = <0 71 0x04>; + clocks = <&tegra_car 23>; }; gr2d { compatible = "nvidia,tegra20-gr2d"; reg = <0x54140000 0x00040000>; interrupts = <0 72 0x04>; + clocks = <&tegra_car 21>; }; gr3d { compatible = "nvidia,tegra20-gr3d"; reg = <0x54180000 0x00040000>; + clocks = <&tegra_car 24>; }; dc@54200000 { compatible = "nvidia,tegra20-dc"; reg = <0x54200000 0x00040000>; interrupts = <0 73 0x04>; + clocks = <&tegra_car 27>, <&tegra_car 121>; + clock-names = "disp1", "parent"; rgb { status = "disabled"; @@ -64,6 +73,8 @@ compatible = "nvidia,tegra20-dc"; reg = <0x54240000 0x00040000>; interrupts = <0 74 0x04>; + clocks = <&tegra_car 26>, <&tegra_car 121>; + clock-names = "disp2", "parent"; rgb { status = "disabled"; @@ -74,6 +85,8 @@ compatible = "nvidia,tegra20-hdmi"; reg = <0x54280000 0x00040000>; interrupts = <0 75 0x04>; + clocks = <&tegra_car 51>, <&tegra_car 117>; + clock-names = "hdmi", "parent"; status = "disabled"; }; @@ -81,12 +94,14 @@ compatible = "nvidia,tegra20-tvo"; reg = <0x542c0000 0x00040000>; interrupts = <0 76 0x04>; + clocks = <&tegra_car 102>; status = "disabled"; }; dsi { compatible = "nvidia,tegra20-dsi"; reg = <0x54300000 0x00040000>; + clocks = <&tegra_car 48>; status = "disabled"; }; }; @@ -148,6 +163,7 @@ 0 117 0x04 0 118 0x04 0 119 0x04>; + clocks = <&tegra_car 34>; }; ahb { @@ -189,6 +205,7 @@ reg = <0x70002800 0x200>; interrupts = <0 13 0x04>; nvidia,dma-request-selector = <&apbdma 2>; + clocks = <&tegra_car 11>; status = "disabled"; }; @@ -197,6 +214,7 @@ reg = <0x70002a00 0x200>; interrupts = <0 3 0x04>; nvidia,dma-request-selector = <&apbdma 1>; + clocks = <&tegra_car 18>; status = "disabled"; }; @@ -205,6 +223,7 @@ reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <0 36 0x04>; + clocks = <&tegra_car 6>; status = "disabled"; }; @@ -213,6 +232,7 @@ reg = <0x70006040 0x40>; reg-shift = <2>; interrupts = <0 37 0x04>; + clocks = <&tegra_car 96>; status = "disabled"; }; @@ -221,6 +241,7 @@ reg = <0x70006200 0x100>; reg-shift = <2>; interrupts = <0 46 0x04>; + clocks = <&tegra_car 55>; status = "disabled"; }; @@ -229,6 +250,7 @@ reg = <0x70006300 0x100>; reg-shift = <2>; interrupts = <0 90 0x04>; + clocks = <&tegra_car 65>; status = "disabled"; }; @@ -237,6 +259,7 @@ reg = <0x70006400 0x100>; reg-shift = <2>; interrupts = <0 91 0x04>; + clocks = <&tegra_car 66>; status = "disabled"; }; @@ -244,6 +267,7 @@ compatible = "nvidia,tegra20-pwm"; reg = <0x7000a000 0x100>; #pwm-cells = <2>; + clocks = <&tegra_car 17>; }; rtc { @@ -258,6 +282,8 @@ interrupts = <0 38 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 12>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -268,6 +294,7 @@ nvidia,dma-request-selector = <&apbdma 11>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 43>; status = "disabled"; }; @@ -277,6 +304,8 @@ interrupts = <0 84 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 54>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -286,6 +315,8 @@ interrupts = <0 92 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 67>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -295,6 +326,8 @@ interrupts = <0 53 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 47>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -305,6 +338,7 @@ nvidia,dma-request-selector = <&apbdma 15>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 41>; status = "disabled"; }; @@ -315,6 +349,7 @@ nvidia,dma-request-selector = <&apbdma 16>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 44>; status = "disabled"; }; @@ -325,6 +360,7 @@ nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 46>; status = "disabled"; }; @@ -335,6 +371,7 @@ nvidia,dma-request-selector = <&apbdma 18>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 68>; status = "disabled"; }; @@ -369,6 +406,7 @@ interrupts = <0 20 0x04>; phy_type = "utmi"; nvidia,has-legacy-mode; + clocks = <&tegra_car 22>; status = "disabled"; }; @@ -377,6 +415,7 @@ reg = <0xc5004000 0x4000>; interrupts = <0 21 0x04>; phy_type = "ulpi"; + clocks = <&tegra_car 58>; status = "disabled"; }; @@ -385,6 +424,7 @@ reg = <0xc5008000 0x4000>; interrupts = <0 97 0x04>; phy_type = "utmi"; + clocks = <&tegra_car 59>; status = "disabled"; }; @@ -392,6 +432,7 @@ compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000000 0x200>; interrupts = <0 14 0x04>; + clocks = <&tegra_car 14>; status = "disabled"; }; @@ -399,6 +440,7 @@ compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000200 0x200>; interrupts = <0 15 0x04>; + clocks = <&tegra_car 9>; status = "disabled"; }; @@ -406,6 +448,7 @@ compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000400 0x200>; interrupts = <0 19 0x04>; + clocks = <&tegra_car 69>; status = "disabled"; }; @@ -413,6 +456,7 @@ compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000600 0x200>; interrupts = <0 31 0x04>; + clocks = <&tegra_car 15>; status = "disabled"; }; From 1cbc733d1e6626efa9b20231668fa2523f3eafeb Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:22 +0530 Subject: [PATCH 064/148] ARM: tegra: add clock properties to Tegra30 DT Add clock information to device nodes. Signed-off-by: Prashant Gaikwad [swarren: added second clock to 3d node] Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra30.dtsi | 56 +++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 6765646c2248..b1483d925878 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -9,6 +9,7 @@ reg = <0x50000000 0x00024000>; interrupts = <0 65 0x04 /* mpcore syncpt */ 0 67 0x04>; /* mpcore general */ + clocks = <&tegra_car 28>; #address-cells = <1>; #size-cells = <1>; @@ -19,41 +20,50 @@ compatible = "nvidia,tegra30-mpe"; reg = <0x54040000 0x00040000>; interrupts = <0 68 0x04>; + clocks = <&tegra_car 60>; }; vi { compatible = "nvidia,tegra30-vi"; reg = <0x54080000 0x00040000>; interrupts = <0 69 0x04>; + clocks = <&tegra_car 164>; }; epp { compatible = "nvidia,tegra30-epp"; reg = <0x540c0000 0x00040000>; interrupts = <0 70 0x04>; + clocks = <&tegra_car 19>; }; isp { compatible = "nvidia,tegra30-isp"; reg = <0x54100000 0x00040000>; interrupts = <0 71 0x04>; + clocks = <&tegra_car 23>; }; gr2d { compatible = "nvidia,tegra30-gr2d"; reg = <0x54140000 0x00040000>; interrupts = <0 72 0x04>; + clocks = <&tegra_car 21>; }; gr3d { compatible = "nvidia,tegra30-gr3d"; reg = <0x54180000 0x00040000>; + clocks = <&tegra_car 24 &tegra_car 98>; + clock-names = "3d", "3d2"; }; dc@54200000 { compatible = "nvidia,tegra30-dc"; reg = <0x54200000 0x00040000>; interrupts = <0 73 0x04>; + clocks = <&tegra_car 27>, <&tegra_car 179>; + clock-names = "disp1", "parent"; rgb { status = "disabled"; @@ -64,6 +74,8 @@ compatible = "nvidia,tegra30-dc"; reg = <0x54240000 0x00040000>; interrupts = <0 74 0x04>; + clocks = <&tegra_car 26>, <&tegra_car 179>; + clock-names = "disp2", "parent"; rgb { status = "disabled"; @@ -74,6 +86,8 @@ compatible = "nvidia,tegra30-hdmi"; reg = <0x54280000 0x00040000>; interrupts = <0 75 0x04>; + clocks = <&tegra_car 51>, <&tegra_car 189>; + clock-names = "hdmi", "parent"; status = "disabled"; }; @@ -81,12 +95,14 @@ compatible = "nvidia,tegra30-tvo"; reg = <0x542c0000 0x00040000>; interrupts = <0 76 0x04>; + clocks = <&tegra_car 169>; status = "disabled"; }; dsi { compatible = "nvidia,tegra30-dsi"; reg = <0x54300000 0x00040000>; + clocks = <&tegra_car 48>; status = "disabled"; }; }; @@ -166,6 +182,7 @@ 0 141 0x04 0 142 0x04 0 143 0x04>; + clocks = <&tegra_car 34>; }; ahb: ahb { @@ -201,6 +218,7 @@ reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <0 36 0x04>; + clocks = <&tegra_car 6>; status = "disabled"; }; @@ -209,6 +227,7 @@ reg = <0x70006040 0x40>; reg-shift = <2>; interrupts = <0 37 0x04>; + clocks = <&tegra_car 160>; status = "disabled"; }; @@ -217,6 +236,7 @@ reg = <0x70006200 0x100>; reg-shift = <2>; interrupts = <0 46 0x04>; + clocks = <&tegra_car 55>; status = "disabled"; }; @@ -225,6 +245,7 @@ reg = <0x70006300 0x100>; reg-shift = <2>; interrupts = <0 90 0x04>; + clocks = <&tegra_car 65>; status = "disabled"; }; @@ -233,6 +254,7 @@ reg = <0x70006400 0x100>; reg-shift = <2>; interrupts = <0 91 0x04>; + clocks = <&tegra_car 66>; status = "disabled"; }; @@ -240,6 +262,7 @@ compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm"; reg = <0x7000a000 0x100>; #pwm-cells = <2>; + clocks = <&tegra_car 17>; }; rtc { @@ -254,6 +277,8 @@ interrupts = <0 38 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 12>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -263,6 +288,8 @@ interrupts = <0 84 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 54>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -272,6 +299,8 @@ interrupts = <0 92 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 67>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -281,6 +310,8 @@ interrupts = <0 120 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 103>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -290,6 +321,8 @@ interrupts = <0 53 0x04>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 47>, <&tegra_car 182>; + clock-names = "div-clk", "fast-clk"; status = "disabled"; }; @@ -300,6 +333,7 @@ nvidia,dma-request-selector = <&apbdma 15>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 41>; status = "disabled"; }; @@ -310,6 +344,7 @@ nvidia,dma-request-selector = <&apbdma 16>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 44>; status = "disabled"; }; @@ -320,6 +355,7 @@ nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 46>; status = "disabled"; }; @@ -330,6 +366,7 @@ nvidia,dma-request-selector = <&apbdma 18>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 68>; status = "disabled"; }; @@ -340,6 +377,7 @@ nvidia,dma-request-selector = <&apbdma 27>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 104>; status = "disabled"; }; @@ -350,6 +388,7 @@ nvidia,dma-request-selector = <&apbdma 28>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 105>; status = "disabled"; }; @@ -383,7 +422,13 @@ 0x70080200 0x100>; interrupts = <0 103 0x04>; nvidia,dma-request-selector = <&apbdma 1>; - + clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>, + <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>, + <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>, + <&tegra_car 110>, <&tegra_car 162>; + clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + "i2s3", "i2s4", "dam0", "dam1", "dam2", + "spdif_in"; ranges; #address-cells = <1>; #size-cells = <1>; @@ -392,6 +437,7 @@ compatible = "nvidia,tegra30-i2s"; reg = <0x70080300 0x100>; nvidia,ahub-cif-ids = <4 4>; + clocks = <&tegra_car 30>; status = "disabled"; }; @@ -399,6 +445,7 @@ compatible = "nvidia,tegra30-i2s"; reg = <0x70080400 0x100>; nvidia,ahub-cif-ids = <5 5>; + clocks = <&tegra_car 11>; status = "disabled"; }; @@ -406,6 +453,7 @@ compatible = "nvidia,tegra30-i2s"; reg = <0x70080500 0x100>; nvidia,ahub-cif-ids = <6 6>; + clocks = <&tegra_car 18>; status = "disabled"; }; @@ -413,6 +461,7 @@ compatible = "nvidia,tegra30-i2s"; reg = <0x70080600 0x100>; nvidia,ahub-cif-ids = <7 7>; + clocks = <&tegra_car 101>; status = "disabled"; }; @@ -420,6 +469,7 @@ compatible = "nvidia,tegra30-i2s"; reg = <0x70080700 0x100>; nvidia,ahub-cif-ids = <8 8>; + clocks = <&tegra_car 102>; status = "disabled"; }; }; @@ -428,6 +478,7 @@ compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000000 0x200>; interrupts = <0 14 0x04>; + clocks = <&tegra_car 14>; status = "disabled"; }; @@ -435,6 +486,7 @@ compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000200 0x200>; interrupts = <0 15 0x04>; + clocks = <&tegra_car 9>; status = "disabled"; }; @@ -442,6 +494,7 @@ compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000400 0x200>; interrupts = <0 19 0x04>; + clocks = <&tegra_car 69>; status = "disabled"; }; @@ -449,6 +502,7 @@ compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000600 0x200>; interrupts = <0 31 0x04>; + clocks = <&tegra_car 15>; status = "disabled"; }; From d409b3af89e93f1e08acf157126fc77188e2b89c Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:23 +0530 Subject: [PATCH 065/148] ARM: tegra: paz00: add clock information to DT Add clock i2c clock information to device node. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra20-paz00.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 6a93d1404c76..a965fe9c7aa1 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -266,6 +266,8 @@ clock-frequency = <80000>; request-gpios = <&gpio 170 0>; /* gpio PV2 */ slave-addr = <138>; + clocks = <&tegra_car 67>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; }; i2c@7000d000 { From 1e54f0a21e7debcd8acb0fe39adc6f81751e1b57 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:24 +0530 Subject: [PATCH 066/148] staging: nvec: remove use of clk_get_sys As clock information is added to device tree clock can be looked up using clk_get. Remove use of clk_get_sys. Signed-off-by: Prashant Gaikwad Acked-by: Greg Kroah-Hartman Acked-by: Marc Dietrich Acked-by: Julian Andres Klode [swarren: updated TODO file to remove entry that requested this change] Signed-off-by: Stephen Warren --- drivers/staging/nvec/TODO | 4 ---- drivers/staging/nvec/nvec.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/staging/nvec/TODO b/drivers/staging/nvec/TODO index f950ab890e2e..e5ae42a0b44a 100644 --- a/drivers/staging/nvec/TODO +++ b/drivers/staging/nvec/TODO @@ -1,9 +1,5 @@ ToDo list (incomplete, unordered) - add compile as module support - - fix clk usage - should not be using clk_get_sys(), but clk_get(&pdev->dev, conn) - where conn is either NULL if the device only has one clock, or - the device specific name if it has multiple clocks. - move half of the nvec init stuff to i2c-tegra.c - move event handling to nvec_events - finish suspend/resume support diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index d51615b19797..9417941974f7 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -770,7 +770,7 @@ static int tegra_nvec_probe(struct platform_device *pdev) return -ENODEV; } - i2c_clk = clk_get_sys("tegra-i2c.2", "div-clk"); + i2c_clk = clk_get(&pdev->dev, "div-clk"); if (IS_ERR(i2c_clk)) { dev_err(nvec->dev, "failed to get controller clock\n"); return -ENODEV; From 79cf5918aaed097144fe7e0e455958c817c8a534 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:25 +0530 Subject: [PATCH 067/148] ASoC: tegra: remove auxdata Configlink clock information is added to device tree. Get the clocks using device node. Remove AUXDATA. Signed-off-by: Prashant Gaikwad Acked-by: Mark Brown Signed-off-by: Stephen Warren --- sound/soc/tegra/tegra30_ahub.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index bb31c4123a7b..2355630367f7 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -299,15 +299,6 @@ static const char * const configlink_clocks[] = { "spdif_in", }; -struct of_dev_auxdata ahub_auxdata[] = { - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080300, "tegra30-i2s.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080400, "tegra30-i2s.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080500, "tegra30-i2s.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080600, "tegra30-i2s.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080700, "tegra30-i2s.4", NULL), - {} -}; - #define LAST_REG(name) \ (TEGRA30_AHUB_##name + \ (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4) @@ -451,7 +442,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) * Ensure that here. */ for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) { - clk = clk_get_sys(NULL, configlink_clocks[i]); + clk = clk_get(&pdev->dev, configlink_clocks[i]); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Can't get clock %s\n", configlink_clocks[i]); @@ -569,8 +560,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) goto err_pm_disable; } - of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata, - &pdev->dev); + of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); return 0; From 0d4b5ba525827731cfb2682404633b38f0a0e18c Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:26 +0530 Subject: [PATCH 068/148] ARM: tegra20: remove auxdata Remove AUXDATA as clock are initialized from device node. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/board-dt-tegra20.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index 0c11b8af3af3..5049edf68f4f 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -70,36 +70,12 @@ static struct tegra_ehci_platform_data tegra_ehci3_pdata = { }; static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC4_BASE, "sdhci-tegra.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C_BASE, "tegra-i2c.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c-dvc", TEGRA_DVC_BASE, "tegra-i2c.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra20-i2s.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra20-i2s.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra20-das", NULL), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0", &tegra_ehci1_pdata), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1", &tegra_ehci2_pdata), OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2", &tegra_ehci3_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sflash", 0x7000c380, "spi", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D400, "spi_tegra.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D600, "spi_tegra.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D800, "spi_tegra.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000DA00, "spi_tegra.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-host1x", 0x50000000, "host1x", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54200000, "tegradc.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54240000, "tegradc.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-hdmi", 0x54280000, "hdmi", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-dsi", 0x54300000, "dsi", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-tvo", 0x542c0000, "tvo", NULL), {} }; From 3c3a8aa9ccc47c4c2c53ab35a87db3bb93c6e450 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:27 +0530 Subject: [PATCH 069/148] ARM: tegra30: remove auxdata Remove AUXDATA as clocks are initialized from device node. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/board-dt-tegra30.c | 31 +------------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 92f6014d22a1..5b58b6439db6 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -38,38 +38,9 @@ #include "common.h" #include "iomap.h" -static struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000600, "sdhci-tegra.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C000, "tegra-i2c.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C400, "tegra-i2c.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D400, "spi_tegra.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D600, "spi_tegra.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D800, "spi_tegra.2", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DA00, "spi_tegra.3", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DC00, "spi_tegra.4", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DE00, "spi_tegra.5", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-host1x", 0x50000000, "host1x", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54200000, "tegradc.0", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54240000, "tegradc.1", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-hdmi", 0x54280000, "hdmi", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-dsi", 0x54300000, "dsi", NULL), - OF_DEV_AUXDATA("nvidia,tegra30-tvo", 0x542c0000, "tvo", NULL), - {} -}; - static void __init tegra30_dt_init(void) { - of_platform_populate(NULL, of_default_bus_match_table, - tegra30_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static const char *tegra30_dt_board_compat[] = { From e5dd26302275562d8bedf885e7aa91bd73bfa041 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:28 +0530 Subject: [PATCH 070/148] clk: tegra20: remove unused TEGRA_CLK_DUPLICATE()s With device tree support added for Tegra clocks look up is done from device tree, remove unused TEGRA_CLK_DUPLICATE()s. Signed-off-by: Prashant Gaikwad Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-tegra20.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 4ae8287b0f81..077d5b9ffe22 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1189,28 +1189,11 @@ static __initdata struct tegra_clk_init_table init_table[] = { * table under two names. */ static struct tegra_clk_duplicate tegra_clk_duplicates[] = { - TEGRA_CLK_DUPLICATE(uarta, "serial8250.0", NULL), - TEGRA_CLK_DUPLICATE(uartb, "serial8250.1", NULL), - TEGRA_CLK_DUPLICATE(uartc, "serial8250.2", NULL), - TEGRA_CLK_DUPLICATE(uartd, "serial8250.3", NULL), - TEGRA_CLK_DUPLICATE(uarte, "serial8250.4", NULL), TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), - TEGRA_CLK_DUPLICATE(pll_p, "tegradc.0", "parent"), - TEGRA_CLK_DUPLICATE(pll_p, "tegradc.1", "parent"), - TEGRA_CLK_DUPLICATE(pll_d_out0, "hdmi", "parent"), - TEGRA_CLK_DUPLICATE(gr2d, "tegra_grhost", "gr2d"), - TEGRA_CLK_DUPLICATE(gr3d, "tegra_grhost", "gr3d"), - TEGRA_CLK_DUPLICATE(epp, "tegra_grhost", "epp"), - TEGRA_CLK_DUPLICATE(mpe, "tegra_grhost", "mpe"), - TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), TEGRA_CLK_DUPLICATE(cclk, NULL, "cpu"), TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.0", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.1", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.2", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.3", "fast-clk"), TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* Must be the last entry */ }; From ef3ffe5a0458606c488def757bb7f6dd013c2db5 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 11 Jan 2013 13:31:29 +0530 Subject: [PATCH 071/148] clk: tegra30: remove unused TEGRA_CLK_DUPLICATE()s With device tree support added for Tegra clocks look up is done from device tree, remove unused TEGRA_CLK_DUPLICATE()s. Signed-off-by: Prashant Gaikwad Acked-by: Mike Turquette Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-tegra30.c | 70 --------------------------------- 1 file changed, 70 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 1c2765db1199..a1638129eba4 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1654,41 +1654,6 @@ static void __init tegra30_periph_clk_init(void) clk_register_clkdev(clk, "emc", NULL); clks[emc] = clk; - /* i2c1-fast */ - clk = clk_register_fixed_factor(NULL, "i2c1-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.0"); - - /* i2c2-fast */ - clk = clk_register_fixed_factor(NULL, "i2c2-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.1"); - - /* i2c3-fast */ - clk = clk_register_fixed_factor(NULL, "i2c3-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.2"); - - /* i2c4-fast */ - clk = clk_register_fixed_factor(NULL, "i2c4-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.3"); - - /* i2c5-fast */ - clk = clk_register_fixed_factor(NULL, "i2c5-fast", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "fast-clk", "tegra-i2c.5"); - - /* dsi1-fixed */ - clk = clk_register_fixed_factor(NULL, "dsi1-fixed", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "dsi-fixed", "tegradc.0"); - - /* dsi2-fixed */ - clk = clk_register_fixed_factor(NULL, "dsi2-fixed", "pll_p_out3", - CLK_SET_RATE_PARENT, 1, 1); - clk_register_clkdev(clk, "dsi-fixed", "tegradc.1"); - for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; clk = tegra_clk_register_periph(data->name, data->parent_names, @@ -1948,19 +1913,9 @@ static __initdata struct tegra_clk_init_table init_table[] = { * table under two names. */ static struct tegra_clk_duplicate tegra_clk_duplicates[] = { - TEGRA_CLK_DUPLICATE(uarta, "serial8250.0", NULL), - TEGRA_CLK_DUPLICATE(uartb, "serial8250.1", NULL), - TEGRA_CLK_DUPLICATE(uartc, "serial8250.2", NULL), - TEGRA_CLK_DUPLICATE(uartd, "serial8250.3", NULL), - TEGRA_CLK_DUPLICATE(uarte, "serial8250.4", NULL), TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), - TEGRA_CLK_DUPLICATE(pll_p, "tegradc.0", "parent"), - TEGRA_CLK_DUPLICATE(pll_p, "tegradc.1", "parent"), - TEGRA_CLK_DUPLICATE(pll_d2_out0, "hdmi", "parent"), - TEGRA_CLK_DUPLICATE(dsib, "tegradc.0", "dsib"), - TEGRA_CLK_DUPLICATE(dsia, "tegradc.1", "dsia"), TEGRA_CLK_DUPLICATE(bsev, "tegra-avp", "bsev"), TEGRA_CLK_DUPLICATE(bsev, "nvavp", "bsev"), TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), @@ -1969,33 +1924,8 @@ static struct tegra_clk_duplicate tegra_clk_duplicates[] = { TEGRA_CLK_DUPLICATE(cml1, "tegra_sata_cml", NULL), TEGRA_CLK_DUPLICATE(cml0, "tegra_pcie", "cml"), TEGRA_CLK_DUPLICATE(pciex, "tegra_pcie", "pciex"), - TEGRA_CLK_DUPLICATE(i2c1, "tegra-i2c-slave.0", NULL), - TEGRA_CLK_DUPLICATE(i2c2, "tegra-i2c-slave.1", NULL), - TEGRA_CLK_DUPLICATE(i2c3, "tegra-i2c-slave.2", NULL), - TEGRA_CLK_DUPLICATE(i2c4, "tegra-i2c-slave.3", NULL), - TEGRA_CLK_DUPLICATE(i2c5, "tegra-i2c-slave.4", NULL), - TEGRA_CLK_DUPLICATE(sbc1, "spi_slave_tegra.0", NULL), - TEGRA_CLK_DUPLICATE(sbc2, "spi_slave_tegra.1", NULL), - TEGRA_CLK_DUPLICATE(sbc3, "spi_slave_tegra.2", NULL), - TEGRA_CLK_DUPLICATE(sbc4, "spi_slave_tegra.3", NULL), - TEGRA_CLK_DUPLICATE(sbc5, "spi_slave_tegra.4", NULL), - TEGRA_CLK_DUPLICATE(sbc6, "spi_slave_tegra.5", NULL), TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"), - TEGRA_CLK_DUPLICATE(i2s0, NULL, "i2s0"), - TEGRA_CLK_DUPLICATE(i2s1, NULL, "i2s1"), - TEGRA_CLK_DUPLICATE(i2s2, NULL, "i2s2"), - TEGRA_CLK_DUPLICATE(i2s3, NULL, "i2s3"), - TEGRA_CLK_DUPLICATE(i2s4, NULL, "i2s4"), - TEGRA_CLK_DUPLICATE(dam0, NULL, "dam0"), - TEGRA_CLK_DUPLICATE(dam1, NULL, "dam1"), - TEGRA_CLK_DUPLICATE(dam2, NULL, "dam2"), - TEGRA_CLK_DUPLICATE(spdif_in, NULL, "spdif_in"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.0", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.1", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.2", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.3", "fast-clk"), - TEGRA_CLK_DUPLICATE(pll_p_out3, "tegra-i2c.4", "fast-clk"), TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* MUST be the last entry */ }; From 16a665f805532ef3e3ff98fdbe0029dfee02df62 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Mon, 17 Dec 2012 18:31:01 +0000 Subject: [PATCH 072/148] ARM: tegra: remove USB address related macros from iomap.h USB register base address and sizes defined in iomap.h are not used in any files other than board-dt-tegra20.c. Hence removed those defines from header file and using the absolute values in board files. Signed-off-by: Venu Byravarasu Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/board-dt-tegra20.c | 6 +++--- arch/arm/mach-tegra/iomap.h | 9 --------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index 5049edf68f4f..63cfc430f9c7 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -70,11 +70,11 @@ static struct tegra_ehci_platform_data tegra_ehci3_pdata = { }; static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0", + OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0", &tegra_ehci1_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1", + OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1", &tegra_ehci2_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2", + OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2", &tegra_ehci3_pdata), {} }; diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h index db8be51cad80..399fbca27102 100644 --- a/arch/arm/mach-tegra/iomap.h +++ b/arch/arm/mach-tegra/iomap.h @@ -240,15 +240,6 @@ #define TEGRA_CSITE_BASE 0x70040000 #define TEGRA_CSITE_SIZE SZ_256K -#define TEGRA_USB_BASE 0xC5000000 -#define TEGRA_USB_SIZE SZ_16K - -#define TEGRA_USB2_BASE 0xC5004000 -#define TEGRA_USB2_SIZE SZ_16K - -#define TEGRA_USB3_BASE 0xC5008000 -#define TEGRA_USB3_SIZE SZ_16K - #define TEGRA_SDMMC1_BASE 0xC8000000 #define TEGRA_SDMMC1_SIZE SZ_512 From 5b26c94cdc1a201f3ae1aa75bf8963da53e1aa71 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Fri, 11 Jan 2013 17:31:29 -0700 Subject: [PATCH 073/148] usb: phy: use kzalloc to allocate struct tegra_usb_phy Use kzalloc instead of kmalloc to allocate struct tegra_usb_phy. This ensures that all function pointers in member u_phy are initialized to NULL. Signed-off-by: Venu Byravarasu Acked-by: Greg Kroah-Hartman Signed-off-by: Stephen Warren --- drivers/usb/phy/tegra_usb_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 9d13c81754e0..2d3cae9a785d 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -740,7 +740,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, int i; int err; - phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); + phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); if (!phy) return ERR_PTR(-ENOMEM); From b4e074788a4a461431e25906358c6e62cb8daf9d Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Thu, 13 Dec 2012 20:59:07 +0000 Subject: [PATCH 074/148] ARM: tegra: Add new DT property to USB node. As Tegra USB host driver is using instance number for resetting PORT0 twice, adding a new DT property for handling this. Signed-off-by: Venu Byravarasu Acked-by: Alan Stern Signed-off-by: Stephen Warren --- Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt | 2 ++ arch/arm/boot/dts/tegra20.dtsi | 1 + 2 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index e9b005dc7625..6ea765ad3dad 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt @@ -27,3 +27,5 @@ Optional properties: registers are accessed through the APB_MISC base address instead of the USB controller. Since this is a legacy issue it probably does not warrant a compatible string of its own. + - nvidia,needs-double-reset : boolean is to be set for some of the Tegra2 + USB ports, which need reset twice due to hardware issues. diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index d665a67d4358..88cf8332e3f7 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -407,6 +407,7 @@ phy_type = "utmi"; nvidia,has-legacy-mode; clocks = <&tegra_car 22>; + nvidia,needs-double-reset; status = "disabled"; }; From 585355c5b54e2ecdcd6463aec264d907bc416727 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Thu, 13 Dec 2012 20:59:08 +0000 Subject: [PATCH 075/148] usb: host: tegra: Resetting PORT0 based on information received via DT. Tegra USB host driver is using port instance number, to handle some of the hardware issues on SOC e.g. reset PORT0 twice etc. As instance number based handling looks ugly, making use of information passed through DT for achieving this. Signed-off-by: Venu Byravarasu Acked-by: Greg Kroah-Hartman Signed-off-by: Stephen Warren --- drivers/usb/host/ehci-tegra.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index acf17556bd87..55a9cdee2949 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -43,6 +43,7 @@ struct tegra_ehci_hcd { struct usb_phy *transceiver; int host_resumed; int port_resuming; + bool needs_double_reset; enum tegra_usb_phy_port_speed port_speed; }; @@ -184,7 +185,7 @@ static int tegra_ehci_hub_control( } /* For USB1 port we need to issue Port Reset twice internally */ - if (tegra->phy->instance == 0 && + if (tegra->needs_double_reset && (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { spin_unlock_irqrestore(&ehci->lock, flags); return tegra_ehci_internal_port_reset(ehci, status_reg); @@ -666,6 +667,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) clk_prepare_enable(tegra->emc_clk); clk_set_rate(tegra->emc_clk, 400000000); + tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, + "nvidia,needs-double-reset"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Failed to get I/O memory\n"); From 5e18150a7b4139e15e1ed7d7c938dd91f7f12354 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Tue, 15 Jan 2013 15:49:30 +0530 Subject: [PATCH 076/148] usb: phy: remove unused APIs from Tegra PHY. As tegra_usb_phy_clk_disable/enable() are not being used, removing them. Signed-off-by: Venu Byravarasu Signed-off-by: Stephen Warren --- drivers/usb/phy/tegra_usb_phy.c | 13 ------------- include/linux/usb/tegra_usb_phy.h | 4 ---- 2 files changed, 17 deletions(-) diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 2d3cae9a785d..3059384326b6 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -825,16 +825,3 @@ void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) } EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); -void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy) -{ - if (!phy_is_ulpi(phy)) - utmi_phy_clk_disable(phy); -} -EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable); - -void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy) -{ - if (!phy_is_ulpi(phy)) - utmi_phy_clk_enable(phy); -} -EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable); diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 176b1ca06ae4..34e6355a15e3 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -64,10 +64,6 @@ struct tegra_usb_phy { struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode); -void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy); - -void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy); - void tegra_usb_phy_preresume(struct tegra_usb_phy *phy); void tegra_usb_phy_postresume(struct tegra_usb_phy *phy); From e374b65c9b15c17685925e45a3f8e97c80a75e5e Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Wed, 16 Jan 2013 03:30:19 +0000 Subject: [PATCH 077/148] ARM: tegra: add DT nodes for Tegra USB PHY Add DT nodes for Tegra USB PHY along with related documentation. Also added a phandle property to controller DT node, for referring to connected PHY instance. Signed-off-by: Venu Byravarasu Signed-off-by: Stephen Warren --- .../bindings/usb/nvidia,tegra20-ehci.txt | 1 + .../bindings/usb/nvidia,tegra20-usb-phy.txt | 14 ++++++++++++ arch/arm/boot/dts/tegra20.dtsi | 22 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index 6ea765ad3dad..34c952883276 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt @@ -11,6 +11,7 @@ Required properties : - phy_type : Should be one of "ulpi" or "utmi". - nvidia,vbus-gpio : If present, specifies a gpio that needs to be activated for the bus to be powered. + - nvidia,phy : phandle of the PHY instance, the controller is connected to. Required properties for phy_type == ulpi: - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt new file mode 100644 index 000000000000..84a4c12943af --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -0,0 +1,14 @@ +Tegra SOC USB PHY + +The device node for Tegra SOC USB PHY: + +Required properties : + - compatible : Should be "nvidia,tegra20-usb-phy". + - reg : Address and length of the register set for the USB PHY interface. + - phy_type : Should be one of "ulpi" or "utmi". + +Optional properties: + - nvidia,has-legacy-mode : boolean indicates whether this controller can + operate in legacy mode (as APX 2500 / 2600). In legacy mode some + registers are accessed through the APB_MISC base address instead of + the USB controller. \ No newline at end of file diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 88cf8332e3f7..3d7ab220ae49 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -400,6 +400,25 @@ #size-cells = <0>; }; + phy1: usb-phy@c5000400 { + compatible = "nvidia,tegra20-usb-phy"; + reg = <0xc5000400 0x3c00>; + phy_type = "utmi"; + nvidia,has-legacy-mode; + }; + + phy2: usb-phy@c5004400 { + compatible = "nvidia,tegra20-usb-phy"; + reg = <0xc5004400 0x3c00>; + phy_type = "ulpi"; + }; + + phy3: usb-phy@c5008400 { + compatible = "nvidia,tegra20-usb-phy"; + reg = <0xc5008400 0x3C00>; + phy_type = "utmi"; + }; + usb@c5000000 { compatible = "nvidia,tegra20-ehci", "usb-ehci"; reg = <0xc5000000 0x4000>; @@ -408,6 +427,7 @@ nvidia,has-legacy-mode; clocks = <&tegra_car 22>; nvidia,needs-double-reset; + nvidia,phy = <&phy1>; status = "disabled"; }; @@ -417,6 +437,7 @@ interrupts = <0 21 0x04>; phy_type = "ulpi"; clocks = <&tegra_car 58>; + nvidia,phy = <&phy2>; status = "disabled"; }; @@ -426,6 +447,7 @@ interrupts = <0 97 0x04>; phy_type = "utmi"; clocks = <&tegra_car 59>; + nvidia,phy = <&phy3>; status = "disabled"; }; From 540fc9d971a6b38339dfcccb5364640b907ae423 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 22 Jan 2013 17:12:25 -0700 Subject: [PATCH 078/148] ARM: tegra: add clocks properties to USB PHY nodes The patch to add USB PHY nodes to device tree was written before Tegra supported the clocks property in device tree. Now that it does, add the required clocks properties to these nodes. This will allow all clk_get_sys() calls in tegra_usb_phy.c to be replaced by clk_get(phy->dev, clock_name), as part of converting the PHY driver to a platform driver. Acked-by: Venu Byravarasu Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra20.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 3d7ab220ae49..649391579871 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -405,18 +405,24 @@ reg = <0xc5000400 0x3c00>; phy_type = "utmi"; nvidia,has-legacy-mode; + clocks = <&tegra_car 22>, <&tegra_car 127>; + clock-names = "phy", "pll_u"; }; phy2: usb-phy@c5004400 { compatible = "nvidia,tegra20-usb-phy"; reg = <0xc5004400 0x3c00>; phy_type = "ulpi"; + clocks = <&tegra_car 94>, <&tegra_car 127>; + clock-names = "phy", "pll_u"; }; phy3: usb-phy@c5008400 { compatible = "nvidia,tegra20-usb-phy"; reg = <0xc5008400 0x3C00>; phy_type = "utmi"; + clocks = <&tegra_car 22>, <&tegra_car 127>; + clock-names = "phy", "pll_u"; }; usb@c5000000 { From 3a55c6a8b96f055783a1b9d5497f66b56a9ea0d7 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Wed, 16 Jan 2013 03:30:20 +0000 Subject: [PATCH 079/148] USB: PHY: tegra: get rid of instance number to differentiate legacy controller Tegra20 USB has 3 PHY instances. Instance 0 is based on legacy PHY interface and other two are standard interfaces. As instance number was used to differentiate legacy from standard interfaces, used DT param to get this info and processed accordingly. Signed-off-by: Venu Byravarasu Acked-by: Felipe Balbi Signed-off-by: Stephen Warren --- drivers/usb/phy/tegra_usb_phy.c | 32 +++++++++++++++---------------- include/linux/usb/tegra_usb_phy.h | 1 + 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 3059384326b6..79280fe90893 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -221,7 +222,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) return PTR_ERR(phy->pad_clk); } - if (phy->instance == 0) { + if (phy->is_legacy_phy) { phy->pad_regs = phy->regs; } else { phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE); @@ -236,7 +237,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) static void utmip_pad_close(struct tegra_usb_phy *phy) { - if (phy->instance != 0) + if (!phy->is_legacy_phy) iounmap(phy->pad_regs); clk_put(phy->pad_clk); } @@ -305,7 +306,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) unsigned long val; void __iomem *base = phy->regs; - if (phy->instance == 0) { + if (phy->is_legacy_phy) { val = readl(base + USB_SUSP_CTRL); val |= USB_SUSP_SET; writel(val, base + USB_SUSP_CTRL); @@ -315,9 +316,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) val = readl(base + USB_SUSP_CTRL); val &= ~USB_SUSP_SET; writel(val, base + USB_SUSP_CTRL); - } - - if (phy->instance == 2) { + } else { val = readl(base + USB_PORTSC1); val |= USB_PORTSC1_PHCD; writel(val, base + USB_PORTSC1); @@ -332,7 +331,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) unsigned long val; void __iomem *base = phy->regs; - if (phy->instance == 0) { + if (phy->is_legacy_phy) { val = readl(base + USB_SUSP_CTRL); val |= USB_SUSP_CLR; writel(val, base + USB_SUSP_CTRL); @@ -342,9 +341,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) val = readl(base + USB_SUSP_CTRL); val &= ~USB_SUSP_CLR; writel(val, base + USB_SUSP_CTRL); - } - - if (phy->instance == 2) { + } else { val = readl(base + USB_PORTSC1); val &= ~USB_PORTSC1_PHCD; writel(val, base + USB_PORTSC1); @@ -365,7 +362,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val |= UTMIP_RESET; writel(val, base + USB_SUSP_CTRL); - if (phy->instance == 0) { + if (phy->is_legacy_phy) { val = readl(base + USB1_LEGACY_CTRL); val |= USB1_NO_LEGACY_MODE; writel(val, base + USB1_LEGACY_CTRL); @@ -440,16 +437,14 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val |= UTMIP_BIAS_PDTRK_COUNT(0x5); writel(val, base + UTMIP_BIAS_CFG1); - if (phy->instance == 0) { + if (phy->is_legacy_phy) { val = readl(base + UTMIP_SPARE_CFG0); if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) val &= ~FUSE_SETUP_SEL; else val |= FUSE_SETUP_SEL; writel(val, base + UTMIP_SPARE_CFG0); - } - - if (phy->instance == 2) { + } else { val = readl(base + USB_SUSP_CTRL); val |= UTMIP_PHY_ENABLE; writel(val, base + USB_SUSP_CTRL); @@ -459,7 +454,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val &= ~UTMIP_RESET; writel(val, base + USB_SUSP_CTRL); - if (phy->instance == 0) { + if (phy->is_legacy_phy) { val = readl(base + USB1_LEGACY_CTRL); val &= ~USB1_VBUS_SENSE_CTL_MASK; val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD; @@ -472,7 +467,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) utmi_phy_clk_enable(phy); - if (phy->instance == 2) { + if (!phy->is_legacy_phy) { val = readl(base + USB_PORTSC1); val &= ~USB_PORTSC1_PTS(~0); writel(val, base + USB_PORTSC1); @@ -739,6 +734,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, unsigned long parent_rate; int i; int err; + struct device_node *np = dev->of_node; phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); if (!phy) @@ -749,6 +745,8 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, phy->config = config; phy->mode = phy_mode; phy->dev = dev; + phy->is_legacy_phy = + of_property_read_bool(np, "nvidia,has-legacy-mode"); if (!phy->config) { if (phy_is_ulpi(phy)) { diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 34e6355a15e3..f03e157abaa8 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -59,6 +59,7 @@ struct tegra_usb_phy { struct usb_phy *ulpi; struct usb_phy u_phy; struct device *dev; + bool is_legacy_phy; }; struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, From 3f9db1a19a8a17f6000973194c6a1d63c5cebf21 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Wed, 16 Jan 2013 03:30:21 +0000 Subject: [PATCH 080/148] USB: PHY: tegra: Get rid of instance number to differentiate PHY type Tegra20 USB has 3 PHY instances: Instance 1 and 3 are UTMI. Instance 2 is ULPI. As instance number was used to differentiate ULPI from UTMI, used DT param to get this info and processed accordingly. Signed-off-by: Venu Byravarasu Acked-by: Felipe Balbi [swarren: moved assignment of phy->is_ulpi_phy into this patch out of next patch.] Signed-off-by: Stephen Warren --- drivers/usb/phy/tegra_usb_phy.c | 28 ++++++++++++++-------------- include/linux/usb/tegra_usb_phy.h | 1 + 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 79280fe90893..48fa5258ce0b 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -209,11 +209,6 @@ static struct tegra_utmip_config utmip_default[] = { }, }; -static inline bool phy_is_ulpi(struct tegra_usb_phy *phy) -{ - return (phy->instance == 1); -} - static int utmip_pad_open(struct tegra_usb_phy *phy) { phy->pad_clk = clk_get_sys("utmip-pad", NULL); @@ -655,7 +650,7 @@ static int tegra_phy_init(struct usb_phy *x) struct tegra_ulpi_config *ulpi_config; int err; - if (phy_is_ulpi(phy)) { + if (phy->is_ulpi_phy) { ulpi_config = phy->config; phy->clk = clk_get_sys(NULL, ulpi_config->clk); if (IS_ERR(phy->clk)) { @@ -693,7 +688,7 @@ static void tegra_usb_phy_close(struct usb_phy *x) { struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); - if (phy_is_ulpi(phy)) + if (phy->is_ulpi_phy) clk_put(phy->clk); else utmip_pad_close(phy); @@ -704,7 +699,7 @@ static void tegra_usb_phy_close(struct usb_phy *x) static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) { - if (phy_is_ulpi(phy)) + if (phy->is_ulpi_phy) return ulpi_phy_power_on(phy); else return utmi_phy_power_on(phy); @@ -712,7 +707,7 @@ static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) { - if (phy_is_ulpi(phy)) + if (phy->is_ulpi_phy) return ulpi_phy_power_off(phy); else return utmi_phy_power_off(phy); @@ -747,9 +742,14 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, phy->dev = dev; phy->is_legacy_phy = of_property_read_bool(np, "nvidia,has-legacy-mode"); + err = of_property_match_string(np, "phy_type", "ulpi"); + if (err < 0) + phy->is_ulpi_phy = false; + else + phy->is_ulpi_phy = true; if (!phy->config) { - if (phy_is_ulpi(phy)) { + if (phy->is_ulpi_phy) { pr_err("%s: ulpi phy configuration missing", __func__); err = -EINVAL; goto err0; @@ -796,14 +796,14 @@ EXPORT_SYMBOL_GPL(tegra_usb_phy_open); void tegra_usb_phy_preresume(struct tegra_usb_phy *phy) { - if (!phy_is_ulpi(phy)) + if (!phy->is_ulpi_phy) utmi_phy_preresume(phy); } EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); void tegra_usb_phy_postresume(struct tegra_usb_phy *phy) { - if (!phy_is_ulpi(phy)) + if (!phy->is_ulpi_phy) utmi_phy_postresume(phy); } EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); @@ -811,14 +811,14 @@ EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, enum tegra_usb_phy_port_speed port_speed) { - if (!phy_is_ulpi(phy)) + if (!phy->is_ulpi_phy) utmi_phy_restore_start(phy, port_speed); } EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) { - if (!phy_is_ulpi(phy)) + if (!phy->is_ulpi_phy) utmi_phy_restore_end(phy); } EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index f03e157abaa8..a6a89d4866f4 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -60,6 +60,7 @@ struct tegra_usb_phy { struct usb_phy u_phy; struct device *dev; bool is_legacy_phy; + bool is_ulpi_phy; }; struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, From bbdabdb62d86090511410728644a19291bf300cf Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Thu, 17 Jan 2013 20:15:37 +0000 Subject: [PATCH 081/148] usb: add APIs to access host registers from Tegra PHY As Tegra PHY driver needs to access one of the host registers, added few APIs. Signed-off-by: Venu Byravarasu Acked-by: Alan Stern [swarren: moved assignment of phy->is_ulpi_phy to previous patch.] Signed-off-by: Stephen Warren --- drivers/usb/host/ehci-tegra.c | 51 +++++++++++++++++++++++++++++-- drivers/usb/phy/tegra_usb_phy.c | 47 ++++------------------------ include/linux/usb/tegra_usb_phy.h | 4 +++ 3 files changed, 59 insertions(+), 43 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 55a9cdee2949..1f596fb7cf71 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -2,7 +2,7 @@ * EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs * * Copyright (C) 2010 Google, Inc. - * Copyright (C) 2009 NVIDIA Corporation + * Copyright (C) 2009 - 2013 NVIDIA Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,13 +26,18 @@ #include #include #include - +#include #include #define TEGRA_USB_BASE 0xC5000000 #define TEGRA_USB2_BASE 0xC5004000 #define TEGRA_USB3_BASE 0xC5008000 +/* PORTSC registers */ +#define TEGRA_USB_PORTSC1 0x184 +#define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) +#define TEGRA_USB_PORTSC1_PHCD (1 << 23) + #define TEGRA_USB_DMA_ALIGN 32 struct tegra_ehci_hcd { @@ -605,6 +610,37 @@ static const struct dev_pm_ops tegra_ehci_pm_ops = { #endif +/* Bits of PORTSC1, which will get cleared by writing 1 into them */ +#define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) + +void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val) +{ + unsigned long val; + struct usb_hcd *hcd = bus_to_hcd(x->otg->host); + void __iomem *base = hcd->regs; + + val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; + val &= ~TEGRA_USB_PORTSC1_PTS(3); + val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3); + writel(val, base + TEGRA_USB_PORTSC1); +} +EXPORT_SYMBOL_GPL(tegra_ehci_set_pts); + +void tegra_ehci_set_phcd(struct usb_phy *x, bool enable) +{ + unsigned long val; + struct usb_hcd *hcd = bus_to_hcd(x->otg->host); + void __iomem *base = hcd->regs; + + val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; + if (enable) + val |= TEGRA_USB_PORTSC1_PHCD; + else + val &= ~TEGRA_USB_PORTSC1_PHCD; + writel(val, base + TEGRA_USB_PORTSC1); +} +EXPORT_SYMBOL_GPL(tegra_ehci_set_phcd); + static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); static int tegra_ehci_probe(struct platform_device *pdev) @@ -616,6 +652,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) int err = 0; int irq; int instance = pdev->id; + struct usb_phy *u_phy; pdata = pdev->dev.platform_data; if (!pdata) { @@ -718,6 +755,16 @@ static int tegra_ehci_probe(struct platform_device *pdev) usb_phy_init(&tegra->phy->u_phy); + hcd->phy = u_phy = &tegra->phy->u_phy; + u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), + GFP_KERNEL); + if (!u_phy->otg) { + dev_err(&pdev->dev, "Failed to alloc memory for otg\n"); + err = -ENOMEM; + goto fail_io; + } + u_phy->otg->host = hcd_to_bus(hcd); + err = usb_phy_set_suspend(&tegra->phy->u_phy, 0); if (err) { dev_err(&pdev->dev, "Failed to power on the phy\n"); diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 48fa5258ce0b..d4657045b8b1 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -36,19 +36,6 @@ #define ULPI_VIEWPORT 0x170 -#define USB_PORTSC1 0x184 -#define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) -#define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26) -#define USB_PORTSC1_PHCD (1 << 23) -#define USB_PORTSC1_WKOC (1 << 22) -#define USB_PORTSC1_WKDS (1 << 21) -#define USB_PORTSC1_WKCN (1 << 20) -#define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16) -#define USB_PORTSC1_PP (1 << 12) -#define USB_PORTSC1_SUSP (1 << 7) -#define USB_PORTSC1_PE (1 << 2) -#define USB_PORTSC1_CCS (1 << 0) - #define USB_SUSP_CTRL 0x400 #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) @@ -311,11 +298,8 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) val = readl(base + USB_SUSP_CTRL); val &= ~USB_SUSP_SET; writel(val, base + USB_SUSP_CTRL); - } else { - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_PHCD; - writel(val, base + USB_PORTSC1); - } + } else + tegra_ehci_set_phcd(&phy->u_phy, true); if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) pr_err("%s: timeout waiting for phy to stabilize\n", __func__); @@ -336,11 +320,8 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) val = readl(base + USB_SUSP_CTRL); val &= ~USB_SUSP_CLR; writel(val, base + USB_SUSP_CTRL); - } else { - val = readl(base + USB_PORTSC1); - val &= ~USB_PORTSC1_PHCD; - writel(val, base + USB_PORTSC1); - } + } else + tegra_ehci_set_phcd(&phy->u_phy, false); if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, USB_PHY_CLK_VALID)) @@ -462,11 +443,8 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) utmi_phy_clk_enable(phy); - if (!phy->is_legacy_phy) { - val = readl(base + USB_PORTSC1); - val &= ~USB_PORTSC1_PTS(~0); - writel(val, base + USB_PORTSC1); - } + if (!phy->is_legacy_phy) + tegra_ehci_set_pts(&phy->u_phy, 0); return 0; } @@ -611,10 +589,6 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) return ret; } - val = readl(base + USB_PORTSC1); - val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN; - writel(val, base + USB_PORTSC1); - val = readl(base + USB_SUSP_CTRL); val |= USB_SUSP_CLR; writel(val, base + USB_SUSP_CTRL); @@ -629,17 +603,8 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) static int ulpi_phy_power_off(struct tegra_usb_phy *phy) { - unsigned long val; - void __iomem *base = phy->regs; struct tegra_ulpi_config *config = phy->config; - /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB - * Controller to immediately bring the ULPI PHY out of low power - */ - val = readl(base + USB_PORTSC1); - val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN); - writel(val, base + USB_PORTSC1); - clk_disable(phy->clk); return gpio_direction_output(config->reset_gpio, 0); } diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index a6a89d4866f4..9259d4659582 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -75,4 +75,8 @@ void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy); +void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val); + +void tegra_ehci_set_phcd(struct usb_phy *x, bool enable); + #endif /* __TEGRA_USB_PHY_H */ From 9304512151b0933c454f0842cdb19bec23422bc5 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 22 Jan 2013 17:06:32 -0700 Subject: [PATCH 082/148] usb: host: tegra: don't touch EMC clock Clock "emc" is for the External Memory Controller. The USB driver has no business touching this clock directly. Remove the code that does so. Acked-by: Greg Kroah-Hartman Acked-by: Alan Stern Signed-off-by: Stephen Warren --- drivers/usb/host/ehci-tegra.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 1f596fb7cf71..b02622a936c2 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -44,7 +44,6 @@ struct tegra_ehci_hcd { struct ehci_hcd *ehci; struct tegra_usb_phy *phy; struct clk *clk; - struct clk *emc_clk; struct usb_phy *transceiver; int host_resumed; int port_resuming; @@ -56,7 +55,6 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - clk_prepare_enable(tegra->emc_clk); clk_prepare_enable(tegra->clk); usb_phy_set_suspend(&tegra->phy->u_phy, 0); tegra->host_resumed = 1; @@ -69,7 +67,6 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd) tegra->host_resumed = 0; usb_phy_set_suspend(&tegra->phy->u_phy, 1); clk_disable_unprepare(tegra->clk); - clk_disable_unprepare(tegra->emc_clk); } static int tegra_ehci_internal_port_reset( @@ -694,16 +691,6 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (err) goto fail_clk; - tegra->emc_clk = devm_clk_get(&pdev->dev, "emc"); - if (IS_ERR(tegra->emc_clk)) { - dev_err(&pdev->dev, "Can't get emc clock\n"); - err = PTR_ERR(tegra->emc_clk); - goto fail_emc_clk; - } - - clk_prepare_enable(tegra->emc_clk); - clk_set_rate(tegra->emc_clk, 400000000); - tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, "nvidia,needs-double-reset"); @@ -813,8 +800,6 @@ fail: #endif usb_phy_shutdown(&tegra->phy->u_phy); fail_io: - clk_disable_unprepare(tegra->emc_clk); -fail_emc_clk: clk_disable_unprepare(tegra->clk); fail_clk: usb_put_hcd(hcd); @@ -842,8 +827,6 @@ static int tegra_ehci_remove(struct platform_device *pdev) clk_disable_unprepare(tegra->clk); - clk_disable_unprepare(tegra->emc_clk); - return 0; } From d4b92fb2535a5b35cab9713d6793f1674cc45ba7 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Tue, 15 Jan 2013 22:10:26 +0000 Subject: [PATCH 083/148] ARM: tegra: add pending SGI checking API The "powered-down" CPU idle mode of Tegra cut off the vdd_cpu rail, it include the power of GIC. That caused the SGI (Software Generated Interrupt) been lost. Because the SGI can't wake up the CPU that in the "powered-down" CPU idle mode. We need to check if there is any pending SGI when go into "powered-down" CPU idle mode. This is important especially when applying the coupled cpuidle framework into "power-down" cpuidle dirver. Because the coupled cpuidle framework may have the chance that misses IPI_SINGLE_FUNC handling sometimes. For the PPI or SPI, something like the legacy peripheral interrupt. It still can be maintained by Tegra legacy interrupt controller. If there is any pending PPI or SPI when CPU in "powered-down" CPU idle mode. The CPU can be woken up immediately. So we don't need to take care the same situation for PPI or SPI. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/irq.c | 15 +++++++++++++++ arch/arm/mach-tegra/irq.h | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 arch/arm/mach-tegra/irq.h diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index b7886f183511..c9976e337bb9 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -45,6 +45,8 @@ #define FIRST_LEGACY_IRQ 32 +#define SGI_MASK 0xFFFF + static int num_ictlrs; static void __iomem *ictlr_reg_base[] = { @@ -55,6 +57,19 @@ static void __iomem *ictlr_reg_base[] = { IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE), }; +bool tegra_pending_sgi(void) +{ + u32 pending_set; + void __iomem *distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE); + + pending_set = readl_relaxed(distbase + GIC_DIST_PENDING_SET); + + if (pending_set & SGI_MASK) + return true; + + return false; +} + static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) { void __iomem *base; diff --git a/arch/arm/mach-tegra/irq.h b/arch/arm/mach-tegra/irq.h new file mode 100644 index 000000000000..5142649bba05 --- /dev/null +++ b/arch/arm/mach-tegra/irq.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012, NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TEGRA_IRQ_H +#define __TEGRA_IRQ_H + +bool tegra_pending_sgi(void); + +#endif From 5c1350bdfcebf47b3b6f83d62e5860259858a54a Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Tue, 15 Jan 2013 22:10:38 +0000 Subject: [PATCH 084/148] ARM: tegra20: cpuidle: add powered-down state for secondary CPU The powered-down state of Tegra20 requires power gating both CPU cores. When the secondary CPU requests to enter powered-down state, it saves its own contexts and then enters WFI. The Tegra20 had a limition to power down both CPU cores. The secondary CPU must waits for CPU0 in powered-down state too. If the secondary CPU be woken up before CPU0 entering powered-down state, then it needs to restore its CPU states and waits for next chance. Be aware of that, you may see the legacy power state "LP2" in the code which is exactly the same meaning of "CPU power down". Based on the work by: Colin Cross Gary King Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/cpuidle-tegra20.c | 90 +++++++++++++++- arch/arm/mach-tegra/pm.c | 3 + arch/arm/mach-tegra/sleep-tegra20.S | 147 ++++++++++++++++++++++++++ arch/arm/mach-tegra/sleep.h | 23 ++++ 4 files changed, 259 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index d32e8b0dbd4f..50f984d28faf 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -22,21 +22,99 @@ #include #include #include +#include +#include #include +#include +#include +#include + +#include "pm.h" +#include "sleep.h" + +#ifdef CONFIG_PM_SLEEP +static int tegra20_idle_lp2(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index); +#endif + +static struct cpuidle_state tegra_idle_states[] = { + [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), +#ifdef CONFIG_PM_SLEEP + [1] = { + .enter = tegra20_idle_lp2, + .exit_latency = 5000, + .target_residency = 10000, + .power_usage = 0, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "powered-down", + .desc = "CPU power gated", + }, +#endif +}; static struct cpuidle_driver tegra_idle_driver = { .name = "tegra_idle", .owner = THIS_MODULE, .en_core_tk_irqen = 1, - .state_count = 1, - .states = { - [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), - }, }; static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); +#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_SMP +static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); + + cpu_suspend(0, tegra20_sleep_cpu_secondary_finish); + + tegra20_cpu_clear_resettable(); + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); + + return true; +} +#else +static inline bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + return true; +} +#endif + +static int tegra20_idle_lp2(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; + bool entered_lp2 = false; + + local_fiq_disable(); + + tegra_set_cpu_in_lp2(cpu); + cpu_pm_enter(); + + if (cpu == 0) + cpu_do_idle(); + else + entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index); + + cpu_pm_exit(); + tegra_clear_cpu_in_lp2(cpu); + + local_fiq_enable(); + + smp_rmb(); + + return entered_lp2 ? index : 0; +} +#endif + int __init tegra20_cpuidle_init(void) { int ret; @@ -44,6 +122,10 @@ int __init tegra20_cpuidle_init(void) struct cpuidle_device *dev; struct cpuidle_driver *drv = &tegra_idle_driver; + drv->state_count = ARRAY_SIZE(tegra_idle_states); + memcpy(drv->states, tegra_idle_states, + drv->state_count * sizeof(drv->states[0])); + ret = cpuidle_register_driver(&tegra_idle_driver); if (ret) { pr_err("CPUidle driver registration failed\n"); diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index abfe9b93cc0c..523604de666f 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -36,6 +36,7 @@ #include "iomap.h" #include "reset.h" #include "flowctrl.h" +#include "fuse.h" #include "sleep.h" #define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ @@ -173,6 +174,8 @@ bool tegra_set_cpu_in_lp2(int phy_cpu_id) if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask)) last_cpu = true; + else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1) + tegra20_cpu_set_resettable_soon(); spin_unlock(&tegra_lp2_lock); return last_cpu; diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S index ad2ca07d0578..1074364e77ee 100644 --- a/arch/arm/mach-tegra/sleep-tegra20.S +++ b/arch/arm/mach-tegra/sleep-tegra20.S @@ -21,6 +21,8 @@ #include #include +#include +#include #include "sleep.h" #include "flowctrl.h" @@ -75,3 +77,148 @@ ENTRY(tegra20_cpu_shutdown) mov pc, lr ENDPROC(tegra20_cpu_shutdown) #endif + +#ifdef CONFIG_PM_SLEEP +/* + * tegra_pen_lock + * + * spinlock implementation with no atomic test-and-set and no coherence + * using Peterson's algorithm on strongly-ordered registers + * used to synchronize a cpu waking up from wfi with entering lp2 on idle + * + * The reference link of Peterson's algorithm: + * http://en.wikipedia.org/wiki/Peterson's_algorithm + * + * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm) + * on cpu 0: + * r2 = flag[0] (in SCRATCH38) + * r3 = flag[1] (in SCRATCH39) + * on cpu1: + * r2 = flag[1] (in SCRATCH39) + * r3 = flag[0] (in SCRATCH38) + * + * must be called with MMU on + * corrupts r0-r3, r12 + */ +ENTRY(tegra_pen_lock) + mov32 r3, TEGRA_PMC_VIRT + cpu_id r0 + add r1, r3, #PMC_SCRATCH37 + cmp r0, #0 + addeq r2, r3, #PMC_SCRATCH38 + addeq r3, r3, #PMC_SCRATCH39 + addne r2, r3, #PMC_SCRATCH39 + addne r3, r3, #PMC_SCRATCH38 + + mov r12, #1 + str r12, [r2] @ flag[cpu] = 1 + dsb + str r12, [r1] @ !turn = cpu +1: dsb + ldr r12, [r3] + cmp r12, #1 @ flag[!cpu] == 1? + ldreq r12, [r1] + cmpeq r12, r0 @ !turn == cpu? + beq 1b @ while !turn == cpu && flag[!cpu] == 1 + + mov pc, lr @ locked +ENDPROC(tegra_pen_lock) + +ENTRY(tegra_pen_unlock) + dsb + mov32 r3, TEGRA_PMC_VIRT + cpu_id r0 + cmp r0, #0 + addeq r2, r3, #PMC_SCRATCH38 + addne r2, r3, #PMC_SCRATCH39 + mov r12, #0 + str r12, [r2] + mov pc, lr +ENDPROC(tegra_pen_unlock) + +/* + * tegra20_cpu_clear_resettable(void) + * + * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when + * it is expected that the secondary CPU will be idle soon. + */ +ENTRY(tegra20_cpu_clear_resettable) + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 + mov r12, #CPU_NOT_RESETTABLE + str r12, [r1] + mov pc, lr +ENDPROC(tegra20_cpu_clear_resettable) + +/* + * tegra20_cpu_set_resettable_soon(void) + * + * Called to set the "resettable soon" flag in PMC_SCRATCH41 when + * it is expected that the secondary CPU will be idle soon. + */ +ENTRY(tegra20_cpu_set_resettable_soon) + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 + mov r12, #CPU_RESETTABLE_SOON + str r12, [r1] + mov pc, lr +ENDPROC(tegra20_cpu_set_resettable_soon) + +/* + * tegra20_sleep_cpu_secondary_finish(unsigned long v2p) + * + * Enters WFI on secondary CPU by exiting coherency. + */ +ENTRY(tegra20_sleep_cpu_secondary_finish) + stmfd sp!, {r4-r11, lr} + + mrc p15, 0, r11, c1, c0, 1 @ save actlr before exiting coherency + + /* Flush and disable the L1 data cache */ + bl tegra_disable_clean_inv_dcache + + mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41 + mov r3, #CPU_RESETTABLE + str r3, [r0] + + bl cpu_do_idle + + /* + * cpu may be reset while in wfi, which will return through + * tegra_resume to cpu_resume + * or interrupt may wake wfi, which will return here + * cpu state is unchanged - MMU is on, cache is on, coherency + * is off, and the data cache is off + * + * r11 contains the original actlr + */ + + bl tegra_pen_lock + + mov32 r3, TEGRA_PMC_VIRT + add r0, r3, #PMC_SCRATCH41 + mov r3, #CPU_NOT_RESETTABLE + str r3, [r0] + + bl tegra_pen_unlock + + /* Re-enable the data cache */ + mrc p15, 0, r10, c1, c0, 0 + orr r10, r10, #CR_C + mcr p15, 0, r10, c1, c0, 0 + isb + + mcr p15, 0, r11, c1, c0, 1 @ reenable coherency + + /* Invalidate the TLBs & BTAC */ + mov r1, #0 + mcr p15, 0, r1, c8, c3, 0 @ invalidate shared TLBs + mcr p15, 0, r1, c7, c1, 6 @ invalidate shared BTAC + dsb + isb + + /* the cpu was running with coherency disabled, + * caches may be out of date */ + bl v7_flush_kern_cache_louis + + ldmfd sp!, {r4 - r11, pc} +ENDPROC(tegra20_sleep_cpu_secondary_finish) +#endif diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h index 56505c381ea8..e39a56beb3a0 100644 --- a/arch/arm/mach-tegra/sleep.h +++ b/arch/arm/mach-tegra/sleep.h @@ -25,6 +25,19 @@ + IO_PPSB_VIRT) #define TEGRA_CLK_RESET_VIRT (TEGRA_CLK_RESET_BASE - IO_PPSB_PHYS \ + IO_PPSB_VIRT) +#define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT) + +/* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */ +#define PMC_SCRATCH37 0x130 +#define PMC_SCRATCH38 0x134 +#define PMC_SCRATCH39 0x138 +#define PMC_SCRATCH41 0x140 + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +#define CPU_RESETTABLE 2 +#define CPU_RESETTABLE_SOON 1 +#define CPU_NOT_RESETTABLE 0 +#endif #ifdef __ASSEMBLY__ /* returns the offset of the flow controller halt register for a cpu */ @@ -104,6 +117,8 @@ exit_l2_resume: .endm #endif /* CONFIG_CACHE_L2X0 */ #else +void tegra_pen_lock(void); +void tegra_pen_unlock(void); void tegra_resume(void); int tegra_sleep_cpu_finish(unsigned long); void tegra_disable_clean_inv_dcache(void); @@ -116,6 +131,14 @@ static inline void tegra20_hotplug_init(void) {} static inline void tegra30_hotplug_init(void) {} #endif +void tegra20_cpu_clear_resettable(void); +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +void tegra20_cpu_set_resettable_soon(void); +#else +static inline void tegra20_cpu_set_resettable_soon(void) {} +#endif + +int tegra20_sleep_cpu_secondary_finish(unsigned long); int tegra30_sleep_cpu_secondary_finish(unsigned long); void tegra30_tear_down_cpu(void); From 4a2e32794e71db679b91df1d9c98921b2e32ec4e Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Tue, 15 Jan 2013 22:10:48 +0000 Subject: [PATCH 085/148] clk: tegra20: Implementing CPU low-power function for tegra_cpu_car_ops Implementing suspend, resume and rail_off_ready API for tegra_cpu_car_ops. These functions were used for CPU powered-down state maintenance. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- drivers/clk/tegra/clk-tegra20.c | 93 +++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 077d5b9ffe22..5d41569883a7 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "clk.h" @@ -104,6 +105,13 @@ #define SUPER_SCLK_DIVIDER 0x2c #define CLK_SYSTEM_RATE 0x30 +#define CCLK_BURST_POLICY_SHIFT 28 +#define CCLK_RUN_POLICY_SHIFT 4 +#define CCLK_IDLE_POLICY_SHIFT 0 +#define CCLK_IDLE_POLICY 1 +#define CCLK_RUN_POLICY 2 +#define CCLK_BURST_POLICY_PLLX 8 + #define CLK_SOURCE_I2S1 0x100 #define CLK_SOURCE_I2S2 0x104 #define CLK_SOURCE_SPDIF_OUT 0x108 @@ -169,6 +177,17 @@ #define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) #define CPU_RESET(cpu) (0x1111ul << (cpu)) +#ifdef CONFIG_PM_SLEEP +static struct cpu_clk_suspend_context { + u32 pllx_misc; + u32 pllx_base; + + u32 cpu_burst; + u32 clk_csite_src; + u32 cclk_divider; +} tegra20_cpu_clk_sctx; +#endif + static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; static void __iomem *clk_base; @@ -1136,12 +1155,86 @@ static void tegra20_disable_cpu_clock(u32 cpu) clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); } +#ifdef CONFIG_PM_SLEEP +static bool tegra20_cpu_rail_off_ready(void) +{ + unsigned int cpu_rst_status; + + cpu_rst_status = readl(clk_base + + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); + + return !!(cpu_rst_status & 0x2); +} + +static void tegra20_cpu_clock_suspend(void) +{ + /* switch coresite to clk_m, save off original source */ + tegra20_cpu_clk_sctx.clk_csite_src = + readl(clk_base + CLK_SOURCE_CSITE); + writel(3<<30, clk_base + CLK_SOURCE_CSITE); + + tegra20_cpu_clk_sctx.cpu_burst = + readl(clk_base + CCLK_BURST_POLICY); + tegra20_cpu_clk_sctx.pllx_base = + readl(clk_base + PLLX_BASE); + tegra20_cpu_clk_sctx.pllx_misc = + readl(clk_base + PLLX_MISC); + tegra20_cpu_clk_sctx.cclk_divider = + readl(clk_base + SUPER_CCLK_DIVIDER); +} + +static void tegra20_cpu_clock_resume(void) +{ + unsigned int reg, policy; + + /* Is CPU complex already running on PLLX? */ + reg = readl(clk_base + CCLK_BURST_POLICY); + policy = (reg >> CCLK_BURST_POLICY_SHIFT) & 0xF; + + if (policy == CCLK_IDLE_POLICY) + reg = (reg >> CCLK_IDLE_POLICY_SHIFT) & 0xF; + else if (policy == CCLK_RUN_POLICY) + reg = (reg >> CCLK_RUN_POLICY_SHIFT) & 0xF; + else + BUG(); + + if (reg != CCLK_BURST_POLICY_PLLX) { + /* restore PLLX settings if CPU is on different PLL */ + writel(tegra20_cpu_clk_sctx.pllx_misc, + clk_base + PLLX_MISC); + writel(tegra20_cpu_clk_sctx.pllx_base, + clk_base + PLLX_BASE); + + /* wait for PLL stabilization if PLLX was enabled */ + if (tegra20_cpu_clk_sctx.pllx_base & (1 << 30)) + udelay(300); + } + + /* + * Restore original burst policy setting for calls resulting from CPU + * LP2 in idle or system suspend. + */ + writel(tegra20_cpu_clk_sctx.cclk_divider, + clk_base + SUPER_CCLK_DIVIDER); + writel(tegra20_cpu_clk_sctx.cpu_burst, + clk_base + CCLK_BURST_POLICY); + + writel(tegra20_cpu_clk_sctx.clk_csite_src, + clk_base + CLK_SOURCE_CSITE); +} +#endif + static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { .wait_for_reset = tegra20_wait_cpu_in_reset, .put_in_reset = tegra20_put_cpu_in_reset, .out_of_reset = tegra20_cpu_out_of_reset, .enable_clock = tegra20_enable_cpu_clock, .disable_clock = tegra20_disable_cpu_clock, +#ifdef CONFIG_PM_SLEEP + .rail_off_ready = tegra20_cpu_rail_off_ready, + .suspend = tegra20_cpu_clock_suspend, + .resume = tegra20_cpu_clock_resume, +#endif }; static __initdata struct tegra_clk_init_table init_table[] = { From afec581c4b53e03a97d9ef1b7a746a67967573cf Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Tue, 15 Jan 2013 22:11:01 +0000 Subject: [PATCH 086/148] ARM: tegra20: flowctrl: add support for cpu_suspend_enter/exit The flow controller can help CPU to go into suspend mode (powered-down state). When CPU go into powered-down state, it needs some careful settings before getting into and after leaving. The enter and exit functions do that by configuring appropriate mode for flow controller. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/flowctrl.c | 38 +++++++++++++++++++++++++++++----- arch/arm/mach-tegra/flowctrl.h | 4 ++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c index 5393eb2cae21..b477ef310dcd 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/arch/arm/mach-tegra/flowctrl.c @@ -25,6 +25,7 @@ #include "flowctrl.h" #include "iomap.h" +#include "fuse.h" static u8 flowctrl_offset_halt_cpu[] = { FLOW_CTRL_HALT_CPU0_EVENTS, @@ -75,11 +76,26 @@ void flowctrl_cpu_suspend_enter(unsigned int cpuid) int i; reg = flowctrl_read_cpu_csr(cpuid); - reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; /* clear wfe bitmap */ - reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; /* clear wfi bitmap */ + switch (tegra_chip_id) { + case TEGRA20: + /* clear wfe bitmap */ + reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP; + /* clear wfi bitmap */ + reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP; + /* pwr gating on wfe */ + reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid; + break; + case TEGRA30: + /* clear wfe bitmap */ + reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; + /* clear wfi bitmap */ + reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; + /* pwr gating on wfi */ + reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid; + break; + } reg |= FLOW_CTRL_CSR_INTR_FLAG; /* clear intr flag */ reg |= FLOW_CTRL_CSR_EVENT_FLAG; /* clear event flag */ - reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid; /* pwr gating on wfi */ reg |= FLOW_CTRL_CSR_ENABLE; /* pwr gating */ flowctrl_write_cpu_csr(cpuid, reg); @@ -99,8 +115,20 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid) /* Disable powergating via flow controller for CPU0 */ reg = flowctrl_read_cpu_csr(cpuid); - reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; /* clear wfe bitmap */ - reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; /* clear wfi bitmap */ + switch (tegra_chip_id) { + case TEGRA20: + /* clear wfe bitmap */ + reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP; + /* clear wfi bitmap */ + reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP; + break; + case TEGRA30: + /* clear wfe bitmap */ + reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; + /* clear wfi bitmap */ + reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; + break; + } reg &= ~FLOW_CTRL_CSR_ENABLE; /* clear enable */ reg |= FLOW_CTRL_CSR_INTR_FLAG; /* clear intr */ reg |= FLOW_CTRL_CSR_EVENT_FLAG; /* clear event */ diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h index 0798dec1832d..67eab56699bd 100644 --- a/arch/arm/mach-tegra/flowctrl.h +++ b/arch/arm/mach-tegra/flowctrl.h @@ -34,6 +34,10 @@ #define FLOW_CTRL_HALT_CPU1_EVENTS 0x14 #define FLOW_CTRL_CPU1_CSR 0x18 +#define TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 (1 << 4) +#define TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP (3 << 4) +#define TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP 0 + #define TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 (1 << 8) #define TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP (0xF << 4) #define TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP (0xF << 8) From 1d328606c66b9bb1c0552f585943d596f37ae3b9 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Wed, 16 Jan 2013 17:33:55 +0000 Subject: [PATCH 087/148] ARM: tegra20: cpuidle: apply coupled cpuidle for powered-down mode The "powered-down" cpuidle mode of Tegra20 needs the CPU0 be the last one core to go into this mode before other core. The coupled cpuidle framework can help to sync the MPCore to coupled state then go into "powered-down" idle mode together. The driver can just assume the MPCore come into "powered-down" mode at the same time. No need to take care if the CPU_0 goes into this mode along and only can put it into safe idle mode (WFI). The powered-down state of Tegra20 requires power gating both CPU cores. When the secondary CPU requests to enter powered-down state, it saves its own contexts and then enters WFI for waiting CPU0 in the same state. When the CPU0 requests powered-down state, it attempts to put the secondary CPU into reset to prevent it from waking up. Then power down both CPUs together and power off the cpu rail. Be aware of that, you may see the legacy power state "LP2" in the code which is exactly the same meaning of "CPU power down". Based on the work by: Colin Cross Gary King Signed-off-by: Joseph Lo Acked-by: Colin Cross Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Kconfig | 1 + arch/arm/mach-tegra/cpuidle-tegra20.c | 125 ++++++++++++++++++++++++-- arch/arm/mach-tegra/sleep-tegra20.S | 53 +++++++++++ arch/arm/mach-tegra/sleep.S | 19 ++++ arch/arm/mach-tegra/sleep.h | 3 + 5 files changed, 192 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 1ec7f80e2af5..abc688fd4807 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -4,6 +4,7 @@ comment "NVIDIA Tegra options" config ARCH_TEGRA_2x_SOC bool "Enable support for Tegra20 family" + select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_720789 select ARM_ERRATA_742230 if SMP diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 50f984d28faf..825ced4f7a40 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -32,22 +33,28 @@ #include "pm.h" #include "sleep.h" +#include "iomap.h" +#include "irq.h" +#include "flowctrl.h" #ifdef CONFIG_PM_SLEEP -static int tegra20_idle_lp2(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index); +static bool abort_flag; +static atomic_t abort_barrier; +static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index); #endif static struct cpuidle_state tegra_idle_states[] = { [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), #ifdef CONFIG_PM_SLEEP [1] = { - .enter = tegra20_idle_lp2, + .enter = tegra20_idle_lp2_coupled, .exit_latency = 5000, .target_residency = 10000, .power_usage = 0, - .flags = CPUIDLE_FLAG_TIME_VALID, + .flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_COUPLED, .name = "powered-down", .desc = "CPU power gated", }, @@ -63,6 +70,88 @@ static struct cpuidle_driver tegra_idle_driver = { static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); #ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_SMP +static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); + +static int tegra20_reset_sleeping_cpu_1(void) +{ + int ret = 0; + + tegra_pen_lock(); + + if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE) + tegra20_cpu_shutdown(1); + else + ret = -EINVAL; + + tegra_pen_unlock(); + + return ret; +} + +static void tegra20_wake_cpu1_from_reset(void) +{ + tegra_pen_lock(); + + tegra20_cpu_clear_resettable(); + + /* enable cpu clock on cpu */ + tegra_enable_cpu_clock(1); + + /* take the CPU out of reset */ + tegra_cpu_out_of_reset(1); + + /* unhalt the cpu */ + flowctrl_write_cpu_halt(1, 0); + + tegra_pen_unlock(); +} + +static int tegra20_reset_cpu_1(void) +{ + if (!cpu_online(1) || !tegra20_reset_sleeping_cpu_1()) + return 0; + + tegra20_wake_cpu1_from_reset(); + return -EBUSY; +} +#else +static inline void tegra20_wake_cpu1_from_reset(void) +{ +} + +static inline int tegra20_reset_cpu_1(void) +{ + return 0; +} +#endif + +static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + struct cpuidle_state *state = &drv->states[index]; + u32 cpu_on_time = state->exit_latency; + u32 cpu_off_time = state->target_residency - state->exit_latency; + + while (tegra20_cpu_is_resettable_soon()) + cpu_relax(); + + if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready()) + return false; + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); + + tegra_idle_lp2_last(cpu_on_time, cpu_off_time); + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); + + if (cpu_online(1)) + tegra20_wake_cpu1_from_reset(); + + return true; +} + #ifdef CONFIG_SMP static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev, struct cpuidle_driver *drv, @@ -87,20 +176,31 @@ static inline bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev, } #endif -static int tegra20_idle_lp2(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) { u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; bool entered_lp2 = false; + if (tegra_pending_sgi()) + ACCESS_ONCE(abort_flag) = true; + + cpuidle_coupled_parallel_barrier(dev, &abort_barrier); + + if (abort_flag) { + cpuidle_coupled_parallel_barrier(dev, &abort_barrier); + abort_flag = false; /* clean flag for next coming */ + return -EINTR; + } + local_fiq_disable(); tegra_set_cpu_in_lp2(cpu); cpu_pm_enter(); if (cpu == 0) - cpu_do_idle(); + entered_lp2 = tegra20_cpu_cluster_power_down(dev, drv, index); else entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index); @@ -122,6 +222,10 @@ int __init tegra20_cpuidle_init(void) struct cpuidle_device *dev; struct cpuidle_driver *drv = &tegra_idle_driver; +#ifdef CONFIG_PM_SLEEP + tegra_tear_down_cpu = tegra20_tear_down_cpu; +#endif + drv->state_count = ARRAY_SIZE(tegra_idle_states); memcpy(drv->states, tegra_idle_states, drv->state_count * sizeof(drv->states[0])); @@ -135,6 +239,9 @@ int __init tegra20_cpuidle_init(void) for_each_possible_cpu(cpu) { dev = &per_cpu(tegra_idle_device, cpu); dev->cpu = cpu; +#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED + dev->coupled_cpus = *cpu_possible_mask; +#endif dev->state_count = drv->state_count; ret = cpuidle_register_device(dev); diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S index 1074364e77ee..9f6bfafdd512 100644 --- a/arch/arm/mach-tegra/sleep-tegra20.S +++ b/arch/arm/mach-tegra/sleep-tegra20.S @@ -57,6 +57,9 @@ ENDPROC(tegra20_hotplug_shutdown) ENTRY(tegra20_cpu_shutdown) cmp r0, #0 moveq pc, lr @ must not be called for CPU 0 + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 + mov r12, #CPU_RESETTABLE + str r12, [r1] cpu_to_halt_reg r1, r0 ldr r3, =TEGRA_FLOW_CTRL_VIRT @@ -162,6 +165,21 @@ ENTRY(tegra20_cpu_set_resettable_soon) mov pc, lr ENDPROC(tegra20_cpu_set_resettable_soon) +/* + * tegra20_cpu_is_resettable_soon(void) + * + * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been + * set because it is expected that the secondary CPU will be idle soon. + */ +ENTRY(tegra20_cpu_is_resettable_soon) + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 + ldr r12, [r1] + cmp r12, #CPU_RESETTABLE_SOON + moveq r0, #1 + movne r0, #0 + mov pc, lr +ENDPROC(tegra20_cpu_is_resettable_soon) + /* * tegra20_sleep_cpu_secondary_finish(unsigned long v2p) * @@ -221,4 +239,39 @@ ENTRY(tegra20_sleep_cpu_secondary_finish) ldmfd sp!, {r4 - r11, pc} ENDPROC(tegra20_sleep_cpu_secondary_finish) + +/* + * tegra20_tear_down_cpu + * + * Switches the CPU cluster to PLL-P and enters sleep. + */ +ENTRY(tegra20_tear_down_cpu) + bl tegra_switch_cpu_to_pllp + b tegra20_enter_sleep +ENDPROC(tegra20_tear_down_cpu) + +/* + * tegra20_enter_sleep + * + * uses flow controller to enter sleep state + * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1 + * executes from SDRAM with target state is LP2 + */ +tegra20_enter_sleep: + mov32 r6, TEGRA_FLOW_CTRL_BASE + + mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT + orr r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ + cpu_id r1 + cpu_to_halt_reg r1, r1 + str r0, [r6, r1] + dsb + ldr r0, [r6, r1] /* memory barrier */ + +halted: + dsb + wfe /* CPU should be power gated here */ + isb + b halted + #endif diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S index addae357da3f..364d84523fba 100644 --- a/arch/arm/mach-tegra/sleep.S +++ b/arch/arm/mach-tegra/sleep.S @@ -34,6 +34,9 @@ #include "flowctrl.h" #include "sleep.h" +#define CLK_RESET_CCLK_BURST 0x20 +#define CLK_RESET_CCLK_DIVIDER 0x24 + #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) /* * tegra_disable_clean_inv_dcache @@ -110,4 +113,20 @@ ENTRY(tegra_shut_off_mmu) mov pc, r0 ENDPROC(tegra_shut_off_mmu) .popsection + +/* + * tegra_switch_cpu_to_pllp + * + * In LP2 the normal cpu clock pllx will be turned off. Switch the CPU to pllp + */ +ENTRY(tegra_switch_cpu_to_pllp) + /* in LP2 idle (SDRAM active), set the CPU burst policy to PLLP */ + mov32 r5, TEGRA_CLK_RESET_BASE + mov r0, #(2 << 28) @ burst policy = run mode + orr r0, r0, #(4 << 4) @ use PLLP in run mode burst + str r0, [r5, #CLK_RESET_CCLK_BURST] + mov r0, #0 + str r0, [r5, #CLK_RESET_CCLK_DIVIDER] + mov pc, lr +ENDPROC(tegra_switch_cpu_to_pllp) #endif diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h index e39a56beb3a0..4ffae541726e 100644 --- a/arch/arm/mach-tegra/sleep.h +++ b/arch/arm/mach-tegra/sleep.h @@ -131,6 +131,8 @@ static inline void tegra20_hotplug_init(void) {} static inline void tegra30_hotplug_init(void) {} #endif +void tegra20_cpu_shutdown(int cpu); +int tegra20_cpu_is_resettable_soon(void); void tegra20_cpu_clear_resettable(void); #ifdef CONFIG_ARCH_TEGRA_2x_SOC void tegra20_cpu_set_resettable_soon(void); @@ -139,6 +141,7 @@ static inline void tegra20_cpu_set_resettable_soon(void) {} #endif int tegra20_sleep_cpu_secondary_finish(unsigned long); +void tegra20_tear_down_cpu(void); int tegra30_sleep_cpu_secondary_finish(unsigned long); void tegra30_tear_down_cpu(void); From 7b30d4578a4ceb9ea3f5c3d999dfe6159092c4a0 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Thu, 24 Jan 2013 01:10:22 +0000 Subject: [PATCH 088/148] ARM: tegra: fuse: Add chip ID Tegra114 0x35 Add tegra_chip_id TEGRA114 0x35 Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/fuse.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index ff1383dd61a7..da78434678c7 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -37,6 +37,7 @@ enum tegra_revision { #define TEGRA20 0x20 #define TEGRA30 0x30 +#define TEGRA114 0x35 extern int tegra_sku_id; extern int tegra_cpu_process_id; From 18a4df70511a5591de3ffe532495d59ee1bf470c Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Thu, 24 Jan 2013 01:10:23 +0000 Subject: [PATCH 089/148] ARM: dt: tegra114: Add new SoC base, Tegra114 SoC Initial support for Tegra 114 SoC. This is expected to be included in the board DTS files, Tegra 114 SoC based evaluation board family. Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra114.dtsi | 114 ++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 arch/arm/boot/dts/tegra114.dtsi diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi new file mode 100644 index 000000000000..c5679163f7d9 --- /dev/null +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -0,0 +1,114 @@ +/include/ "skeleton.dtsi" + +/ { + compatible = "nvidia,tegra114"; + interrupt-parent = <&gic>; + + gic: interrupt-controller { + compatible = "arm,cortex-a15-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x50041000 0x1000>, + <0x50042000 0x1000>, + <0x50044000 0x2000>, + <0x50046000 0x2000>; + interrupts = <1 9 0xf04>; + }; + + timer@60005000 { + compatible = "nvidia,tegra114-timer", "nvidia,tegra20-timer"; + reg = <0x60005000 0x400>; + interrupts = <0 0 0x04 + 0 1 0x04 + 0 41 0x04 + 0 42 0x04 + 0 121 0x04 + 0 122 0x04>; + }; + + tegra_car: clock { + compatible = "nvidia,tegra114-car, nvidia,tegra30-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + + serial@70006000 { + compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart"; + reg = <0x70006000 0x40>; + reg-shift = <2>; + interrupts = <0 36 0x04>; + status = "disabled"; + }; + + serial@70006040 { + compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart"; + reg = <0x70006040 0x40>; + reg-shift = <2>; + interrupts = <0 37 0x04>; + status = "disabled"; + }; + + serial@70006200 { + compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart"; + reg = <0x70006200 0x100>; + reg-shift = <2>; + interrupts = <0 46 0x04>; + status = "disabled"; + }; + + serial@70006300 { + compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart"; + reg = <0x70006300 0x100>; + reg-shift = <2>; + interrupts = <0 90 0x04>; + status = "disabled"; + }; + + rtc { + compatible = "nvidia,tegra114-rtc", "nvidia,tegra20-rtc"; + reg = <0x7000e000 0x100>; + interrupts = <0 2 0x04>; + }; + + pmc { + compatible = "nvidia,tegra114-pmc", "nvidia,tegra30-pmc"; + reg = <0x7000e400 0x400>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <1>; + }; + + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <2>; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <3>; + }; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = <1 13 0xf08>, + <1 14 0xf08>, + <1 11 0xf08>, + <1 10 0xf08>; + }; +}; From a71c03e7fd6a4027f750e2951830669244a8dad6 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Thu, 24 Jan 2013 01:10:24 +0000 Subject: [PATCH 090/148] ARM: dt: tegra114: Add new board, Dalmore Add a new evaluation board, Dalmore for Tegra 114 family. Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/boot/dts/Makefile | 3 ++- arch/arm/boot/dts/tegra114-dalmore.dts | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/tegra114-dalmore.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index e44da40d984f..88ea9fcccc64 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -143,7 +143,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ tegra20-ventana.dtb \ tegra20-whistler.dtb \ tegra30-cardhu-a02.dtb \ - tegra30-cardhu-a04.dtb + tegra30-cardhu-a04.dtb \ + tegra114-dalmore.dtb dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ vexpress-v2p-ca9.dtb \ vexpress-v2p-ca15-tc1.dtb \ diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts new file mode 100644 index 000000000000..a30aca62658a --- /dev/null +++ b/arch/arm/boot/dts/tegra114-dalmore.dts @@ -0,0 +1,21 @@ +/dts-v1/; + +/include/ "tegra114.dtsi" + +/ { + model = "NVIDIA Tegra114 Dalmore evaluation board"; + compatible = "nvidia,dalmore", "nvidia,tegra114"; + + memory { + reg = <0x80000000 0x40000000>; + }; + + serial@70006300 { + status = "okay"; + clock-frequency = <408000000>; + }; + + pmc { + nvidia,invert-interrupt; + }; +}; From 9f19cbef99a29669a1224e3ba6ba505152247517 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Thu, 24 Jan 2013 01:10:25 +0000 Subject: [PATCH 091/148] ARM: dt: tegra114: Add new board, Pluto Add a new evaluation board, Pluto for Tegra 114 family. Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/boot/dts/Makefile | 3 ++- arch/arm/boot/dts/tegra114-pluto.dts | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/tegra114-pluto.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 88ea9fcccc64..b53f18f8d5d9 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -144,7 +144,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ tegra20-whistler.dtb \ tegra30-cardhu-a02.dtb \ tegra30-cardhu-a04.dtb \ - tegra114-dalmore.dtb + tegra114-dalmore.dtb \ + tegra114-pluto.dtb dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ vexpress-v2p-ca9.dtb \ vexpress-v2p-ca15-tc1.dtb \ diff --git a/arch/arm/boot/dts/tegra114-pluto.dts b/arch/arm/boot/dts/tegra114-pluto.dts new file mode 100644 index 000000000000..9bea8f57aa47 --- /dev/null +++ b/arch/arm/boot/dts/tegra114-pluto.dts @@ -0,0 +1,21 @@ +/dts-v1/; + +/include/ "tegra114.dtsi" + +/ { + model = "NVIDIA Tegra114 Pluto evaluation board"; + compatible = "nvidia,pluto", "nvidia,tegra114"; + + memory { + reg = <0x80000000 0x40000000>; + }; + + serial@70006300 { + status = "okay"; + clock-frequency = <408000000>; + }; + + pmc { + nvidia,invert-interrupt; + }; +}; From 5c541b884c09559723f426af2391ab07a4ca10e0 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Thu, 24 Jan 2013 01:10:26 +0000 Subject: [PATCH 092/148] ARM: tegra: Add initial support for Tegra114 SoC. Add new Tegra 114 SoC support. Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Kconfig | 10 ++++++ arch/arm/mach-tegra/Makefile | 1 + arch/arm/mach-tegra/board-dt-tegra114.c | 48 +++++++++++++++++++++++++ arch/arm/mach-tegra/common.c | 1 + 4 files changed, 60 insertions(+) create mode 100644 arch/arm/mach-tegra/board-dt-tegra114.c diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index abc688fd4807..eada60f388af 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -45,6 +45,16 @@ config ARCH_TEGRA_3x_SOC Support for NVIDIA Tegra T30 processor family, based on the ARM CortexA9MP CPU and the ARM PL310 L2 cache controller +config ARCH_TEGRA_114_SOC + bool "Enable support for Tegra114 family" + select ARM_GIC + select CPU_V7 + select ARM_L1_CACHE_SHIFT_6 + select ARM_ARCH_TIMER + help + Support for NVIDIA Tegra T114 processor family, based on the + ARM CortexA15MP CPU + config TEGRA_PCI bool "PCI Express support" depends on ARCH_TEGRA_2x_SOC diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 6018a05e808c..8165b0a477da 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_TEGRA_PCI) += pcie.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += board-dt-tegra114.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-harmony-pcie.o diff --git a/arch/arm/mach-tegra/board-dt-tegra114.c b/arch/arm/mach-tegra/board-dt-tegra114.c new file mode 100644 index 000000000000..3ed17ce884df --- /dev/null +++ b/arch/arm/mach-tegra/board-dt-tegra114.c @@ -0,0 +1,48 @@ +/* + * NVIDIA Tegra114 device tree board support + * + * Copyright (C) 2013 NVIDIA Corporation + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include +#include + +#include "board.h" +#include "common.h" + +static void __init tegra114_dt_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +static const char * const tegra114_dt_board_compat[] = { + "nvidia,tegra114", + NULL, +}; + +DT_MACHINE_START(TEGRA114_DT, "NVIDIA Tegra114 (Flattened Device Tree)") + .smp = smp_ops(tegra_smp_ops), + .map_io = tegra_map_common_io, + .init_early = tegra30_init_early, + .init_irq = tegra_dt_init_irq, + .handle_irq = gic_handle_irq, + .init_time = clocksource_of_init, + .init_machine = tegra114_dt_init, + .init_late = tegra_init_late, + .restart = tegra_assert_system_reset, + .dt_compat = tegra114_dt_board_compat, +MACHINE_END diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 87dd69ccdf8e..2f1351359a35 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -59,6 +59,7 @@ u32 tegra_uart_config[4] = { #ifdef CONFIG_OF static const struct of_device_id tegra_dt_irq_match[] __initconst = { + { .compatible = "arm,cortex-a15-gic", .data = gic_of_init }, { .compatible = "arm,cortex-a9-gic", .data = gic_of_init }, { } }; From 40e8b3a690ec0ef574c458a991eb647e56683b7d Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Thu, 24 Jan 2013 15:46:46 +0530 Subject: [PATCH 093/148] ARM: tegra: Add reset GPIO information to PHY DT node As reset GPIO information is PHY specific detail, adding it to PHY DT node. Signed-off-by: Venu Byravarasu Signed-off-by: Stephen Warren --- .../devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt | 3 +++ arch/arm/boot/dts/tegra20-harmony.dts | 4 ++++ arch/arm/boot/dts/tegra20-paz00.dts | 4 ++++ arch/arm/boot/dts/tegra20-seaboard.dts | 4 ++++ arch/arm/boot/dts/tegra20-trimslice.dts | 4 ++++ arch/arm/boot/dts/tegra20-ventana.dts | 4 ++++ 6 files changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt index 84a4c12943af..6bdaba2f0aa1 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -7,6 +7,9 @@ Required properties : - reg : Address and length of the register set for the USB PHY interface. - phy_type : Should be one of "ulpi" or "utmi". +Required properties for phy_type == ulpi: + - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. + Optional properties: - nvidia,has-legacy-mode : boolean indicates whether this controller can operate in legacy mode (as APX 2500 / 2600). In legacy mode some diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index 43eb72af8948..2b4169702c8d 100644 --- a/arch/arm/boot/dts/tegra20-harmony.dts +++ b/arch/arm/boot/dts/tegra20-harmony.dts @@ -432,6 +432,10 @@ status = "okay"; }; + usb-phy@c5004400 { + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ + }; + sdhci@c8000200 { status = "okay"; cd-gpios = <&gpio 69 0>; /* gpio PI5 */ diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index a965fe9c7aa1..11b30db63ff2 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -420,6 +420,10 @@ status = "okay"; }; + usb-phy@c5004400 { + nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */ + }; + sdhci@c8000000 { status = "okay"; cd-gpios = <&gpio 173 0>; /* gpio PV5 */ diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index 420459825b46..607bf0c6bf9c 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts @@ -561,6 +561,10 @@ status = "okay"; }; + usb-phy@c5004400 { + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ + }; + sdhci@c8000000 { status = "okay"; power-gpios = <&gpio 86 0>; /* gpio PK6 */ diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts index b70b4cb754c8..e47cf6a58b6f 100644 --- a/arch/arm/boot/dts/tegra20-trimslice.dts +++ b/arch/arm/boot/dts/tegra20-trimslice.dts @@ -310,6 +310,10 @@ status = "okay"; }; + usb-phy@c5004400 { + nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */ + }; + sdhci@c8000000 { status = "okay"; bus-width = <4>; diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts index adc47547eaae..f6c61d10fd27 100644 --- a/arch/arm/boot/dts/tegra20-ventana.dts +++ b/arch/arm/boot/dts/tegra20-ventana.dts @@ -497,6 +497,10 @@ status = "okay"; }; + usb-phy@c5004400 { + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ + }; + sdhci@c8000000 { status = "okay"; power-gpios = <&gpio 86 0>; /* gpio PK6 */ From ab137d04db5a4b32250ce5ef1b288ce6cf06adf6 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Thu, 24 Jan 2013 15:57:03 +0530 Subject: [PATCH 094/148] usb: host: tegra: make use of PHY pointer of HCD As pointer to PHY structure can be stored in struct usb_hcd making use of it, to call Tegra PHY APIs. Call to usb_phy_shutdown() is moved up in tegra_ehci_remove(), so that to avoid dereferencing of hcd after its freed up. Signed-off-by: Venu Byravarasu Acked-by: Alan Stern Acked-by: Felipe Balbi Acked-by: Greg Kroah-Hartman Signed-off-by: Stephen Warren --- drivers/usb/host/ehci-tegra.c | 27 +++++++++++++-------------- drivers/usb/phy/tegra_usb_phy.c | 16 ++++++++++++---- include/linux/usb/tegra_usb_phy.h | 8 ++++---- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index b02622a936c2..568aecc7075b 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -56,7 +56,7 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd) struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); clk_prepare_enable(tegra->clk); - usb_phy_set_suspend(&tegra->phy->u_phy, 0); + usb_phy_set_suspend(hcd->phy, 0); tegra->host_resumed = 1; } @@ -65,7 +65,7 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd) struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); tegra->host_resumed = 0; - usb_phy_set_suspend(&tegra->phy->u_phy, 1); + usb_phy_set_suspend(hcd->phy, 1); clk_disable_unprepare(tegra->clk); } @@ -159,7 +159,7 @@ static int tegra_ehci_hub_control( if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { /* Resume completed, re-enable disconnect detection */ tegra->port_resuming = 0; - tegra_usb_phy_postresume(tegra->phy); + tegra_usb_phy_postresume(hcd->phy); } } @@ -212,7 +212,7 @@ static int tegra_ehci_hub_control( goto done; /* Disable disconnect detection during port resume */ - tegra_usb_phy_preresume(tegra->phy); + tegra_usb_phy_preresume(hcd->phy); ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); @@ -476,7 +476,7 @@ static int controller_resume(struct device *dev) } /* Force the phy to keep data lines in suspend state */ - tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); + tegra_ehci_phy_restore_start(hcd->phy, tegra->port_speed); /* Enable host mode */ tdi_reset(ehci); @@ -543,17 +543,17 @@ static int controller_resume(struct device *dev) } } - tegra_ehci_phy_restore_end(tegra->phy); + tegra_ehci_phy_restore_end(hcd->phy); goto done; restart: if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) - tegra_ehci_phy_restore_end(tegra->phy); + tegra_ehci_phy_restore_end(hcd->phy); tegra_ehci_restart(hcd); done: - tegra_usb_phy_preresume(tegra->phy); + tegra_usb_phy_preresume(hcd->phy); tegra->port_resuming = 1; return 0; } @@ -740,9 +740,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_io; } - usb_phy_init(&tegra->phy->u_phy); - hcd->phy = u_phy = &tegra->phy->u_phy; + usb_phy_init(hcd->phy); + u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), GFP_KERNEL); if (!u_phy->otg) { @@ -752,7 +752,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) } u_phy->otg->host = hcd_to_bus(hcd); - err = usb_phy_set_suspend(&tegra->phy->u_phy, 0); + err = usb_phy_set_suspend(hcd->phy, 0); if (err) { dev_err(&pdev->dev, "Failed to power on the phy\n"); goto fail; @@ -798,7 +798,7 @@ fail: if (!IS_ERR_OR_NULL(tegra->transceiver)) otg_set_host(tegra->transceiver->otg, NULL); #endif - usb_phy_shutdown(&tegra->phy->u_phy); + usb_phy_shutdown(hcd->phy); fail_io: clk_disable_unprepare(tegra->clk); fail_clk: @@ -820,11 +820,10 @@ static int tegra_ehci_remove(struct platform_device *pdev) otg_set_host(tegra->transceiver->otg, NULL); #endif + usb_phy_shutdown(hcd->phy); usb_remove_hcd(hcd); usb_put_hcd(hcd); - usb_phy_shutdown(&tegra->phy->u_phy); - clk_disable_unprepare(tegra->clk); return 0; diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index d4657045b8b1..5487d38481af 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -759,30 +759,38 @@ err0: } EXPORT_SYMBOL_GPL(tegra_usb_phy_open); -void tegra_usb_phy_preresume(struct tegra_usb_phy *phy) +void tegra_usb_phy_preresume(struct usb_phy *x) { + struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + if (!phy->is_ulpi_phy) utmi_phy_preresume(phy); } EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); -void tegra_usb_phy_postresume(struct tegra_usb_phy *phy) +void tegra_usb_phy_postresume(struct usb_phy *x) { + struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + if (!phy->is_ulpi_phy) utmi_phy_postresume(phy); } EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); -void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, +void tegra_ehci_phy_restore_start(struct usb_phy *x, enum tegra_usb_phy_port_speed port_speed) { + struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + if (!phy->is_ulpi_phy) utmi_phy_restore_start(phy, port_speed); } EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); -void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) +void tegra_ehci_phy_restore_end(struct usb_phy *x) { + struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + if (!phy->is_ulpi_phy) utmi_phy_restore_end(phy); } diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 9259d4659582..9ebebe906925 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -66,14 +66,14 @@ struct tegra_usb_phy { struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode); -void tegra_usb_phy_preresume(struct tegra_usb_phy *phy); +void tegra_usb_phy_preresume(struct usb_phy *phy); -void tegra_usb_phy_postresume(struct tegra_usb_phy *phy); +void tegra_usb_phy_postresume(struct usb_phy *phy); -void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, +void tegra_ehci_phy_restore_start(struct usb_phy *phy, enum tegra_usb_phy_port_speed port_speed); -void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy); +void tegra_ehci_phy_restore_end(struct usb_phy *phy); void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val); From 0dfe42edcc0a30c21c9bbcfc8a5ad91fb49c2dfb Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 15 Jan 2013 10:17:27 +0200 Subject: [PATCH 095/148] ARM: tegra: add AHB entry to Tegra114 DT Add AHB entry. Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra114.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index c5679163f7d9..879b4ea4ff3a 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -32,6 +32,11 @@ #clock-cells = <1>; }; + ahb: ahb { + compatible = "nvidia,tegra114-ahb", "nvidia,tegra30-ahb"; + reg = <0x6000c004 0x14c>; + }; + serial@70006000 { compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart"; reg = <0x70006000 0x40>; From c5795aec8487680d748a635d6ab03766f90166ec Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 28 Jan 2013 09:41:40 +0900 Subject: [PATCH 096/148] ARM: mach-shmobile: sh73a0: Add reg and device_type properties to cpus Cc: Mark Rutland Signed-off-by: Simon Horman --- arch/arm/boot/dts/sh73a0.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi index 721f48668f98..8a59465d0231 100644 --- a/arch/arm/boot/dts/sh73a0.dtsi +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -14,11 +14,18 @@ compatible = "renesas,sh73a0"; cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + device_type = "cpu"; compatible = "arm,cortex-a9"; + reg = <0>; }; cpu@1 { + device_type = "cpu"; compatible = "arm,cortex-a9"; + reg = <1>; }; }; From fe681d2941a7dc4870753d88545a35ec5080d710 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 28 Jan 2013 09:41:40 +0900 Subject: [PATCH 097/148] ARM: mach-shmobile: emev2: Add reg and device_type properties to cpus Cc: Mark Rutland Signed-off-by: Simon Horman --- arch/arm/boot/dts/emev2.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi index eb504a6c0f4a..c8a8c08b48dd 100644 --- a/arch/arm/boot/dts/emev2.dtsi +++ b/arch/arm/boot/dts/emev2.dtsi @@ -15,11 +15,18 @@ interrupt-parent = <&gic>; cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + device_type = "cpu"; compatible = "arm,cortex-a9"; + reg = <0>; }; cpu@1 { + device_type = "cpu"; compatible = "arm,cortex-a9"; + reg = <1>; }; }; From 2da139657b108ab4485640178dd4d7f3ca931065 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 15 Jan 2013 10:17:28 +0200 Subject: [PATCH 098/148] ARM: tegra: Add SMMU entry to Tegra114 DT Add SMMU entry. Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra114.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 879b4ea4ff3a..366c177cba76 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -80,6 +80,17 @@ reg = <0x7000e400 0x400>; }; + iommu { + compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu"; + reg = <0x7000f010 0x02c + 0x7000f1f0 0x010 + 0x7000f228 0x074>; + nvidia,#asids = <4>; + dma-window = <0 0x40000000>; + nvidia,swgroups = <0x18659fe>; + nvidia,ahb = <&ahb>; + }; + cpus { #address-cells = <1>; #size-cells = <0>; From 51dc5259e8e1a05b9224e0c3ad61ebc3dc17d885 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Mon, 21 Jan 2013 17:49:06 +0800 Subject: [PATCH 099/148] ARM: tegra: add Tegra114 ARM_CPUIDLE_WFI_STATE support Adding the generic ARM_CPUIDLE_WFI_STATE support for Tegra114. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Makefile | 3 ++ arch/arm/mach-tegra/cpuidle-tegra114.c | 61 ++++++++++++++++++++++++++ arch/arm/mach-tegra/cpuidle.c | 3 ++ arch/arm/mach-tegra/cpuidle.h | 6 +++ 4 files changed, 73 insertions(+) create mode 100644 arch/arm/mach-tegra/cpuidle-tegra114.c diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 8165b0a477da..f6b46ae2b7f8 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -30,6 +30,9 @@ obj-$(CONFIG_TEGRA_PCI) += pcie.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += board-dt-tegra114.o +ifeq ($(CONFIG_CPU_IDLE),y) +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += cpuidle-tegra114.o +endif obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-harmony-pcie.o diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c new file mode 100644 index 000000000000..0f4e8c483b34 --- /dev/null +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013, NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include + +static struct cpuidle_driver tegra_idle_driver = { + .name = "tegra_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, + .state_count = 1, + .states = { + [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), + }, +}; + +static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); + +int __init tegra114_cpuidle_init(void) +{ + int ret; + unsigned int cpu; + struct cpuidle_device *dev; + struct cpuidle_driver *drv = &tegra_idle_driver; + + ret = cpuidle_register_driver(&tegra_idle_driver); + if (ret) { + pr_err("CPUidle driver registration failed\n"); + return ret; + } + + for_each_possible_cpu(cpu) { + dev = &per_cpu(tegra_idle_device, cpu); + dev->cpu = cpu; + + dev->state_count = drv->state_count; + ret = cpuidle_register_device(dev); + if (ret) { + pr_err("CPU%u: CPUidle device registration failed\n", + cpu); + return ret; + } + } + return 0; +} diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c index d0651397aec7..4b744c4661e2 100644 --- a/arch/arm/mach-tegra/cpuidle.c +++ b/arch/arm/mach-tegra/cpuidle.c @@ -38,6 +38,9 @@ static int __init tegra_cpuidle_init(void) case TEGRA30: ret = tegra30_cpuidle_init(); break; + case TEGRA114: + ret = tegra114_cpuidle_init(); + break; default: ret = -ENODEV; break; diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h index 496204d34e55..d733f75d0208 100644 --- a/arch/arm/mach-tegra/cpuidle.h +++ b/arch/arm/mach-tegra/cpuidle.h @@ -29,4 +29,10 @@ int tegra30_cpuidle_init(void); static inline int tegra30_cpuidle_init(void) { return -ENODEV; } #endif +#ifdef CONFIG_ARCH_TEGRA_114_SOC +int tegra114_cpuidle_init(void); +#else +static inline int tegra114_cpuidle_init(void) { return -ENODEV; } +#endif + #endif From 20fd4806ab5dd86c8c44788c6fc5ea19b930b635 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 29 Jan 2013 18:26:17 +0530 Subject: [PATCH 100/148] ARM: tegra114: select PINCTRL for Tegra114 SoC Select PINCTRL and PINCTRL_TEGRA114 for enabling Tegra114 pincontrol driver for Tegra114 SoC. Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index eada60f388af..bde8197c8db8 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -51,6 +51,8 @@ config ARCH_TEGRA_114_SOC select CPU_V7 select ARM_L1_CACHE_SHIFT_6 select ARM_ARCH_TIMER + select PINCTRL + select PINCTRL_TEGRA114 help Support for NVIDIA Tegra T114 processor family, based on the ARM CortexA15MP CPU From b16f9183c7c1918a3a5c36d35482f5e01dc9c384 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 29 Jan 2013 18:26:18 +0530 Subject: [PATCH 101/148] ARM: DT: tegra114: add GPIO DT entry Tegra114 has the GPIO controllers with 8 GPIO bank and each bank supports 32 pins. Add DT entry for GPIO controller. Tegra114 GPIO controller is compatible with Tegra30 GPIO controller driver. Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra114.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 366c177cba76..8f7ea189f6df 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -37,6 +37,23 @@ reg = <0x6000c004 0x14c>; }; + gpio: gpio { + compatible = "nvidia,tegra114-gpio", "nvidia,tegra30-gpio"; + reg = <0x6000d000 0x1000>; + interrupts = <0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04 + 0 125 0x04>; + #gpio-cells = <2>; + gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; + }; + serial@70006000 { compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart"; reg = <0x70006000 0x40>; From 031b77afc374cf1b86dbcda5dfa6e1bbb989836c Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 29 Jan 2013 18:26:20 +0530 Subject: [PATCH 102/148] ARM: DT: tegra114: add pinmux DT entry Add DT entry for pinmux and drive configuration addresses. Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra114.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 8f7ea189f6df..1dfaf2874c57 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -54,6 +54,12 @@ interrupt-controller; }; + pinmux: pinmux { + compatible = "nvidia,tegra114-pinmux"; + reg = <0x70000868 0x148 /* Pad control registers */ + 0x70003000 0x40c>; /* Mux registers */ + }; + serial@70006000 { compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart"; reg = <0x70006000 0x40>; From 1cd96478cf1505a32861ffed8d8f1189d1b1b8ab Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:13 -0700 Subject: [PATCH 103/148] ARM: OMAP3xxx: CPUIdle: optimize __omap3_enter_idle() Avoid programming the MPU and CORE powerdomain next-power-state registers if those powerdomains will never enter low-power states (e.g., the state that people refer to as "C1"). To avoid making assumptions about CPUIdle states based on their order in the list, use a flag to mark CPUIdle states that don't enter powerdomain low-power states. Avoid a previous-power-state register read on the MPU powerdomain unless we know that the MPU was supposed to go OFF during the last state transition. Previous-power-state register reads can be very expensive, so it's worth avoiding these when possible. Since the CORE_L3 clockdomain can't go inactive unless the MPU is active, there's little point blocking autoidle on the CORE_L3 clockdomain in "C1" state, since we've programmed the MPU clockdomain to stay active. Remove the unnecessary code. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/cpuidle34xx.c | 35 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index cba69455647a..80392fca86c6 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -39,10 +39,22 @@ struct omap3_idle_statedata { u8 mpu_state; u8 core_state; u8 per_min_state; + u8 flags; }; static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; +/* + * Possible flag bits for struct omap3_idle_statedata.flags: + * + * OMAP_CPUIDLE_CX_NO_CLKDM_IDLE: don't allow the MPU clockdomain to go + * inactive. This in turn prevents the MPU DPLL from entering autoidle + * mode, so wakeup latency is greatly reduced, at the cost of additional + * energy consumption. This also prevents the CORE clockdomain from + * entering idle. + */ +#define OMAP_CPUIDLE_CX_NO_CLKDM_IDLE BIT(0) + /* * Prevent PER OFF if CORE is not in RETention or OFF as this would * disable PER wakeups completely. @@ -53,6 +65,7 @@ static struct omap3_idle_statedata omap3_idle_data[] = { .core_state = PWRDM_POWER_ON, /* In C1 do not allow PER state lower than CORE state */ .per_min_state = PWRDM_POWER_ON, + .flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE, }, { .mpu_state = PWRDM_POWER_ON, @@ -93,27 +106,25 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, int index) { struct omap3_idle_statedata *cx = &omap3_idle_data[index]; - u32 mpu_state = cx->mpu_state, core_state = cx->core_state; local_fiq_disable(); - pwrdm_set_next_pwrst(mpu_pd, mpu_state); - pwrdm_set_next_pwrst(core_pd, core_state); - if (omap_irq_pending() || need_resched()) goto return_sleep_time; /* Deny idle for C1 */ - if (index == 0) { + if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) { clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]); - clkdm_deny_idle(core_pd->pwrdm_clkdms[0]); + } else { + pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state); + pwrdm_set_next_pwrst(core_pd, cx->core_state); } /* * Call idle CPU PM enter notifier chain so that * VFP context is saved. */ - if (mpu_state == PWRDM_POWER_OFF) + if (cx->mpu_state == PWRDM_POWER_OFF) cpu_pm_enter(); /* Execute ARM wfi */ @@ -123,17 +134,15 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, * Call idle CPU PM enter notifier chain to restore * VFP context. */ - if (pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) + if (cx->mpu_state == PWRDM_POWER_OFF && + pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) cpu_pm_exit(); /* Re-allow idle for C1 */ - if (index == 0) { + if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]); - clkdm_allow_idle(core_pd->pwrdm_clkdms[0]); - } return_sleep_time: - local_fiq_enable(); return index; @@ -198,7 +207,7 @@ static int next_valid_state(struct cpuidle_device *dev, * Start search from the next (lower) state. */ for (idx = index - 1; idx >= 0; idx--) { - cx = &omap3_idle_data[idx]; + cx = &omap3_idle_data[idx]; if ((cx->mpu_state >= mpu_deepest_state) && (cx->core_state >= core_deepest_state)) { next_index = idx; From 32d174ed1bd793e9be578914cce6b1e45c36843e Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:13 -0700 Subject: [PATCH 104/148] ARM: OMAP4: MPUSS PM: remove unnecessary shim functions for powerdomain control The OMAP4 MPU subsystem power management code contains several unnecessary shim functions for powerdomain control; remove them. Signed-off-by: Paul Walmsley Cc: Santosh Shilimkar Cc: Kevin Hilman Acked-by: Santosh Shilimkar --- arch/arm/mach-omap2/omap-mpuss-lowpower.c | 44 ++++------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index aac46bfdbeb2..8bcb64bcdcdb 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -86,37 +86,6 @@ static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr) __raw_writel(addr, pm_info->wkup_sar_addr); } -/* - * Set the CPUx powerdomain's previous power state - */ -static inline void set_cpu_next_pwrst(unsigned int cpu_id, - unsigned int power_state) -{ - struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); - - pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); -} - -/* - * Read CPU's previous power state - */ -static inline unsigned int read_cpu_prev_pwrst(unsigned int cpu_id) -{ - struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); - - return pwrdm_read_prev_pwrst(pm_info->pwrdm); -} - -/* - * Clear the CPUx powerdomain's previous power state - */ -static inline void clear_cpu_prev_pwrst(unsigned int cpu_id) -{ - struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); - - pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); -} - /* * Store the SCU power status value to scratchpad memory */ @@ -230,6 +199,7 @@ static void save_l2x0_context(void) */ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); unsigned int save_state = 0; unsigned int wakeup_cpu; @@ -268,7 +238,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) save_state = 2; cpu_clear_prev_logic_pwrst(cpu); - set_cpu_next_pwrst(cpu, power_state); + pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); scu_pwrst_prepare(cpu, power_state); l2x0_pwrst_prepare(cpu, save_state); @@ -286,7 +256,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) * domain transition */ wakeup_cpu = smp_processor_id(); - set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); + pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); pwrdm_post_transition(NULL); @@ -300,8 +270,8 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) */ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) { - unsigned int cpu_state = 0; struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); + unsigned int cpu_state = 0; if (omap_rev() == OMAP4430_REV_ES1_0) return -ENXIO; @@ -309,8 +279,8 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) if (power_state == PWRDM_POWER_OFF) cpu_state = 1; - clear_cpu_prev_pwrst(cpu); - set_cpu_next_pwrst(cpu, power_state); + pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); + pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup)); scu_pwrst_prepare(cpu, power_state); @@ -321,7 +291,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) */ omap4_finish_suspend(cpu_state); - set_cpu_next_pwrst(cpu, PWRDM_POWER_ON); + pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); return 0; } From c165a14023ecec8a68f3b87d0c3c822426065937 Mon Sep 17 00:00:00 2001 From: Jean Pihet Date: Sat, 26 Jan 2013 00:58:13 -0700 Subject: [PATCH 105/148] ARM: OMAP2+: powerdomain: fix powerdomain trace integration Fix the trace in the case a power domain did not hit the desired state, as reported by Paul Walmsley. Reported-by: Paul Walmsley Signed-off-by: Jean Pihet [paul@pwsan.com: split this fix off from the patch "ARM: OMAP2+: PM debug: trace the functional power domains states"] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index dea62a9aad07..92388c04f83d 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -143,7 +143,7 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm) static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { - int prev, state, trace_state = 0; + int prev, next, state, trace_state = 0; if (pwrdm == NULL) return -EINVAL; @@ -164,9 +164,10 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) * If the power domain did not hit the desired state, * generate a trace event with both the desired and hit states */ - if (state != prev) { + next = pwrdm_read_next_pwrst(pwrdm); + if (next != prev) { trace_state = (PWRDM_TRACE_STATES_FLAG | - ((state & OMAP_POWERSTATE_MASK) << 8) | + ((next & OMAP_POWERSTATE_MASK) << 8) | ((prev & OMAP_POWERSTATE_MASK) << 0)); trace_power_domain_target(pwrdm->name, trace_state, smp_processor_id()); From 53e1cb469e6cf353aa581e6b0a36cca359ecee25 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:14 -0700 Subject: [PATCH 106/148] ARM: OMAP2+: clockdomain: add pwrdm_state_switch() call to clkdm_sleep() In clkdm_sleep(), the powerdomain should be eligible to switch power states right after the call to the low-level clockdomain sleep function. We should have been tracking that with the pwrdm_state_switch() code, but we weren't, for whatever reason. Fix that. This resolves the "pwrdm state mismatch(cam_pwrdm) 3 != 0" that appears during the OMAP4460 Pandaboard-ES PM test, e.g. here: http://www.pwsan.com/omap/testlogs/test_v3.8-rc5/20130126003323/pm/4460pandaes/4460pandaes_log.txt Signed-off-by: Paul Walmsley Cc: Tero Kristo --- arch/arm/mach-omap2/clockdomain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 7faf82d4e85c..f0ec51497ce2 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -764,6 +764,7 @@ int clkdm_sleep(struct clockdomain *clkdm) spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; ret = arch_clkdm->clkdm_sleep(clkdm); + ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); spin_unlock_irqrestore(&clkdm->lock, flags); return ret; } From f653b29825817a929a606726f03a04fcd0b2b566 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:14 -0700 Subject: [PATCH 107/148] ARM: OMAP2xxx: PM: clean up some crufty powerstate programming code Don't attempt to put clockdomains to sleep; this should be handled by the clock framework. It should be enough to program the next-power-state, and then let the code in omap_pm_clkdms_setup() deal with the rest. Start out by programming the MPU and CORE powerdomains to stay ON. Then control the MPU and CORE powerdomain states directly in omap2_enter_full_retention() and omap2_enter_mpu_retention(). Not the most optimal way to do it, but certainly is the most conservative until OMAP2xxx PM is working again. Get rid of the open-coded PM_PWSTCTRL_MPU writes in omap2_enter_mpu_retention(); use the powerdomain code instead. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/pm24xx.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index c333fa6dffa8..5d0f39b490b6 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -90,11 +90,7 @@ static int omap2_enter_full_retention(void) omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); - /* - * Set MPU powerdomain's next power state to RETENTION; - * preserve logic state during retention - */ - pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); + pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); /* Workaround to kill USB */ @@ -137,6 +133,9 @@ no_sleep: /* Mask future PRCM-to-MPU interrupts */ omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); + pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); + pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON); + return 0; } @@ -186,17 +185,16 @@ static void omap2_enter_mpu_retention(void) omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); /* Try to enter MPU retention */ - omap2_prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) | - OMAP_LOGICRETSTATE_MASK, - MPU_MOD, OMAP2_PM_PWSTCTRL); + pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); + } else { /* Block MPU retention */ - - omap2_prm_write_mod_reg(OMAP_LOGICRETSTATE_MASK, MPU_MOD, - OMAP2_PM_PWSTCTRL); + pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); } omap2_sram_idle(); + + pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); } static int omap2_can_sleep(void) @@ -251,25 +249,17 @@ static void __init prcm_setup_regs(void) for (i = 0; i < num_mem_banks; i++) pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET); - /* Set CORE powerdomain's next power state to RETENTION */ - pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); + pwrdm_set_logic_retst(core_pwrdm, PWRDM_POWER_RET); - /* - * Set MPU powerdomain's next power state to RETENTION; - * preserve logic state during retention - */ pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); /* Force-power down DSP, GFX powerdomains */ pwrdm = clkdm_get_pwrdm(dsp_clkdm); pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); - clkdm_sleep(dsp_clkdm); pwrdm = clkdm_get_pwrdm(gfx_clkdm); pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); - clkdm_sleep(gfx_clkdm); /* Enable hardware-supervised idle for all clkdms */ clkdm_for_each(omap_pm_clkdms_setup, NULL); From f8457c2d8be94779c8c460060e536d3a2a02c8d8 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:15 -0700 Subject: [PATCH 108/148] ARM: OMAP2: PM/powerdomain: drop unnecessary pwrdm_wait_transition() Drop an unnecessary pwrdm_wait_transition() from mach-omap2/pm.c - it's called by the subsequent pwrdm_state_switch(). Also get rid of pwrdm_wait_transition() in the powerdomain code - there's no longer any need to export this function. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/pm.c | 1 - arch/arm/mach-omap2/powerdomain.c | 30 +++++------------------------- arch/arm/mach-omap2/powerdomain.h | 2 -- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index f4b3143a8b1d..f18afc9cbd8e 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -171,7 +171,6 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst) break; case LOWPOWERSTATE_SWITCH: pwrdm_set_lowpwrstchange(pwrdm); - pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); break; } diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 92388c04f83d..97b3881dd60d 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -112,7 +112,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm) for (i = 0; i < pwrdm->banks; i++) pwrdm->ret_mem_off_counter[i] = 0; - pwrdm_wait_transition(pwrdm); + arch_pwrdm->pwrdm_wait_transition(pwrdm); pwrdm->state = pwrdm_read_pwrst(pwrdm); pwrdm->state_counter[pwrdm->state] = 1; @@ -950,34 +950,14 @@ int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) return ret; } -/** - * pwrdm_wait_transition - wait for powerdomain power transition to finish - * @pwrdm: struct powerdomain * to wait for - * - * If the powerdomain @pwrdm is in the process of a state transition, - * spin until it completes the power transition, or until an iteration - * bailout value is reached. Returns -EINVAL if the powerdomain - * pointer is null, -EAGAIN if the bailout value was reached, or - * returns 0 upon success. - */ -int pwrdm_wait_transition(struct powerdomain *pwrdm) -{ - int ret = -EINVAL; - - if (!pwrdm) - return -EINVAL; - - if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition) - ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); - - return ret; -} - int pwrdm_state_switch(struct powerdomain *pwrdm) { int ret; - ret = pwrdm_wait_transition(pwrdm); + if (!pwrdm || !arch_pwrdm) + return -EINVAL; + + ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); if (!ret) ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 5277d56eb37f..7c1534bb16e9 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -225,8 +225,6 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm); int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); -int pwrdm_wait_transition(struct powerdomain *pwrdm); - int pwrdm_state_switch(struct powerdomain *pwrdm); int pwrdm_pre_transition(struct powerdomain *pwrdm); int pwrdm_post_transition(struct powerdomain *pwrdm); From c4978fba6b2d4e3a584d72c067a371871fecbedc Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 29 Jan 2013 13:45:09 -0700 Subject: [PATCH 109/148] ARM: OMAP2+: PM/powerdomain: move omap_set_pwrdm_state() to powerdomain code Move omap_set_pwrdm_state() from the PM code to the powerdomain code, and refactor it to split it up into several functions. A subsequent patch will rename it to conform with the existing powerdomain function names. This version includes some additional documentation, based on a suggestion from Jean Pihet. It also modifies omap_set_pwrdm_state() to not bail out early unless both the powerdomain current power state and the next power state are equal. (Previously it would terminate early if the next power state was equal to the target power state, which was insufficiently rigorous.) Signed-off-by: Paul Walmsley Cc: Jean Pihet Cc: Kevin Hilman Cc: Tero Kristo --- arch/arm/mach-omap2/pm.c | 61 ----------- arch/arm/mach-omap2/pm.h | 1 - arch/arm/mach-omap2/powerdomain.c | 161 ++++++++++++++++++++++++------ arch/arm/mach-omap2/powerdomain.h | 13 ++- 4 files changed, 144 insertions(+), 92 deletions(-) diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index f18afc9cbd8e..48d6d5d2c926 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -108,10 +108,6 @@ static void __init omap2_init_processor_devices(void) } } -/* Types of sleep_switch used in omap_set_pwrdm_state */ -#define FORCEWAKEUP_SWITCH 0 -#define LOWPOWERSTATE_SWITCH 1 - int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) { if ((clkdm->flags & CLKDM_CAN_ENABLE_AUTO) && @@ -123,63 +119,6 @@ int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) return 0; } -/* - * This sets pwrdm state (other than mpu & core. Currently only ON & - * RET are supported. - */ -int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst) -{ - u8 curr_pwrst, next_pwrst; - int sleep_switch = -1, ret = 0, hwsup = 0; - - if (!pwrdm || IS_ERR(pwrdm)) - return -EINVAL; - - while (!(pwrdm->pwrsts & (1 << pwrst))) { - if (pwrst == PWRDM_POWER_OFF) - return ret; - pwrst--; - } - - next_pwrst = pwrdm_read_next_pwrst(pwrdm); - if (next_pwrst == pwrst) - return ret; - - curr_pwrst = pwrdm_read_pwrst(pwrdm); - if (curr_pwrst < PWRDM_POWER_ON) { - if ((curr_pwrst > pwrst) && - (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { - sleep_switch = LOWPOWERSTATE_SWITCH; - } else { - hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); - clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); - sleep_switch = FORCEWAKEUP_SWITCH; - } - } - - ret = pwrdm_set_next_pwrst(pwrdm, pwrst); - if (ret) - pr_err("%s: unable to set power state of powerdomain: %s\n", - __func__, pwrdm->name); - - switch (sleep_switch) { - case FORCEWAKEUP_SWITCH: - if (hwsup) - clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); - else - clkdm_sleep(pwrdm->pwrdm_clkdms[0]); - break; - case LOWPOWERSTATE_SWITCH: - pwrdm_set_lowpwrstchange(pwrdm); - pwrdm_state_switch(pwrdm); - break; - } - - return ret; -} - - - /* * This API is to be called during init to set the various voltage * domains to the voltage as per the opp table. Typically we boot up diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index c22503b17abd..7bdd22afce69 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -33,7 +33,6 @@ static inline int omap4_idle_init(void) extern void *omap3_secure_ram_storage; extern void omap3_pm_off_mode_enable(int); extern void omap_sram_idle(void); -extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state); extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused); extern int (*omap_pm_suspend)(void); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 97b3881dd60d..65c34645c8ed 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -42,6 +42,16 @@ enum { PWRDM_STATE_PREV, }; +/* + * Types of sleep_switch used internally in omap_set_pwrdm_state() + * and its associated static functions + * + * XXX Better documentation is needed here + */ +#define ALREADYACTIVE_SWITCH 0 +#define FORCEWAKEUP_SWITCH 1 +#define LOWPOWERSTATE_SWITCH 2 +#define ERROR_SWITCH 3 /* pwrdm_list contains all registered struct powerdomains */ static LIST_HEAD(pwrdm_list); @@ -200,6 +210,80 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) return 0; } +/** + * _pwrdm_save_clkdm_state_and_activate - prepare for power state change + * @pwrdm: struct powerdomain * to operate on + * @curr_pwrst: current power state of @pwrdm + * @pwrst: power state to switch to + * @hwsup: ptr to a bool to return whether the clkdm is hardware-supervised + * + * Determine whether the powerdomain needs to be turned on before + * attempting to switch power states. Called by + * omap_set_pwrdm_state(). NOTE that if the powerdomain contains + * multiple clockdomains, this code assumes that the first clockdomain + * supports software-supervised wakeup mode - potentially a problem. + * Returns the power state switch mode currently in use (see the + * "Types of sleep_switch" comment above). + */ +static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm, + u8 curr_pwrst, u8 pwrst, + bool *hwsup) +{ + u8 sleep_switch; + + if (curr_pwrst < 0) { + WARN_ON(1); + sleep_switch = ERROR_SWITCH; + } else if (curr_pwrst < PWRDM_POWER_ON) { + if (curr_pwrst > pwrst && + pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && + arch_pwrdm->pwrdm_set_lowpwrstchange) { + sleep_switch = LOWPOWERSTATE_SWITCH; + } else { + *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); + clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); + sleep_switch = FORCEWAKEUP_SWITCH; + } + } else { + sleep_switch = ALREADYACTIVE_SWITCH; + } + + return sleep_switch; +} + +/** + * _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change + * @pwrdm: struct powerdomain * to operate on + * @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate() + * @hwsup: should @pwrdm's first clockdomain be set to hardware-supervised mode? + * + * Restore the clockdomain state perturbed by + * _pwrdm_save_clkdm_state_and_activate(), and call the power state + * bookkeeping code. Called by omap_set_pwrdm_state(). NOTE that if + * the powerdomain contains multiple clockdomains, this assumes that + * the first associated clockdomain supports either + * hardware-supervised idle control in the register, or + * software-supervised sleep. No return value. + */ +static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm, + u8 sleep_switch, bool hwsup) +{ + switch (sleep_switch) { + case FORCEWAKEUP_SWITCH: + if (hwsup) + clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); + else + clkdm_sleep(pwrdm->pwrdm_clkdms[0]); + break; + case LOWPOWERSTATE_SWITCH: + if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && + arch_pwrdm->pwrdm_set_lowpwrstchange) + arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); + pwrdm_state_switch(pwrdm); + break; + } +} + /* Public functions */ /** @@ -921,35 +1005,6 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm) return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; } -/** - * pwrdm_set_lowpwrstchange - Request a low power state change - * @pwrdm: struct powerdomain * - * - * Allows a powerdomain to transtion to a lower power sleep state - * from an existing sleep state without waking up the powerdomain. - * Returns -EINVAL if the powerdomain pointer is null or if the - * powerdomain does not support LOWPOWERSTATECHANGE, or returns 0 - * upon success. - */ -int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) -{ - int ret = -EINVAL; - - if (!pwrdm) - return -EINVAL; - - if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) - return -EINVAL; - - pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n", - pwrdm->name); - - if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange) - ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); - - return ret; -} - int pwrdm_state_switch(struct powerdomain *pwrdm) { int ret; @@ -984,6 +1039,54 @@ int pwrdm_post_transition(struct powerdomain *pwrdm) return 0; } +/** + * omap_set_pwrdm_state - change a powerdomain's current power state + * @pwrdm: struct powerdomain * to change the power state of + * @pwrst: power state to change to + * + * Change the current hardware power state of the powerdomain + * represented by @pwrdm to the power state represented by @pwrst. + * Returns -EINVAL if @pwrdm is null or invalid or if the + * powerdomain's current power state could not be read, or returns 0 + * upon success or if @pwrdm does not support @pwrst or any + * lower-power state. XXX Should not return 0 if the @pwrdm does not + * support @pwrst or any lower-power state: this should be an error. + */ +int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) +{ + u8 curr_pwrst, next_pwrst, sleep_switch; + int ret = 0; + bool hwsup = false; + + if (!pwrdm || IS_ERR(pwrdm)) + return -EINVAL; + + while (!(pwrdm->pwrsts & (1 << pwrst))) { + if (pwrst == PWRDM_POWER_OFF) + return ret; + pwrst--; + } + + curr_pwrst = pwrdm_read_pwrst(pwrdm); + next_pwrst = pwrdm_read_next_pwrst(pwrdm); + if (curr_pwrst == pwrst && next_pwrst == pwrst) + return ret; + + sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst, + pwrst, &hwsup); + if (sleep_switch == ERROR_SWITCH) + return -EINVAL; + + ret = pwrdm_set_next_pwrst(pwrdm, pwrst); + if (ret) + pr_err("%s: unable to set power state of powerdomain: %s\n", + __func__, pwrdm->name); + + _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup); + + return ret; +} + /** * pwrdm_get_context_loss_count - get powerdomain's context loss count * @pwrdm: struct powerdomain * to wait for diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 7c1534bb16e9..93e7df824650 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -162,6 +162,16 @@ struct powerdomain { * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep * @pwrdm_wait_transition: Wait for a pd state transition to complete + * + * Regarding @pwrdm_set_lowpwrstchange: On the OMAP2 and 3-family + * chips, a powerdomain's power state is not allowed to directly + * transition from one low-power state (e.g., CSWR) to another + * low-power state (e.g., OFF) without first waking up the + * powerdomain. This wastes energy. So OMAP4 chips support the + * ability to transition a powerdomain power state directly from one + * low-power state to another. The function pointed to by + * @pwrdm_set_lowpwrstchange is intended to configure the OMAP4 + * hardware powerdomain state machine to enable this feature. */ struct pwrdm_ops { int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst); @@ -228,10 +238,11 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); int pwrdm_state_switch(struct powerdomain *pwrdm); int pwrdm_pre_transition(struct powerdomain *pwrdm); int pwrdm_post_transition(struct powerdomain *pwrdm); -int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); +extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state); + extern void omap242x_powerdomains_init(void); extern void omap243x_powerdomains_init(void); extern void omap3xxx_powerdomains_init(void); From 3a090284056954f382612da42ebe9f3147403ef5 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:16 -0700 Subject: [PATCH 110/148] ARM: OMAP2+: powerdomain/clockdomain: add a per-powerdomain spinlock Add a per-powerdomain spinlock. Use that instead of the clockdomain spinlock. Add pwrdm_lock()/pwrdm_unlock() functions to allow other code to acquire or release the powerdomain spinlock without reaching directly into the struct powerdomain. Signed-off-by: Paul Walmsley Cc: Jean Pihet --- arch/arm/mach-omap2/clockdomain.c | 172 +++++++++++++++++++----------- arch/arm/mach-omap2/clockdomain.h | 6 +- arch/arm/mach-omap2/powerdomain.c | 60 +++++++++-- arch/arm/mach-omap2/powerdomain.h | 11 +- 4 files changed, 176 insertions(+), 73 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index f0ec51497ce2..275bdfbb6fc5 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -92,8 +92,6 @@ static int _clkdm_register(struct clockdomain *clkdm) pwrdm_add_clkdm(pwrdm, clkdm); - spin_lock_init(&clkdm->lock); - pr_debug("clockdomain: registered %s\n", clkdm->name); return 0; @@ -734,18 +732,17 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) } /** - * clkdm_sleep - force clockdomain sleep transition + * clkdm_sleep_nolock - force clockdomain sleep transition (lockless) * @clkdm: struct clockdomain * * * Instruct the CM to force a sleep transition on the specified - * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if - * clockdomain does not support software-initiated sleep; 0 upon - * success. + * clockdomain @clkdm. Only for use by the powerdomain code. Returns + * -EINVAL if @clkdm is NULL or if clockdomain does not support + * software-initiated sleep; 0 upon success. */ -int clkdm_sleep(struct clockdomain *clkdm) +int clkdm_sleep_nolock(struct clockdomain *clkdm) { int ret; - unsigned long flags; if (!clkdm) return -EINVAL; @@ -761,27 +758,45 @@ int clkdm_sleep(struct clockdomain *clkdm) pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); - spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; ret = arch_clkdm->clkdm_sleep(clkdm); - ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); - spin_unlock_irqrestore(&clkdm->lock, flags); + ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); + return ret; } /** - * clkdm_wakeup - force clockdomain wakeup transition + * clkdm_sleep - force clockdomain sleep transition + * @clkdm: struct clockdomain * + * + * Instruct the CM to force a sleep transition on the specified + * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if + * clockdomain does not support software-initiated sleep; 0 upon + * success. + */ +int clkdm_sleep(struct clockdomain *clkdm) +{ + int ret; + + pwrdm_lock(clkdm->pwrdm.ptr); + ret = clkdm_sleep_nolock(clkdm); + pwrdm_unlock(clkdm->pwrdm.ptr); + + return ret; +} + +/** + * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless) * @clkdm: struct clockdomain * * * Instruct the CM to force a wakeup transition on the specified - * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the - * clockdomain does not support software-controlled wakeup; 0 upon - * success. + * clockdomain @clkdm. Only for use by the powerdomain code. Returns + * -EINVAL if @clkdm is NULL or if the clockdomain does not support + * software-controlled wakeup; 0 upon success. */ -int clkdm_wakeup(struct clockdomain *clkdm) +int clkdm_wakeup_nolock(struct clockdomain *clkdm) { int ret; - unsigned long flags; if (!clkdm) return -EINVAL; @@ -797,28 +812,46 @@ int clkdm_wakeup(struct clockdomain *clkdm) pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); - spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; ret = arch_clkdm->clkdm_wakeup(clkdm); - ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); - spin_unlock_irqrestore(&clkdm->lock, flags); + ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); + return ret; } /** - * clkdm_allow_idle - enable hwsup idle transitions for clkdm + * clkdm_wakeup - force clockdomain wakeup transition * @clkdm: struct clockdomain * * - * Allow the hardware to automatically switch the clockdomain @clkdm into - * active or idle states, as needed by downstream clocks. If the + * Instruct the CM to force a wakeup transition on the specified + * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the + * clockdomain does not support software-controlled wakeup; 0 upon + * success. + */ +int clkdm_wakeup(struct clockdomain *clkdm) +{ + int ret; + + pwrdm_lock(clkdm->pwrdm.ptr); + ret = clkdm_wakeup_nolock(clkdm); + pwrdm_unlock(clkdm->pwrdm.ptr); + + return ret; +} + +/** + * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm + * @clkdm: struct clockdomain * + * + * Allow the hardware to automatically switch the clockdomain @clkdm + * into active or idle states, as needed by downstream clocks. If the * clockdomain has any downstream clocks enabled in the clock * framework, wkdep/sleepdep autodependencies are added; this is so - * device drivers can read and write to the device. No return value. + * device drivers can read and write to the device. Only for use by + * the powerdomain code. No return value. */ -void clkdm_allow_idle(struct clockdomain *clkdm) +void clkdm_allow_idle_nolock(struct clockdomain *clkdm) { - unsigned long flags; - if (!clkdm) return; @@ -834,11 +867,26 @@ void clkdm_allow_idle(struct clockdomain *clkdm) pr_debug("clockdomain: enabling automatic idle transitions for %s\n", clkdm->name); - spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; arch_clkdm->clkdm_allow_idle(clkdm); - pwrdm_state_switch(clkdm->pwrdm.ptr); - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); +} + +/** + * clkdm_allow_idle - enable hwsup idle transitions for clkdm + * @clkdm: struct clockdomain * + * + * Allow the hardware to automatically switch the clockdomain @clkdm into + * active or idle states, as needed by downstream clocks. If the + * clockdomain has any downstream clocks enabled in the clock + * framework, wkdep/sleepdep autodependencies are added; this is so + * device drivers can read and write to the device. No return value. + */ +void clkdm_allow_idle(struct clockdomain *clkdm) +{ + pwrdm_lock(clkdm->pwrdm.ptr); + clkdm_allow_idle_nolock(clkdm); + pwrdm_unlock(clkdm->pwrdm.ptr); } /** @@ -848,12 +896,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm) * Prevent the hardware from automatically switching the clockdomain * @clkdm into inactive or idle states. If the clockdomain has * downstream clocks enabled in the clock framework, wkdep/sleepdep - * autodependencies are removed. No return value. + * autodependencies are removed. Only for use by the powerdomain + * code. No return value. */ -void clkdm_deny_idle(struct clockdomain *clkdm) +void clkdm_deny_idle_nolock(struct clockdomain *clkdm) { - unsigned long flags; - if (!clkdm) return; @@ -869,11 +916,25 @@ void clkdm_deny_idle(struct clockdomain *clkdm) pr_debug("clockdomain: disabling automatic idle transitions for %s\n", clkdm->name); - spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; arch_clkdm->clkdm_deny_idle(clkdm); - pwrdm_state_switch(clkdm->pwrdm.ptr); - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); +} + +/** + * clkdm_deny_idle - disable hwsup idle transitions for clkdm + * @clkdm: struct clockdomain * + * + * Prevent the hardware from automatically switching the clockdomain + * @clkdm into inactive or idle states. If the clockdomain has + * downstream clocks enabled in the clock framework, wkdep/sleepdep + * autodependencies are removed. No return value. + */ +void clkdm_deny_idle(struct clockdomain *clkdm) +{ + pwrdm_lock(clkdm->pwrdm.ptr); + clkdm_deny_idle_nolock(clkdm); + pwrdm_unlock(clkdm->pwrdm.ptr); } /** @@ -890,14 +951,11 @@ void clkdm_deny_idle(struct clockdomain *clkdm) bool clkdm_in_hwsup(struct clockdomain *clkdm) { bool ret; - unsigned long flags; if (!clkdm) return false; - spin_lock_irqsave(&clkdm->lock, flags); ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; - spin_unlock_irqrestore(&clkdm->lock, flags); return ret; } @@ -923,12 +981,10 @@ bool clkdm_missing_idle_reporting(struct clockdomain *clkdm) static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) { - unsigned long flags; - if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) return -EINVAL; - spin_lock_irqsave(&clkdm->lock, flags); + pwrdm_lock(clkdm->pwrdm.ptr); /* * For arch's with no autodeps, clkcm_clk_enable @@ -936,13 +992,13 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) * enabled, so the clkdm can be force woken up. */ if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_unlock(clkdm->pwrdm.ptr); return 0; } arch_clkdm->clkdm_clk_enable(clkdm); - pwrdm_state_switch(clkdm->pwrdm.ptr); - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); + pwrdm_unlock(clkdm->pwrdm.ptr); pr_debug("clockdomain: %s: enabled\n", clkdm->name); @@ -991,12 +1047,10 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) */ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) { - unsigned long flags; - if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) return -EINVAL; - spin_lock_irqsave(&clkdm->lock, flags); + pwrdm_lock(clkdm->pwrdm.ptr); /* corner case: disabling unused clocks */ if ((__clk_get_enable_count(clk) == 0) && @@ -1004,23 +1058,23 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) goto ccd_exit; if (atomic_read(&clkdm->usecount) == 0) { - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_unlock(clkdm->pwrdm.ptr); WARN_ON(1); /* underflow */ return -ERANGE; } if (atomic_dec_return(&clkdm->usecount) > 0) { - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_unlock(clkdm->pwrdm.ptr); return 0; } arch_clkdm->clkdm_clk_disable(clkdm); - pwrdm_state_switch(clkdm->pwrdm.ptr); + pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); pr_debug("clockdomain: %s: disabled\n", clkdm->name); ccd_exit: - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_unlock(clkdm->pwrdm.ptr); return 0; } @@ -1073,8 +1127,6 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh) */ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) { - unsigned long flags; - /* The clkdm attribute does not exist yet prior OMAP4 */ if (cpu_is_omap24xx() || cpu_is_omap34xx()) return 0; @@ -1087,22 +1139,22 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) return -EINVAL; - spin_lock_irqsave(&clkdm->lock, flags); + pwrdm_lock(clkdm->pwrdm.ptr); if (atomic_read(&clkdm->usecount) == 0) { - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_unlock(clkdm->pwrdm.ptr); WARN_ON(1); /* underflow */ return -ERANGE; } if (atomic_dec_return(&clkdm->usecount) > 0) { - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_unlock(clkdm->pwrdm.ptr); return 0; } arch_clkdm->clkdm_clk_disable(clkdm); - pwrdm_state_switch(clkdm->pwrdm.ptr); - spin_unlock_irqrestore(&clkdm->lock, flags); + pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); + pwrdm_unlock(clkdm->pwrdm.ptr); pr_debug("clockdomain: %s: disabled\n", clkdm->name); diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index bc42446e23ab..e7f1b4ba2d5b 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h @@ -15,7 +15,6 @@ #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H #include -#include #include "powerdomain.h" #include "clock.h" @@ -139,7 +138,6 @@ struct clockdomain { struct clkdm_dep *sleepdep_srcs; atomic_t usecount; struct list_head node; - spinlock_t lock; }; /** @@ -196,12 +194,16 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); +void clkdm_allow_idle_nolock(struct clockdomain *clkdm); void clkdm_allow_idle(struct clockdomain *clkdm); +void clkdm_deny_idle_nolock(struct clockdomain *clkdm); void clkdm_deny_idle(struct clockdomain *clkdm); bool clkdm_in_hwsup(struct clockdomain *clkdm); bool clkdm_missing_idle_reporting(struct clockdomain *clkdm); +int clkdm_wakeup_nolock(struct clockdomain *clkdm); int clkdm_wakeup(struct clockdomain *clkdm); +int clkdm_sleep_nolock(struct clockdomain *clkdm); int clkdm_sleep(struct clockdomain *clkdm); int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 65c34645c8ed..8e61d80bf6b3 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "cm2xxx_3xxx.h" @@ -111,6 +112,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm) pwrdm->voltdm.ptr = voltdm; INIT_LIST_HEAD(&pwrdm->voltdm_node); voltdm_add_pwrdm(voltdm, pwrdm); + spin_lock_init(&pwrdm->_lock); list_add(&pwrdm->node, &pwrdm_list); @@ -241,7 +243,7 @@ static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm, sleep_switch = LOWPOWERSTATE_SWITCH; } else { *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); - clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); + clkdm_wakeup_nolock(pwrdm->pwrdm_clkdms[0]); sleep_switch = FORCEWAKEUP_SWITCH; } } else { @@ -271,15 +273,15 @@ static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm, switch (sleep_switch) { case FORCEWAKEUP_SWITCH: if (hwsup) - clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); + clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]); else - clkdm_sleep(pwrdm->pwrdm_clkdms[0]); + clkdm_sleep_nolock(pwrdm->pwrdm_clkdms[0]); break; case LOWPOWERSTATE_SWITCH: if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && arch_pwrdm->pwrdm_set_lowpwrstchange) arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); - pwrdm_state_switch(pwrdm); + pwrdm_state_switch_nolock(pwrdm); break; } } @@ -359,6 +361,30 @@ int pwrdm_complete_init(void) return 0; } +/** + * pwrdm_lock - acquire a Linux spinlock on a powerdomain + * @pwrdm: struct powerdomain * to lock + * + * Acquire the powerdomain spinlock on @pwrdm. No return value. + */ +void pwrdm_lock(struct powerdomain *pwrdm) + __acquires(&pwrdm->_lock) +{ + spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags); +} + +/** + * pwrdm_unlock - release a Linux spinlock on a powerdomain + * @pwrdm: struct powerdomain * to unlock + * + * Release the powerdomain spinlock on @pwrdm. No return value. + */ +void pwrdm_unlock(struct powerdomain *pwrdm) + __releases(&pwrdm->_lock) +{ + spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags); +} + /** * pwrdm_lookup - look up a powerdomain by name, return a pointer * @name: name of powerdomain @@ -1005,7 +1031,7 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm) return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; } -int pwrdm_state_switch(struct powerdomain *pwrdm) +int pwrdm_state_switch_nolock(struct powerdomain *pwrdm) { int ret; @@ -1019,6 +1045,17 @@ int pwrdm_state_switch(struct powerdomain *pwrdm) return ret; } +int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm) +{ + int ret; + + pwrdm_lock(pwrdm); + ret = pwrdm_state_switch_nolock(pwrdm); + pwrdm_unlock(pwrdm); + + return ret; +} + int pwrdm_pre_transition(struct powerdomain *pwrdm) { if (pwrdm) @@ -1067,15 +1104,19 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) pwrst--; } + pwrdm_lock(pwrdm); + curr_pwrst = pwrdm_read_pwrst(pwrdm); next_pwrst = pwrdm_read_next_pwrst(pwrdm); if (curr_pwrst == pwrst && next_pwrst == pwrst) - return ret; + goto osps_out; sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst, pwrst, &hwsup); - if (sleep_switch == ERROR_SWITCH) - return -EINVAL; + if (sleep_switch == ERROR_SWITCH) { + ret = -EINVAL; + goto osps_out; + } ret = pwrdm_set_next_pwrst(pwrdm, pwrst); if (ret) @@ -1084,6 +1125,9 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup); +osps_out: + pwrdm_unlock(pwrdm); + return ret; } diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 93e7df824650..909cc5c1c23a 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -19,8 +19,7 @@ #include #include - -#include +#include #include "voltage.h" @@ -103,6 +102,8 @@ struct powerdomain; * @state_counter: * @timer: * @state_timer: + * @_lock: spinlock used to serialize powerdomain and some clockdomain ops + * @_lock_flags: stored flags when @_lock is taken * * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. */ @@ -127,7 +128,8 @@ struct powerdomain { unsigned state_counter[PWRDM_MAX_PWRSTS]; unsigned ret_logic_off_counter; unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; - + spinlock_t _lock; + unsigned long _lock_flags; const u8 pwrstctrl_offs; const u8 pwrstst_offs; const u32 logicretstate_mask; @@ -235,6 +237,7 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm); int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); +int pwrdm_state_switch_nolock(struct powerdomain *pwrdm); int pwrdm_state_switch(struct powerdomain *pwrdm); int pwrdm_pre_transition(struct powerdomain *pwrdm); int pwrdm_post_transition(struct powerdomain *pwrdm); @@ -262,5 +265,7 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank); extern struct powerdomain wkup_omap2_pwrdm; extern struct powerdomain gfx_omap2_pwrdm; +extern void pwrdm_lock(struct powerdomain *pwrdm); +extern void pwrdm_unlock(struct powerdomain *pwrdm); #endif From cc3af91b504ab1810311c78cce1bc2b7f52240ee Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:16 -0700 Subject: [PATCH 111/148] ARM: OMAP2xxx: CM: remove autodep handling There's no need to preserve the autodep handling code in mach-omap2/cm2xxx.c, since no autodeps are defined for these chips. Hopefully they'll never be needed, but if in some future case they are, this code can be added back in. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/cm2xxx.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index db650690e9d0..6774a53a3874 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c @@ -273,9 +273,6 @@ int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm) { - if (atomic_read(&clkdm->usecount) > 0) - _clkdm_add_autodeps(clkdm); - omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); } @@ -284,9 +281,6 @@ static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm) { omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - - if (atomic_read(&clkdm->usecount) > 0) - _clkdm_del_autodeps(clkdm); } static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) @@ -298,18 +292,8 @@ static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - - if (hwsup) { - /* Disable HW transitions when we are changing deps */ - omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - _clkdm_add_autodeps(clkdm); - omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - } else { - if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) - omap2xxx_clkdm_wakeup(clkdm); - } + if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) + omap2xxx_clkdm_wakeup(clkdm); return 0; } @@ -324,17 +308,8 @@ static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm) hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - if (hwsup) { - /* Disable HW transitions when we are changing deps */ - omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - _clkdm_del_autodeps(clkdm); - omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - } else { - if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP) - omap2xxx_clkdm_sleep(clkdm); - } + if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_SLEEP) + omap2xxx_clkdm_sleep(clkdm); return 0; } From 65958fb6ca7b7e504caf852e492fe554224de1ba Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:17 -0700 Subject: [PATCH 112/148] ARM: OMAP2+: clockdomain: work on wkdep/sleepdep functions Split the clkdm_(add|del)_(wk|sleep)dep() functions into lockless and locking versions -- this will be needed in a subsequent patch. Also, while here, remove the leading underscore, since these are not currently static functions. And for functions that have kerneldoc-style comment blocks, but which are missing the initial '/**' tag, fix the tag to indicate that they are kerneldoc. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clockdomain.c | 410 ++++++++++++++++++------------ arch/arm/mach-omap2/clockdomain.h | 5 +- arch/arm/mach-omap2/cm3xxx.c | 8 +- 3 files changed, 248 insertions(+), 175 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 275bdfbb6fc5..ab194753eb7a 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -120,7 +120,7 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, return cd; } -/* +/** * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store * @autodep: struct clkdm_autodep * to resolve * @@ -152,66 +152,6 @@ static void _autodep_lookup(struct clkdm_autodep *autodep) autodep->clkdm.ptr = clkdm; } -/* - * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable - * @clkdm: struct clockdomain * - * - * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' - * in hardware-supervised mode. Meant to be called from clock framework - * when a clock inside clockdomain 'clkdm' is enabled. No return value. - * - * XXX autodeps are deprecated and should be removed at the earliest - * opportunity - */ -void _clkdm_add_autodeps(struct clockdomain *clkdm) -{ - struct clkdm_autodep *autodep; - - if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) - return; - - for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { - if (IS_ERR(autodep->clkdm.ptr)) - continue; - - pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", - clkdm->name, autodep->clkdm.ptr->name); - - clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); - clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); - } -} - -/* - * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm - * @clkdm: struct clockdomain * - * - * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' - * in hardware-supervised mode. Meant to be called from clock framework - * when a clock inside clockdomain 'clkdm' is disabled. No return value. - * - * XXX autodeps are deprecated and should be removed at the earliest - * opportunity - */ -void _clkdm_del_autodeps(struct clockdomain *clkdm) -{ - struct clkdm_autodep *autodep; - - if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) - return; - - for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { - if (IS_ERR(autodep->clkdm.ptr)) - continue; - - pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", - clkdm->name, autodep->clkdm.ptr->name); - - clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); - clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); - } -} - /** * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms * @clkdm: clockdomain that we are resolving dependencies for @@ -236,6 +176,180 @@ static void _resolve_clkdm_deps(struct clockdomain *clkdm, } } +/** + * _clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 (lockless) + * @clkdm1: wake this struct clockdomain * up (dependent) + * @clkdm2: when this struct clockdomain * wakes up (source) + * + * When the clockdomain represented by @clkdm2 wakes up, wake up + * @clkdm1. Implemented in hardware on the OMAP, this feature is + * designed to reduce wakeup latency of the dependent clockdomain @clkdm1. + * Returns -EINVAL if presented with invalid clockdomain pointers, + * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon + * success. + */ +static int _clkdm_add_wkdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + int ret = 0; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) + ret = -EINVAL; + + if (ret) { + pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", + clkdm1->name, clkdm2->name); + return ret; + } + + if (atomic_inc_return(&cd->wkdep_usecount) == 1) { + pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", + clkdm1->name, clkdm2->name); + + ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); + } + + return ret; +} + +/** + * _clkdm_del_wkdep - remove a wakeup dep from clkdm2 to clkdm1 (lockless) + * @clkdm1: wake this struct clockdomain * up (dependent) + * @clkdm2: when this struct clockdomain * wakes up (source) + * + * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2 + * wakes up. Returns -EINVAL if presented with invalid clockdomain + * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or + * 0 upon success. + */ +static int _clkdm_del_wkdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + int ret = 0; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) + ret = -EINVAL; + + if (ret) { + pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", + clkdm1->name, clkdm2->name); + return ret; + } + + if (atomic_dec_return(&cd->wkdep_usecount) == 0) { + pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n", + clkdm1->name, clkdm2->name); + + ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); + } + + return ret; +} + +/** + * _clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 (lockless) + * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) + * @clkdm2: when this struct clockdomain * is active (source) + * + * Prevent @clkdm1 from automatically going inactive (and then to + * retention or off) if @clkdm2 is active. Returns -EINVAL if + * presented with invalid clockdomain pointers or called on a machine + * that does not support software-configurable hardware sleep + * dependencies, -ENOENT if the specified dependency cannot be set in + * hardware, or 0 upon success. + */ +static int _clkdm_add_sleepdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + int ret = 0; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) + ret = -EINVAL; + + if (ret) { + pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", + clkdm1->name, clkdm2->name); + return ret; + } + + if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { + pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", + clkdm1->name, clkdm2->name); + + ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); + } + + return ret; +} + +/** + * _clkdm_del_sleepdep - remove a sleep dep from clkdm2 to clkdm1 (lockless) + * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) + * @clkdm2: when this struct clockdomain * is active (source) + * + * Allow @clkdm1 to automatically go inactive (and then to retention or + * off), independent of the activity state of @clkdm2. Returns -EINVAL + * if presented with invalid clockdomain pointers or called on a machine + * that does not support software-configurable hardware sleep dependencies, + * -ENOENT if the specified dependency cannot be cleared in hardware, or + * 0 upon success. + */ +static int _clkdm_del_sleepdep(struct clockdomain *clkdm1, + struct clockdomain *clkdm2) +{ + struct clkdm_dep *cd; + int ret = 0; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); + if (IS_ERR(cd)) + ret = PTR_ERR(cd); + + if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) + ret = -EINVAL; + + if (ret) { + pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", + clkdm1->name, clkdm2->name); + return ret; + } + + if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { + pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n", + clkdm1->name, clkdm2->name); + + ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); + } + + return ret; +} + /* Public functions */ /** @@ -453,33 +567,7 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) */ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { - struct clkdm_dep *cd; - int ret = 0; - - if (!clkdm1 || !clkdm2) - return -EINVAL; - - cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); - if (IS_ERR(cd)) - ret = PTR_ERR(cd); - - if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) - ret = -EINVAL; - - if (ret) { - pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", - clkdm1->name, clkdm2->name); - return ret; - } - - if (atomic_inc_return(&cd->wkdep_usecount) == 1) { - pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", - clkdm1->name, clkdm2->name); - - ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); - } - - return ret; + return _clkdm_add_wkdep(clkdm1, clkdm2); } /** @@ -494,33 +582,7 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) */ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { - struct clkdm_dep *cd; - int ret = 0; - - if (!clkdm1 || !clkdm2) - return -EINVAL; - - cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); - if (IS_ERR(cd)) - ret = PTR_ERR(cd); - - if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) - ret = -EINVAL; - - if (ret) { - pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", - clkdm1->name, clkdm2->name); - return ret; - } - - if (atomic_dec_return(&cd->wkdep_usecount) == 0) { - pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n", - clkdm1->name, clkdm2->name); - - ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); - } - - return ret; + return _clkdm_del_wkdep(clkdm1, clkdm2); } /** @@ -597,33 +659,7 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) */ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { - struct clkdm_dep *cd; - int ret = 0; - - if (!clkdm1 || !clkdm2) - return -EINVAL; - - cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); - if (IS_ERR(cd)) - ret = PTR_ERR(cd); - - if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) - ret = -EINVAL; - - if (ret) { - pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", - clkdm1->name, clkdm2->name); - return ret; - } - - if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { - pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", - clkdm1->name, clkdm2->name); - - ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); - } - - return ret; + return _clkdm_add_sleepdep(clkdm1, clkdm2); } /** @@ -640,33 +676,7 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) */ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { - struct clkdm_dep *cd; - int ret = 0; - - if (!clkdm1 || !clkdm2) - return -EINVAL; - - cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); - if (IS_ERR(cd)) - ret = PTR_ERR(cd); - - if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) - ret = -EINVAL; - - if (ret) { - pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", - clkdm1->name, clkdm2->name); - return ret; - } - - if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { - pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n", - clkdm1->name, clkdm2->name); - - ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); - } - - return ret; + return _clkdm_del_sleepdep(clkdm1, clkdm2); } /** @@ -977,6 +987,68 @@ bool clkdm_missing_idle_reporting(struct clockdomain *clkdm) return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false; } +/* Public autodep handling functions (deprecated) */ + +/** + * clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable + * @clkdm: struct clockdomain * + * + * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' + * in hardware-supervised mode. Meant to be called from clock framework + * when a clock inside clockdomain 'clkdm' is enabled. No return value. + * + * XXX autodeps are deprecated and should be removed at the earliest + * opportunity + */ +void clkdm_add_autodeps(struct clockdomain *clkdm) +{ + struct clkdm_autodep *autodep; + + if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) + return; + + for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { + if (IS_ERR(autodep->clkdm.ptr)) + continue; + + pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", + clkdm->name, autodep->clkdm.ptr->name); + + _clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); + _clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); + } +} + +/** + * clkdm_del_autodeps - remove auto sleepdeps/wkdeps from clkdm + * @clkdm: struct clockdomain * + * + * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' + * in hardware-supervised mode. Meant to be called from clock framework + * when a clock inside clockdomain 'clkdm' is disabled. No return value. + * + * XXX autodeps are deprecated and should be removed at the earliest + * opportunity + */ +void clkdm_del_autodeps(struct clockdomain *clkdm) +{ + struct clkdm_autodep *autodep; + + if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) + return; + + for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { + if (IS_ERR(autodep->clkdm.ptr)) + continue; + + pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", + clkdm->name, autodep->clkdm.ptr->name); + + _clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); + _clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); + } +} + /* Clockdomain-to-clock/hwmod framework interface code */ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index e7f1b4ba2d5b..50c3cd8bd706 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h @@ -216,8 +216,9 @@ extern void __init omap243x_clockdomains_init(void); extern void __init omap3xxx_clockdomains_init(void); extern void __init am33xx_clockdomains_init(void); extern void __init omap44xx_clockdomains_init(void); -extern void _clkdm_add_autodeps(struct clockdomain *clkdm); -extern void _clkdm_del_autodeps(struct clockdomain *clkdm); + +extern void clkdm_add_autodeps(struct clockdomain *clkdm); +extern void clkdm_del_autodeps(struct clockdomain *clkdm); extern struct clkdm_ops omap2_clkdm_operations; extern struct clkdm_ops omap3_clkdm_operations; diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index c2086f2e86b6..b94af4cb9dd9 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c @@ -210,7 +210,7 @@ static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm) static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm) { if (atomic_read(&clkdm->usecount) > 0) - _clkdm_add_autodeps(clkdm); + clkdm_add_autodeps(clkdm); omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); @@ -222,7 +222,7 @@ static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm) clkdm->clktrctrl_mask); if (atomic_read(&clkdm->usecount) > 0) - _clkdm_del_autodeps(clkdm); + clkdm_del_autodeps(clkdm); } static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) @@ -250,7 +250,7 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) /* Disable HW transitions when we are changing deps */ omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - _clkdm_add_autodeps(clkdm); + clkdm_add_autodeps(clkdm); omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); } else { @@ -287,7 +287,7 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm) /* Disable HW transitions when we are changing deps */ omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - _clkdm_del_autodeps(clkdm); + clkdm_del_autodeps(clkdm); omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); } else { From 92493870196f52c743330db7b545b54b2abfda82 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:17 -0700 Subject: [PATCH 113/148] ARM: OMAP2+: clockdomain: convert existing atomic usecounts into spinlock-protected shorts/ints The atomic usecounts seem to be confusing, and are no longer needed since the operations that they are attached to really should take place under lock. Replace the atomic counters with simple integers, protected by the enclosing powerdomain spinlock. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/clockdomain.c | 96 ++++++++++++++++++++++++------ arch/arm/mach-omap2/clockdomain.h | 6 +- arch/arm/mach-omap2/cm3xxx.c | 6 +- arch/arm/mach-omap2/cminst44xx.c | 2 +- arch/arm/mach-omap2/pm-debug.c | 6 +- arch/arm/mach-omap2/pm.c | 3 +- arch/arm/mach-omap2/prm2xxx_3xxx.c | 3 +- 7 files changed, 92 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index ab194753eb7a..2da3b5ec010c 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -210,7 +210,8 @@ static int _clkdm_add_wkdep(struct clockdomain *clkdm1, return ret; } - if (atomic_inc_return(&cd->wkdep_usecount) == 1) { + cd->wkdep_usecount++; + if (cd->wkdep_usecount == 1) { pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", clkdm1->name, clkdm2->name); @@ -252,7 +253,8 @@ static int _clkdm_del_wkdep(struct clockdomain *clkdm1, return ret; } - if (atomic_dec_return(&cd->wkdep_usecount) == 0) { + cd->wkdep_usecount--; + if (cd->wkdep_usecount == 0) { pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n", clkdm1->name, clkdm2->name); @@ -296,7 +298,8 @@ static int _clkdm_add_sleepdep(struct clockdomain *clkdm1, return ret; } - if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { + cd->sleepdep_usecount++; + if (cd->sleepdep_usecount == 1) { pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", clkdm1->name, clkdm2->name); @@ -340,7 +343,8 @@ static int _clkdm_del_sleepdep(struct clockdomain *clkdm1, return ret; } - if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { + cd->sleepdep_usecount--; + if (cd->sleepdep_usecount == 0) { pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n", clkdm1->name, clkdm2->name); @@ -567,7 +571,21 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) */ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { - return _clkdm_add_wkdep(clkdm1, clkdm2); + struct clkdm_dep *cd; + int ret; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) + return PTR_ERR(cd); + + pwrdm_lock(cd->clkdm->pwrdm.ptr); + ret = _clkdm_add_wkdep(clkdm1, clkdm2); + pwrdm_unlock(cd->clkdm->pwrdm.ptr); + + return ret; } /** @@ -582,7 +600,21 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) */ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { - return _clkdm_del_wkdep(clkdm1, clkdm2); + struct clkdm_dep *cd; + int ret; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) + return PTR_ERR(cd); + + pwrdm_lock(cd->clkdm->pwrdm.ptr); + ret = _clkdm_del_wkdep(clkdm1, clkdm2); + pwrdm_unlock(cd->clkdm->pwrdm.ptr); + + return ret; } /** @@ -620,7 +652,7 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return ret; } - /* XXX It's faster to return the atomic wkdep_usecount */ + /* XXX It's faster to return the wkdep_usecount */ return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); } @@ -659,7 +691,21 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) */ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { - return _clkdm_add_sleepdep(clkdm1, clkdm2); + struct clkdm_dep *cd; + int ret; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) + return PTR_ERR(cd); + + pwrdm_lock(cd->clkdm->pwrdm.ptr); + ret = _clkdm_add_sleepdep(clkdm1, clkdm2); + pwrdm_unlock(cd->clkdm->pwrdm.ptr); + + return ret; } /** @@ -676,7 +722,21 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) */ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) { - return _clkdm_del_sleepdep(clkdm1, clkdm2); + struct clkdm_dep *cd; + int ret; + + if (!clkdm1 || !clkdm2) + return -EINVAL; + + cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); + if (IS_ERR(cd)) + return PTR_ERR(cd); + + pwrdm_lock(cd->clkdm->pwrdm.ptr); + ret = _clkdm_del_sleepdep(clkdm1, clkdm2); + pwrdm_unlock(cd->clkdm->pwrdm.ptr); + + return ret; } /** @@ -716,7 +776,7 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) return ret; } - /* XXX It's faster to return the atomic sleepdep_usecount */ + /* XXX It's faster to return the sleepdep_usecount */ return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); } @@ -1063,7 +1123,8 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) * should be called for every clock instance or hwmod that is * enabled, so the clkdm can be force woken up. */ - if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { + clkdm->usecount++; + if (clkdm->usecount > 1 && autodeps) { pwrdm_unlock(clkdm->pwrdm.ptr); return 0; } @@ -1125,17 +1186,17 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) pwrdm_lock(clkdm->pwrdm.ptr); /* corner case: disabling unused clocks */ - if ((__clk_get_enable_count(clk) == 0) && - (atomic_read(&clkdm->usecount) == 0)) + if ((__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0) goto ccd_exit; - if (atomic_read(&clkdm->usecount) == 0) { + if (clkdm->usecount == 0) { pwrdm_unlock(clkdm->pwrdm.ptr); WARN_ON(1); /* underflow */ return -ERANGE; } - if (atomic_dec_return(&clkdm->usecount) > 0) { + clkdm->usecount--; + if (clkdm->usecount > 0) { pwrdm_unlock(clkdm->pwrdm.ptr); return 0; } @@ -1213,13 +1274,14 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) pwrdm_lock(clkdm->pwrdm.ptr); - if (atomic_read(&clkdm->usecount) == 0) { + if (clkdm->usecount == 0) { pwrdm_unlock(clkdm->pwrdm.ptr); WARN_ON(1); /* underflow */ return -ERANGE; } - if (atomic_dec_return(&clkdm->usecount) > 0) { + clkdm->usecount--; + if (clkdm->usecount > 0) { pwrdm_unlock(clkdm->pwrdm.ptr); return 0; } diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index 50c3cd8bd706..2da37656a693 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h @@ -91,8 +91,8 @@ struct clkdm_autodep { struct clkdm_dep { const char *clkdm_name; struct clockdomain *clkdm; - atomic_t wkdep_usecount; - atomic_t sleepdep_usecount; + s16 wkdep_usecount; + s16 sleepdep_usecount; }; /* Possible flags for struct clockdomain._flags */ @@ -136,7 +136,7 @@ struct clockdomain { const u16 clkdm_offs; struct clkdm_dep *wkdep_srcs; struct clkdm_dep *sleepdep_srcs; - atomic_t usecount; + int usecount; struct list_head node; }; diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index b94af4cb9dd9..9061c307d915 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c @@ -186,7 +186,7 @@ static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) continue; /* only happens if data is erroneous */ mask |= 1 << cd->clkdm->dep_bit; - atomic_set(&cd->sleepdep_usecount, 0); + cd->sleepdep_usecount = 0; } omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, OMAP3430_CM_SLEEPDEP); @@ -209,7 +209,7 @@ static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm) static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm) { - if (atomic_read(&clkdm->usecount) > 0) + if (clkdm->usecount > 0) clkdm_add_autodeps(clkdm); omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, @@ -221,7 +221,7 @@ static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm) omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); - if (atomic_read(&clkdm->usecount) > 0) + if (clkdm->usecount > 0) clkdm_del_autodeps(clkdm); } diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 7f9a464f01e9..f0290f5566fe 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -393,7 +393,7 @@ static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm) continue; /* only happens if data is erroneous */ mask |= 1 << cd->clkdm->dep_bit; - atomic_set(&cd->wkdep_usecount, 0); + cd->wkdep_usecount = 0; } omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition, diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index e2c291f52f92..6db89ae92389 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -83,10 +83,8 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) strncmp(clkdm->name, "dpll", 4) == 0) return 0; - seq_printf(s, "%s->%s (%d)", clkdm->name, - clkdm->pwrdm.ptr->name, - atomic_read(&clkdm->usecount)); - seq_printf(s, "\n"); + seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name, + clkdm->usecount); return 0; } diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 48d6d5d2c926..88586d15004a 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -110,11 +110,12 @@ static void __init omap2_init_processor_devices(void) int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) { + /* XXX The usecount test is racy */ if ((clkdm->flags & CLKDM_CAN_ENABLE_AUTO) && !(clkdm->flags & CLKDM_MISSING_IDLE_REPORTING)) clkdm_allow_idle(clkdm); else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && - atomic_read(&clkdm->usecount) == 0) + clkdm->usecount == 0) clkdm_sleep(clkdm); return 0; } diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index a3e121f94a86..947f6adfed0c 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -210,6 +210,7 @@ int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1, PM_WKDEP, (1 << clkdm2->dep_bit)); } +/* XXX Caller must hold the clkdm's powerdomain lock */ int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) { struct clkdm_dep *cd; @@ -221,7 +222,7 @@ int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) /* PRM accesses are slow, so minimize them */ mask |= 1 << cd->clkdm->dep_bit; - atomic_set(&cd->wkdep_usecount, 0); + cd->wkdep_usecount = 0; } omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, From 562e54d13b6e0b17f72c9e629e1fd0b71e2a8a36 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 26 Jan 2013 00:58:17 -0700 Subject: [PATCH 114/148] ARM: OMAP2+: powerdomain: fix whitespace, improve flag comments Fix some whitespace problems introduced by commit da03ce65b5431245b9cd20db3edaaa6b9f5c8dc1 ("OMAP3: powerdomain data: add voltage domains"). Also, improve the documentation for the struct powerdomain.flags field. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/powerdomain.h | 26 ++++++----- .../mach-omap2/powerdomains2xxx_3xxx_data.c | 4 +- arch/arm/mach-omap2/powerdomains2xxx_data.c | 8 ++-- arch/arm/mach-omap2/powerdomains3xxx_data.c | 44 +++++++++---------- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 909cc5c1c23a..140c36074fed 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -43,18 +43,20 @@ #define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON) -/* Powerdomain flags */ -#define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */ -#define PWRDM_HAS_MPU_QUIRK (1 << 1) /* MPU pwr domain has MEM bank 0 bits - * in MEM bank 1 position. This is - * true for OMAP3430 - */ -#define PWRDM_HAS_LOWPOWERSTATECHANGE (1 << 2) /* - * support to transition from a - * sleep state to a lower sleep - * state without waking up the - * powerdomain - */ +/* + * Powerdomain flags (struct powerdomain.flags) + * + * PWRDM_HAS_HDWR_SAR - powerdomain has hardware save-and-restore support + * + * PWRDM_HAS_MPU_QUIRK - MPU pwr domain has MEM bank 0 bits in MEM + * bank 1 position. This is true for OMAP3430 + * + * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state + * to a lower sleep state without waking up the powerdomain + */ +#define PWRDM_HAS_HDWR_SAR BIT(0) +#define PWRDM_HAS_MPU_QUIRK BIT(1) +#define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2) /* * Number of memory banks that are power-controllable. On OMAP4430, the diff --git a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c index d3a5399091ad..7b946f1005b1 100644 --- a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c @@ -54,12 +54,12 @@ struct powerdomain gfx_omap2_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; struct powerdomain wkup_omap2_pwrdm = { .name = "wkup_pwrdm", .prcm_offs = WKUP_MOD, .pwrsts = PWRSTS_ON, - .voltdm = { .name = "wakeup" }, + .voltdm = { .name = "wakeup" }, }; diff --git a/arch/arm/mach-omap2/powerdomains2xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_data.c index 01abc1e77789..578eef86fcf2 100644 --- a/arch/arm/mach-omap2/powerdomains2xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains2xxx_data.c @@ -38,7 +38,7 @@ static struct powerdomain dsp_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain mpu_24xx_pwrdm = { @@ -53,7 +53,7 @@ static struct powerdomain mpu_24xx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain core_24xx_pwrdm = { @@ -72,7 +72,7 @@ static struct powerdomain core_24xx_pwrdm = { [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; @@ -94,7 +94,7 @@ static struct powerdomain mdm_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; /* diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c index 8b23d234fb55..f0e14e9efe5a 100644 --- a/arch/arm/mach-omap2/powerdomains3xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c @@ -50,7 +50,7 @@ static struct powerdomain iva2_pwrdm = { [2] = PWRSTS_OFF_ON, [3] = PWRSTS_ON, }, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain mpu_3xxx_pwrdm = { @@ -66,7 +66,7 @@ static struct powerdomain mpu_3xxx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_OFF_ON, }, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain mpu_am35x_pwrdm = { @@ -82,7 +82,7 @@ static struct powerdomain mpu_am35x_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, }, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; /* @@ -109,7 +109,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = { [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain core_3xxx_es3_1_pwrdm = { @@ -131,7 +131,7 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = { [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain core_am35x_pwrdm = { @@ -148,7 +148,7 @@ static struct powerdomain core_am35x_pwrdm = { [0] = PWRSTS_ON, /* MEM1ONSTATE */ [1] = PWRSTS_ON, /* MEM2ONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dss_pwrdm = { @@ -163,7 +163,7 @@ static struct powerdomain dss_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dss_am35x_pwrdm = { @@ -178,7 +178,7 @@ static struct powerdomain dss_am35x_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; /* @@ -199,7 +199,7 @@ static struct powerdomain sgx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain sgx_am35x_pwrdm = { @@ -214,7 +214,7 @@ static struct powerdomain sgx_am35x_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain cam_pwrdm = { @@ -229,7 +229,7 @@ static struct powerdomain cam_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain per_pwrdm = { @@ -244,7 +244,7 @@ static struct powerdomain per_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain per_am35x_pwrdm = { @@ -259,13 +259,13 @@ static struct powerdomain per_am35x_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain emu_pwrdm = { .name = "emu_pwrdm", .prcm_offs = OMAP3430_EMU_MOD, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain neon_pwrdm = { @@ -273,7 +273,7 @@ static struct powerdomain neon_pwrdm = { .prcm_offs = OMAP3430_NEON_MOD, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_RET, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain neon_am35x_pwrdm = { @@ -281,7 +281,7 @@ static struct powerdomain neon_am35x_pwrdm = { .prcm_offs = OMAP3430_NEON_MOD, .pwrsts = PWRSTS_ON, .pwrsts_logic_ret = PWRSTS_ON, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain usbhost_pwrdm = { @@ -303,37 +303,37 @@ static struct powerdomain usbhost_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dpll1_pwrdm = { .name = "dpll1_pwrdm", .prcm_offs = MPU_MOD, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain dpll2_pwrdm = { .name = "dpll2_pwrdm", .prcm_offs = OMAP3430_IVA2_MOD, - .voltdm = { .name = "mpu_iva" }, + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain dpll3_pwrdm = { .name = "dpll3_pwrdm", .prcm_offs = PLL_MOD, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dpll4_pwrdm = { .name = "dpll4_pwrdm", .prcm_offs = PLL_MOD, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; static struct powerdomain dpll5_pwrdm = { .name = "dpll5_pwrdm", .prcm_offs = PLL_MOD, - .voltdm = { .name = "core" }, + .voltdm = { .name = "core" }, }; /* As powerdomains are added or removed above, this list must also be changed */ From 0f234d91b8f50119c4c921db9d9dc0dac24db383 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Thu, 10 Jan 2013 11:16:43 +0100 Subject: [PATCH 115/148] ARM: mach-shmobile: add shmobile_cpu_disable_any() Method to disable any core to be used on platforms where CPU0 does not need special treatment. Signed-off-by: Ulrich Hecht Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/hotplug.c | 6 ++++++ arch/arm/mach-shmobile/include/mach/common.h | 1 + 2 files changed, 7 insertions(+) diff --git a/arch/arm/mach-shmobile/hotplug.c b/arch/arm/mach-shmobile/hotplug.c index b09a0bdbf813..a1524e3367b0 100644 --- a/arch/arm/mach-shmobile/hotplug.c +++ b/arch/arm/mach-shmobile/hotplug.c @@ -56,6 +56,12 @@ int shmobile_cpu_disable(unsigned int cpu) return cpu == 0 ? -EPERM : 0; } +int shmobile_cpu_disable_any(unsigned int cpu) +{ + cpumask_clear_cpu(cpu, &dead_cpus); + return 0; +} + int shmobile_cpu_is_dead(unsigned int cpu) { return cpumask_test_cpu(cpu, &dead_cpus); diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 64c0622ae7d6..e48606d8a2be 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -84,6 +84,7 @@ static inline int shmobile_cpuidle_init(void) { return 0; } extern void shmobile_cpu_die(unsigned int cpu); extern int shmobile_cpu_disable(unsigned int cpu); +extern int shmobile_cpu_disable_any(unsigned int cpu); #ifdef CONFIG_HOTPLUG_CPU extern int shmobile_cpu_is_dead(unsigned int cpu); From dc784e73b45dc055f9dcb174ea5753ea020516fc Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Thu, 10 Jan 2013 11:16:44 +0100 Subject: [PATCH 116/148] ARM: mach-shmobile: sh73a0: allow unplugging of CPU0 sh73a0 deals fine with disabling any core, so we should permit it. Signed-off-by: Ulrich Hecht Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/smp-sh73a0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 9812ea3255c9..acb46a94ccdf 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -143,6 +143,6 @@ struct smp_operations sh73a0_smp_ops __initdata = { #ifdef CONFIG_HOTPLUG_CPU .cpu_kill = sh73a0_cpu_kill, .cpu_die = sh73a0_cpu_die, - .cpu_disable = shmobile_cpu_disable, + .cpu_disable = shmobile_cpu_disable_any, #endif }; From eea8e326ff476e418b99b6daa97f9bd85ac6c523 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 6 Dec 2012 22:54:41 +0800 Subject: [PATCH 117/148] ARM: imx: return zero in case next event gets a large increment The return of v2_set_next_event() will lead to an infinite loop in tick_handle_oneshot_broadcast() - "goto again;" with imx6q WAIT mode (to be enabled). This happens because when global event did not expire any CPU local events, the broadcast device will be rearmed to a CPU local next_event, which could be far away from now and result in a max_delta_tick programming in set_next_event(). Fix the problem by detecting those next events with increments larger than 0x7fffffff, and simply return zero in that case. It leaves mx1_2_set_next_event() unchanged since only v2_set_next_event() will be running with imx6q WAIT mode support. Thanks Russell King for helping understand the problem. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/time.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index f017302f6d09..5d7eb482efd3 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c @@ -152,7 +152,8 @@ static int v2_set_next_event(unsigned long evt, __raw_writel(tcmp, timer_base + V2_TCMP); - return (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ? + return evt < 0x7fffffff && + (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ? -ETIME : 0; } From 485863b8fa02d515e48ce6b59f01d62172d2fe0d Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 4 Dec 2012 22:55:13 +0800 Subject: [PATCH 118/148] ARM: imx: mask gpc interrupts initially Mask gpc interrupts initially to avoid suspicious interrupts. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/gpc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index e1537f9e45b8..722e5df7e44e 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -101,11 +101,16 @@ static void imx_gpc_irq_mask(struct irq_data *d) void __init imx_gpc_init(void) { struct device_node *np; + int i; np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); gpc_base = of_iomap(np, 0); WARN_ON(!gpc_base); + /* Initially mask all interrupts */ + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4); + /* Register GPC as the secondary interrupt controller behind GIC */ gic_arch_extn.irq_mask = imx_gpc_irq_mask; gic_arch_extn.irq_unmask = imx_gpc_irq_unmask; From 12bb344074cfc50482121c76571e3cda07c4bc09 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 4 Dec 2012 22:55:14 +0800 Subject: [PATCH 119/148] ARM: imx: move imx6q_cpuidle_driver into a separate file Move imx6q_cpuidle_driver into a separate file as more codes will be added when WAIT mode gets implemented as cpuidle. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 6 +++++- arch/arm/mach-imx/cpuidle-imx6q.c | 26 ++++++++++++++++++++++++++ arch/arm/mach-imx/cpuidle.h | 5 +++++ arch/arm/mach-imx/mach-imx6q.c | 12 +----------- 4 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 arch/arm/mach-imx/cpuidle-imx6q.c diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 240e0294c372..c4ce0906d76a 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -28,7 +28,11 @@ obj-$(CONFIG_MXC_ULPI) += ulpi.o obj-$(CONFIG_MXC_USE_EPIT) += epit.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o -obj-$(CONFIG_CPU_IDLE) += cpuidle.o + +ifeq ($(CONFIG_CPU_IDLE),y) +obj-y += cpuidle.o +obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o +endif ifdef CONFIG_SND_IMX_SOC obj-y += ssi-fiq.o diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c new file mode 100644 index 000000000000..83facc97b5da --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * + * 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. + */ + +#include +#include +#include + +#include "cpuidle.h" + +static struct cpuidle_driver imx6q_cpuidle_driver = { + .name = "imx6q_cpuidle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, + .states[0] = ARM_CPUIDLE_WFI_STATE, + .state_count = 1, +}; + +int __init imx6q_cpuidle_init(void) +{ + return imx_cpuidle_init(&imx6q_cpuidle_driver); +} diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h index bc932d1af372..e092d1359d94 100644 --- a/arch/arm/mach-imx/cpuidle.h +++ b/arch/arm/mach-imx/cpuidle.h @@ -14,9 +14,14 @@ #ifdef CONFIG_CPU_IDLE extern int imx_cpuidle_init(struct cpuidle_driver *drv); +extern int imx6q_cpuidle_init(void); #else static inline int imx_cpuidle_init(struct cpuidle_driver *drv) { return -ENODEV; } +static inline int imx6q_cpuidle_init(void) +{ + return -ENODEV; +} #endif diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index ce7476d49271..27726de3537e 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -26,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -202,17 +200,9 @@ static void __init imx6q_init_machine(void) imx6q_1588_init(); } -static struct cpuidle_driver imx6q_cpuidle_driver = { - .name = "imx6q_cpuidle", - .owner = THIS_MODULE, - .en_core_tk_irqen = 1, - .states[0] = ARM_CPUIDLE_WFI_STATE, - .state_count = 1, -}; - static void __init imx6q_init_late(void) { - imx_cpuidle_init(&imx6q_cpuidle_driver); + imx6q_cpuidle_init(); } static void __init imx6q_map_io(void) From e5f9dec8ff5ff3f6254412abed1f68d758f6616b Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 4 Dec 2012 22:55:15 +0800 Subject: [PATCH 120/148] ARM: imx6q: support WAIT mode using cpuidle Add WAIT mode (ARM core clock gating) support to imx6q cpuidle driver. As WAIT mode is broken on imx6q TO 1.0 and 1.1, it only enables the support for revision 1.2 with chicken bit set. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 12 +++++ arch/arm/mach-imx/common.h | 3 ++ arch/arm/mach-imx/cpuidle-imx6q.c | 73 ++++++++++++++++++++++++++++++- arch/arm/mach-imx/mach-imx6q.c | 7 ++- arch/arm/mach-imx/platsmp.c | 10 +++++ 5 files changed, 102 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index c7e429bd32d0..b30b65a8cce5 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -54,8 +54,19 @@ #define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) #define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) +#define CGPR 0x64 +#define BM_CGPR_CHICKEN_BIT (0x1 << 17) + static void __iomem *ccm_base; +void imx6q_set_chicken_bit(void) +{ + u32 val = readl_relaxed(ccm_base + CGPR); + + val |= BM_CGPR_CHICKEN_BIT; + writel_relaxed(val, ccm_base + CGPR); +} + int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) { u32 val = readl_relaxed(ccm_base + CLPCR); @@ -66,6 +77,7 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) break; case WAIT_UNCLOCKED: val |= 0x1 << BP_CLPCR_LPM; + val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM; break; case STOP_POWER_ON: val |= 0x2 << BP_CLPCR_LPM; diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 972c9f8cc97a..c04ec845e3a3 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -117,9 +117,11 @@ extern u32 *pl310_get_save_ptr(void); extern void v7_secondary_startup(void); extern void imx_scu_map_io(void); extern void imx_smp_prepare(void); +extern void imx_scu_standby_enable(void); #else static inline void imx_scu_map_io(void) {} static inline void imx_smp_prepare(void) {} +static inline void imx_scu_standby_enable(void) {} #endif extern void imx_enable_cpu(int cpu, bool enable); extern void imx_set_cpu_jump(int cpu, void *jump_addr); @@ -129,6 +131,7 @@ extern void imx_gpc_init(void); extern void imx_gpc_pre_suspend(void); extern void imx_gpc_post_resume(void); extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); +extern void imx6q_set_chicken_bit(void); extern void imx_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index 83facc97b5da..d533e2695f0e 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -6,21 +6,90 @@ * published by the Free Software Foundation. */ +#include #include #include #include +#include +#include "common.h" #include "cpuidle.h" +static atomic_t master = ATOMIC_INIT(0); +static DEFINE_SPINLOCK(master_lock); + +static int imx6q_enter_wait(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + int cpu = dev->cpu; + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); + + if (atomic_inc_return(&master) == num_online_cpus()) { + /* + * With this lock, we prevent other cpu to exit and enter + * this function again and become the master. + */ + if (!spin_trylock(&master_lock)) + goto idle; + imx6q_set_lpm(WAIT_UNCLOCKED); + cpu_do_idle(); + imx6q_set_lpm(WAIT_CLOCKED); + spin_unlock(&master_lock); + goto done; + } + +idle: + cpu_do_idle(); +done: + atomic_dec(&master); + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); + + return index; +} + +/* + * For each cpu, setup the broadcast timer because local timer + * stops for the states other than WFI. + */ +static void imx6q_setup_broadcast_timer(void *arg) +{ + int cpu = smp_processor_id(); + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); +} + static struct cpuidle_driver imx6q_cpuidle_driver = { .name = "imx6q_cpuidle", .owner = THIS_MODULE, .en_core_tk_irqen = 1, - .states[0] = ARM_CPUIDLE_WFI_STATE, - .state_count = 1, + .states = { + /* WFI */ + ARM_CPUIDLE_WFI_STATE, + /* WAIT */ + { + .exit_latency = 50, + .target_residency = 75, + .flags = CPUIDLE_FLAG_TIME_VALID, + .enter = imx6q_enter_wait, + .name = "WAIT", + .desc = "Clock off", + }, + }, + .state_count = 2, + .safe_state_index = 0, }; int __init imx6q_cpuidle_init(void) { + /* Need to enable SCU standby for entering WAIT modes */ + imx_scu_standby_enable(); + + /* Set chicken bit to get a reliable WAIT mode support */ + imx6q_set_chicken_bit(); + + /* Configure the broadcast timer on each cpu */ + on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1); + return imx_cpuidle_init(&imx6q_cpuidle_driver); } diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 27726de3537e..77a3b4bfff20 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -202,7 +202,12 @@ static void __init imx6q_init_machine(void) static void __init imx6q_init_late(void) { - imx6q_cpuidle_init(); + /* + * WAIT mode is broken on TO 1.0 and 1.1, so there is no point + * to run cpuidle on them. + */ + if (imx6q_revision() > IMX_CHIP_REVISION_1_1) + imx6q_cpuidle_init(); } static void __init imx6q_map_io(void) diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 3777b805b76b..a70b54877191 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -20,6 +20,8 @@ #include "common.h" #include "hardware.h" +#define SCU_STANDBY_ENABLE (1 << 5) + static void __iomem *scu_base; static struct map_desc scu_io_desc __initdata = { @@ -42,6 +44,14 @@ void __init imx_scu_map_io(void) scu_base = IMX_IO_ADDRESS(base); } +void imx_scu_standby_enable(void) +{ + u32 val = readl_relaxed(scu_base); + + val |= SCU_STANDBY_ENABLE; + writel_relaxed(val, scu_base); +} + static void __cpuinit imx_secondary_init(unsigned int cpu) { /* From b73690c8f8b5d12ed32e10fb787f54e4b4ca232b Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 21 Nov 2012 11:25:28 -0700 Subject: [PATCH 121/148] ARM: Kirkwood: Support basic hotplug for PCI-E Unconditionally register the PCI-E bus, even if the link is currently down. When the link is brought up the bus can be scanned through /sys/bus/pci/rescan or otherwise. Since the HW has no interrupt for link up, userspace will have to take care of the timing. An earlier version of this was contingent on CONFIG_HOTPLUG, but that is being removed from the kernel. This also fixes printing the link up/down message to be displayed on one line (structured logging broke this?) Signed-off-by: Jason Gunthorpe Signed-off-by: Jason Cooper --- arch/arm/mach-kirkwood/pcie.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index a1c3ab6fc809..d96ad4c09972 100644 --- a/arch/arm/mach-kirkwood/pcie.c +++ b/arch/arm/mach-kirkwood/pcie.c @@ -247,13 +247,9 @@ static struct hw_pci kirkwood_pci __initdata = { static void __init add_pcie_port(int index, void __iomem *base) { - pr_info("Kirkwood PCIe port %d: ", index); - - if (orion_pcie_link_up(base)) { - pr_info("link up\n"); - pcie_port_map[num_pcie_ports++] = index; - } else - pr_info("link down, ignoring\n"); + pcie_port_map[num_pcie_ports++] = index; + pr_info("Kirkwood PCIe port %d: link %s\n", index, + orion_pcie_link_up(base) ? "up" : "down"); } void __init kirkwood_pcie_init(unsigned int portmask) From a1671da560df1f6bd20d8c6934d1cfa2aacc4f32 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 12 Dec 2012 10:06:23 +0100 Subject: [PATCH 122/148] rtc: Add support of rtc-mv for MVEBU SoCs The Armada 370 and Armada XP Socs have the same controller that the one used in the orion platforms. This patch enables the selection of rtc-mv with mvebu platforms. Signed-off-by: Gregory CLEMENT Acked-by: Andrew Lunn Tested-by: Florian Fainelli Acked-by: Arnd Bergmann Signed-off-by: Jason Cooper --- drivers/rtc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 923a9da9c829..20354b43932e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1023,7 +1023,7 @@ config RTC_DRV_TX4939 config RTC_DRV_MV tristate "Marvell SoC RTC" - depends on ARCH_KIRKWOOD || ARCH_DOVE + depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU help If you say yes here you will get support for the in-chip RTC that can be found in some of Marvell's SoC devices, such as From 9cfc94eb0f4843af5d1141a37d7b7ca5d3b27220 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 9 Jan 2013 13:22:15 +0100 Subject: [PATCH 123/148] cpuidle: kirkwood: Move out of mach directory Move the Kirkwood cpuidle driver out of arch/arm/mach-kirkwood and into drivers/cpuidle. Convert the driver into a platform driver. Signed-off-by: Andrew Lunn Signed-off-by: Jason Cooper --- arch/arm/configs/kirkwood_defconfig | 1 + arch/arm/mach-kirkwood/Makefile | 1 - arch/arm/mach-kirkwood/board-dt.c | 2 + arch/arm/mach-kirkwood/common.c | 23 ++++++++++ arch/arm/mach-kirkwood/common.h | 1 + .../arm/mach-kirkwood/include/mach/kirkwood.h | 3 +- drivers/cpuidle/Kconfig | 6 +++ drivers/cpuidle/Makefile | 1 + .../cpuidle/cpuidle-kirkwood.c | 45 ++++++++++++++++--- 9 files changed, 75 insertions(+), 8 deletions(-) rename arch/arm/mach-kirkwood/cpuidle.c => drivers/cpuidle/cpuidle-kirkwood.c (61%) diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig index 93f3794ba5cb..13482ea58b09 100644 --- a/arch/arm/configs/kirkwood_defconfig +++ b/arch/arm/configs/kirkwood_defconfig @@ -56,6 +56,7 @@ CONFIG_AEABI=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_KIRKWOOD=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile index 8d2e5a96247c..d6653095a1eb 100644 --- a/arch/arm/mach-kirkwood/Makefile +++ b/arch/arm/mach-kirkwood/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_MACH_NET2BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o obj-$(CONFIG_MACH_NET5BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o obj-$(CONFIG_MACH_T5325) += t5325-setup.o -obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_KIRKWOOD_DT) += board-dt.o obj-$(CONFIG_MACH_DREAMPLUG_DT) += board-dreamplug.o obj-$(CONFIG_MACH_ICONNECT_DT) += board-iconnect.o diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c index de4fd2bb1e27..f964cdc44b1a 100644 --- a/arch/arm/mach-kirkwood/board-dt.c +++ b/arch/arm/mach-kirkwood/board-dt.c @@ -98,6 +98,8 @@ static void __init kirkwood_dt_init(void) /* Setup root of clk tree */ kirkwood_of_clk_init(); + kirkwood_cpuidle_init(); + #ifdef CONFIG_KEXEC kexec_reinit = kirkwood_enable_pcie; #endif diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index bac21a554c91..5ed1f2e8c5f8 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -499,6 +499,28 @@ void __init kirkwood_wdt_init(void) orion_wdt_init(); } +/***************************************************************************** + * CPU idle + ****************************************************************************/ +static struct resource kirkwood_cpuidle_resource[] = { + { + .flags = IORESOURCE_MEM, + .start = DDR_OPERATION_BASE, + .end = DDR_OPERATION_BASE + 3, + }, +}; + +static struct platform_device kirkwood_cpuidle = { + .name = "kirkwood_cpuidle", + .id = -1, + .resource = kirkwood_cpuidle_resource, + .num_resources = 1, +}; + +void __init kirkwood_cpuidle_init(void) +{ + platform_device_register(&kirkwood_cpuidle); +} /***************************************************************************** * Time handling @@ -671,6 +693,7 @@ void __init kirkwood_init(void) kirkwood_xor1_init(); kirkwood_crypto_init(); + kirkwood_cpuidle_init(); #ifdef CONFIG_KEXEC kexec_reinit = kirkwood_enable_pcie; #endif diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h index 5ffa57f08c80..320aa61ff505 100644 --- a/arch/arm/mach-kirkwood/common.h +++ b/arch/arm/mach-kirkwood/common.h @@ -50,6 +50,7 @@ void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay); void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *)); void kirkwood_audio_init(void); +void kirkwood_cpuidle_init(void); void kirkwood_restart(char, const char *); void kirkwood_clk_init(void); diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h index 041653a04a9c..a05563a31c95 100644 --- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h +++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h @@ -60,8 +60,9 @@ * Register Map */ #define DDR_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE + 0x00000) +#define DDR_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x00000) #define DDR_WINDOW_CPU_BASE (DDR_VIRT_BASE + 0x1500) -#define DDR_OPERATION_BASE (DDR_VIRT_BASE + 0x1418) +#define DDR_OPERATION_BASE (DDR_PHYS_BASE + 0x1418) #define DEV_BUS_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x10000) #define DEV_BUS_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE + 0x10000) diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index c4cc27e5c8a5..071e2c3eec4f 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -39,4 +39,10 @@ config CPU_IDLE_CALXEDA help Select this to enable cpuidle on Calxeda processors. +config CPU_IDLE_KIRKWOOD + bool "CPU Idle Driver for Kirkwood processors" + depends on ARCH_KIRKWOOD + help + Select this to enable cpuidle on Kirkwood processors. + endif diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 03ee87482c71..24c6e7d945ed 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -6,3 +6,4 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o +obj-$(CONFIG_CPU_IDLE_KIRKWOOD) += cpuidle-kirkwood.o diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/drivers/cpuidle/cpuidle-kirkwood.c similarity index 61% rename from arch/arm/mach-kirkwood/cpuidle.c rename to drivers/cpuidle/cpuidle-kirkwood.c index f7304670f2f8..670aa1e55cd6 100644 --- a/arch/arm/mach-kirkwood/cpuidle.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -21,16 +22,17 @@ #include #include #include -#include #define KIRKWOOD_MAX_STATES 2 +static void __iomem *ddr_operation_base; + /* Actual code that puts the SoC in different idle states */ static int kirkwood_enter_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, + struct cpuidle_driver *drv, int index) { - writel(0x7, DDR_OPERATION_BASE); + writel(0x7, ddr_operation_base); cpu_do_idle(); return index; @@ -51,13 +53,22 @@ static struct cpuidle_driver kirkwood_idle_driver = { }, .state_count = KIRKWOOD_MAX_STATES, }; +static struct cpuidle_device *device; static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); /* Initialize CPU idle by registering the idle states */ -static int kirkwood_init_cpuidle(void) +static int kirkwood_cpuidle_probe(struct platform_device *pdev) { - struct cpuidle_device *device; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -EINVAL; + + ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res); + if (!ddr_operation_base) + return -EADDRNOTAVAIL; device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); device->state_count = KIRKWOOD_MAX_STATES; @@ -70,4 +81,26 @@ static int kirkwood_init_cpuidle(void) return 0; } -device_initcall(kirkwood_init_cpuidle); +int kirkwood_cpuidle_remove(struct platform_device *pdev) +{ + cpuidle_unregister_device(device); + cpuidle_unregister_driver(&kirkwood_idle_driver); + + return 0; +} + +static struct platform_driver kirkwood_cpuidle_driver = { + .probe = kirkwood_cpuidle_probe, + .remove = kirkwood_cpuidle_remove, + .driver = { + .name = "kirkwood_cpuidle", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(kirkwood_cpuidle_driver); + +MODULE_AUTHOR("Andrew Lunn "); +MODULE_DESCRIPTION("Kirkwood cpu idle driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kirkwood-cpuidle"); From f93c32d90f8d878c3cad78f41a047ca4fb5792ba Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 25 Dec 2012 10:07:52 -0200 Subject: [PATCH 124/148] ARM: imx_v6_v7_defconfig: Select IPUV3 driver Let IPUV3 driver be built by default. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/imx_v6_v7_defconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 6dddbf877b0c..a225f1cec333 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -158,6 +158,7 @@ CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_OV2640=y +CONFIG_DRM=y CONFIG_VIDEO_MX3=y CONFIG_FB=y CONFIG_LCD_PLATFORM=y @@ -199,6 +200,10 @@ CONFIG_RTC_DRV_MXC=y CONFIG_DMADEVICES=y CONFIG_IMX_SDMA=y CONFIG_MXS_DMA=y +CONFIG_STAGING=y +CONFIG_DRM_IMX=y +CONFIG_DRM_IMX_IPUV3_CORE=y +CONFIG_DRM_IMX_IPUV3=y CONFIG_COMMON_CLK_DEBUG=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT2_FS=y From 4ad625d466389b016a9aec425b3dc2d82adc43df Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 12 Dec 2012 18:54:01 +0800 Subject: [PATCH 125/148] ARM: imx: use separated debug uart symbol for imx31 and imx35 It's improper to use combined symbol DEBUG_IMX31_IMX35_UART for imx31 and imx35, because imx31 has 5 UARTs while imx35 only has 3. So later when we add UART port selection for DEBUG_IMX31_IMX35_UART, we will have problem. Use separated Kconfig options for imx31 and imx35 debug uart selection. Signed-off-by: Shawn Guo --- arch/arm/Kconfig.debug | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 1dceb8e31618..dfe788a84e5e 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -205,12 +205,19 @@ choice Say Y here if you want kernel low-level debugging support on i.MX28. - config DEBUG_IMX31_IMX35_UART - bool "i.MX31 and i.MX35 Debug UART" - depends on SOC_IMX31 || SOC_IMX35 + config DEBUG_IMX31_UART + bool "i.MX31 Debug UART" + depends on SOC_IMX31 help Say Y here if you want kernel low-level debugging support - on i.MX31 or i.MX35. + on i.MX31. + + config DEBUG_IMX35_UART + bool "i.MX35 Debug UART" + depends on SOC_IMX35 + help + Say Y here if you want kernel low-level debugging support + on i.MX35. config DEBUG_IMX51_UART bool "i.MX51 Debug UART" @@ -495,7 +502,8 @@ config DEBUG_LL_INCLUDE default "debug/imx.S" if DEBUG_IMX1_UART || \ DEBUG_IMX25_UART || \ DEBUG_IMX21_IMX27_UART || \ - DEBUG_IMX31_IMX35_UART || \ + DEBUG_IMX31_UART || \ + DEBUG_IMX35_UART || \ DEBUG_IMX51_UART || \ DEBUG_IMX53_UART ||\ DEBUG_IMX6Q_UART From f8c95fe6d9adad72fc7bce90f4ab68d119f50c5b Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 12 Dec 2012 19:03:53 +0800 Subject: [PATCH 126/148] ARM: imx: support DEBUG_LL uart port selection for all i.MX SoCs Extend imx6q DEBUG_LL uart port selection support to cover all i.MX SoCs. The 'range' of the Kconfig option gets dropped, as users looking at the option must know the uart number on his board. The bottom line is that the build system will report an error if an invalid port number is picked for given SoC. The header arch/arm/include/debug/imx-uart.h is created to accommodate all the uart base addresses. And the header will also be used for other low-level debug facility later. Signed-off-by: Shawn Guo --- arch/arm/Kconfig.debug | 13 +++-- arch/arm/include/debug/imx-uart.h | 88 +++++++++++++++++++++++++++++++ arch/arm/include/debug/imx.S | 29 +--------- 3 files changed, 98 insertions(+), 32 deletions(-) create mode 100644 arch/arm/include/debug/imx-uart.h diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index dfe788a84e5e..7fee63f84099 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -457,11 +457,16 @@ choice endchoice -config DEBUG_IMX6Q_UART_PORT - int "i.MX6Q Debug UART Port (1-5)" if DEBUG_IMX6Q_UART - range 1 5 +config DEBUG_IMX_UART_PORT + int "i.MX Debug UART Port Selection" if DEBUG_IMX1_UART || \ + DEBUG_IMX25_UART || \ + DEBUG_IMX21_IMX27_UART || \ + DEBUG_IMX31_UART || \ + DEBUG_IMX35_UART || \ + DEBUG_IMX51_UART || \ + DEBUG_IMX50_IMX53_UART || \ + DEBUG_IMX6Q_UART default 1 - depends on SOC_IMX6Q help Choose UART port on which kernel low-level debug messages should be output. diff --git a/arch/arm/include/debug/imx-uart.h b/arch/arm/include/debug/imx-uart.h new file mode 100644 index 000000000000..91d38e38a0b4 --- /dev/null +++ b/arch/arm/include/debug/imx-uart.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * + * 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. + */ + +#ifndef __DEBUG_IMX_UART_H +#define __DEBUG_IMX_UART_H + +#define IMX1_UART1_BASE_ADDR 0x00206000 +#define IMX1_UART2_BASE_ADDR 0x00207000 +#define IMX1_UART_BASE_ADDR(n) IMX1_UART##n##_BASE_ADDR +#define IMX1_UART_BASE(n) IMX1_UART_BASE_ADDR(n) + +#define IMX21_UART1_BASE_ADDR 0x1000a000 +#define IMX21_UART2_BASE_ADDR 0x1000b000 +#define IMX21_UART3_BASE_ADDR 0x1000c000 +#define IMX21_UART4_BASE_ADDR 0x1000d000 +#define IMX21_UART_BASE_ADDR(n) IMX21_UART##n##_BASE_ADDR +#define IMX21_UART_BASE(n) IMX21_UART_BASE_ADDR(n) + +#define IMX25_UART1_BASE_ADDR 0x43f90000 +#define IMX25_UART2_BASE_ADDR 0x43f94000 +#define IMX25_UART3_BASE_ADDR 0x5000c000 +#define IMX25_UART4_BASE_ADDR 0x50008000 +#define IMX25_UART5_BASE_ADDR 0x5002c000 +#define IMX25_UART_BASE_ADDR(n) IMX25_UART##n##_BASE_ADDR +#define IMX25_UART_BASE(n) IMX25_UART_BASE_ADDR(n) + +#define IMX31_UART1_BASE_ADDR 0x43f90000 +#define IMX31_UART2_BASE_ADDR 0x43f94000 +#define IMX31_UART3_BASE_ADDR 0x5000c000 +#define IMX31_UART4_BASE_ADDR 0x43fb0000 +#define IMX31_UART5_BASE_ADDR 0x43fb4000 +#define IMX31_UART_BASE_ADDR(n) IMX31_UART##n##_BASE_ADDR +#define IMX31_UART_BASE(n) IMX31_UART_BASE_ADDR(n) + +#define IMX35_UART1_BASE_ADDR 0x43f90000 +#define IMX35_UART2_BASE_ADDR 0x43f94000 +#define IMX35_UART3_BASE_ADDR 0x5000c000 +#define IMX35_UART_BASE_ADDR(n) IMX35_UART##n##_BASE_ADDR +#define IMX35_UART_BASE(n) IMX35_UART_BASE_ADDR(n) + +#define IMX51_UART1_BASE_ADDR 0x73fbc000 +#define IMX51_UART2_BASE_ADDR 0x73fc0000 +#define IMX51_UART3_BASE_ADDR 0x7000c000 +#define IMX51_UART_BASE_ADDR(n) IMX51_UART##n##_BASE_ADDR +#define IMX51_UART_BASE(n) IMX51_UART_BASE_ADDR(n) + +#define IMX53_UART1_BASE_ADDR 0x53fbc000 +#define IMX53_UART2_BASE_ADDR 0x53fc0000 +#define IMX53_UART3_BASE_ADDR 0x5000c000 +#define IMX53_UART4_BASE_ADDR 0x53ff0000 +#define IMX53_UART5_BASE_ADDR 0x63f90000 +#define IMX53_UART_BASE_ADDR(n) IMX53_UART##n##_BASE_ADDR +#define IMX53_UART_BASE(n) IMX53_UART_BASE_ADDR(n) + +#define IMX6Q_UART1_BASE_ADDR 0x02020000 +#define IMX6Q_UART2_BASE_ADDR 0x021e8000 +#define IMX6Q_UART3_BASE_ADDR 0x021ec000 +#define IMX6Q_UART4_BASE_ADDR 0x021f0000 +#define IMX6Q_UART5_BASE_ADDR 0x021f4000 +#define IMX6Q_UART_BASE_ADDR(n) IMX6Q_UART##n##_BASE_ADDR +#define IMX6Q_UART_BASE(n) IMX6Q_UART_BASE_ADDR(n) + +#define IMX_DEBUG_UART_BASE(soc) soc##_UART_BASE(CONFIG_DEBUG_IMX_UART_PORT) + +#ifdef CONFIG_DEBUG_IMX1_UART +#define UART_PADDR IMX_DEBUG_UART_BASE(IMX1) +#elif defined(CONFIG_DEBUG_IMX21_IMX27_UART) +#define UART_PADDR IMX_DEBUG_UART_BASE(IMX21) +#elif defined(CONFIG_DEBUG_IMX25_UART) +#define UART_PADDR IMX_DEBUG_UART_BASE(IMX25) +#elif defined(CONFIG_DEBUG_IMX31_UART) +#define UART_PADDR IMX_DEBUG_UART_BASE(IMX31) +#elif defined(CONFIG_DEBUG_IMX35_UART) +#define UART_PADDR IMX_DEBUG_UART_BASE(IMX35) +#elif defined(CONFIG_DEBUG_IMX51_UART) +#define UART_PADDR IMX_DEBUG_UART_BASE(IMX51) +#elif defined(CONFIG_DEBUG_IMX53_UART) +#define UART_PADDR IMX_DEBUG_UART_BASE(IMX53) +#elif defined(CONFIG_DEBUG_IMX6Q_UART) +#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6Q) +#endif + +#endif /* __DEBUG_IMX_UART_H */ diff --git a/arch/arm/include/debug/imx.S b/arch/arm/include/debug/imx.S index c6f294cf18f0..619d8cc1ac12 100644 --- a/arch/arm/include/debug/imx.S +++ b/arch/arm/include/debug/imx.S @@ -10,35 +10,8 @@ * published by the Free Software Foundation. * */ -#define IMX6Q_UART1_BASE_ADDR 0x02020000 -#define IMX6Q_UART2_BASE_ADDR 0x021e8000 -#define IMX6Q_UART3_BASE_ADDR 0x021ec000 -#define IMX6Q_UART4_BASE_ADDR 0x021f0000 -#define IMX6Q_UART5_BASE_ADDR 0x021f4000 -/* - * IMX6Q_UART_BASE_ADDR is put in the middle to force the expansion - * of IMX6Q_UART##n##_BASE_ADDR. - */ -#define IMX6Q_UART_BASE_ADDR(n) IMX6Q_UART##n##_BASE_ADDR -#define IMX6Q_UART_BASE(n) IMX6Q_UART_BASE_ADDR(n) -#define IMX6Q_DEBUG_UART_BASE IMX6Q_UART_BASE(CONFIG_DEBUG_IMX6Q_UART_PORT) - -#ifdef CONFIG_DEBUG_IMX1_UART -#define UART_PADDR 0x00206000 -#elif defined (CONFIG_DEBUG_IMX25_UART) -#define UART_PADDR 0x43f90000 -#elif defined (CONFIG_DEBUG_IMX21_IMX27_UART) -#define UART_PADDR 0x1000a000 -#elif defined (CONFIG_DEBUG_IMX31_IMX35_UART) -#define UART_PADDR 0x43f90000 -#elif defined (CONFIG_DEBUG_IMX51_UART) -#define UART_PADDR 0x73fbc000 -#elif defined (CONFIG_DEBUG_IMX53_UART) -#define UART_PADDR 0x53fbc000 -#elif defined (CONFIG_DEBUG_IMX6Q_UART) -#define UART_PADDR IMX6Q_DEBUG_UART_BASE -#endif +#include "imx-uart.h" /* * FIXME: This is a copy of IMX_IO_P2V in hardware.h, and needs to From 26246919329c045d8c1bd70dfebd44c54a5cf657 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 29 Jan 2013 23:12:59 +0800 Subject: [PATCH 127/148] ARM: imx_v6_v7_defconfig: enable anatop regulator and snvs rtc Eanble anatop regulator and snvs rtc support which are very useful for imx6q build. Signed-off-by: Shawn Guo --- arch/arm/configs/imx_v6_v7_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index a225f1cec333..6039f0c44147 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -150,6 +150,7 @@ CONFIG_MFD_MC13XXX_I2C=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_DA9052=y +CONFIG_REGULATOR_ANATOP=y CONFIG_REGULATOR_MC13783=y CONFIG_REGULATOR_MC13892=y CONFIG_MEDIA_SUPPORT=y @@ -197,6 +198,7 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_INTF_DEV_UIE_EMUL=y CONFIG_RTC_DRV_MC13XXX=y CONFIG_RTC_DRV_MXC=y +CONFIG_RTC_DRV_SNVS=y CONFIG_DMADEVICES=y CONFIG_IMX_SDMA=y CONFIG_MXS_DMA=y From 77d168a99877bd045f02e4845a7f392762f182fb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 21 Dec 2012 03:07:31 +0100 Subject: [PATCH 128/148] ARM: mxs: Update mxs_defconfig Regenerate the mxs_defconfig to match recent kernel using the following commands: make mxs_defconfig make savedefconfig cp defconfig arch/arm/configs/mxs_defconfig Then enable these features: - MTD block access - UBI and UBIFS - JFFS2 - EXT2 and EXT4 - AT24 EEPROM support - Support for most of the SPI flashes - Support for ethernet PHYs that are usually used on mxs designs Signed-off-by: Marek Vasut Cc: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/mxs_defconfig | 63 ++++++++++++++++------------------ 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 7bf535104e26..dfd5c82e9613 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -1,5 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y @@ -8,7 +10,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_UTS_NS is not set # CONFIG_IPC_NS is not set -# CONFIG_USER_NS is not set # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_PERF_EVENTS=y @@ -24,8 +25,6 @@ CONFIG_BLK_DEV_INTEGRITY=y CONFIG_ARCH_MXS=y CONFIG_MACH_MXS_DT=y # CONFIG_ARM_THUMB is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT_VOLUNTARY=y CONFIG_AEABI=y CONFIG_AUTO_ZRELADDR=y @@ -46,25 +45,33 @@ CONFIG_SYN_COOKIES=y CONFIG_CAN=m CONFIG_CAN_RAW=m CONFIG_CAN_BCM=m -CONFIG_CAN_DEV=m CONFIG_CAN_FLEXCAN=m # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_BLK_DEV is not set CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y -CONFIG_MTD_M25P80 +CONFIG_MTD_M25P80=y +# CONFIG_M25PXX_USE_FAST_READ is not set +CONFIG_MTD_SST25L=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_GPMI_NAND=y +CONFIG_MTD_UBI=y +# CONFIG_BLK_DEV is not set +CONFIG_EEPROM_AT24=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_ENC28J60=y CONFIG_USB_USBNET=y CONFIG_USB_NET_SMSC95XX=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_SMSC_PHY=y +CONFIG_ICPLUS_PHY=y +CONFIG_REALTEK_PHY=y +CONFIG_MICREL_PHY=y # CONFIG_WLAN is not set # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_EVDEV=m @@ -91,21 +98,6 @@ CONFIG_SPI_MXS=y CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y # CONFIG_HWMON is not set -# CONFIG_MFD_SUPPORT is not set -CONFIG_DISPLAY_SUPPORT=m -# CONFIG_HID_SUPPORT is not set -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_TIMER=y -CONFIG_SND_PCM=y -CONFIG_SND_JACK=y -CONFIG_SND_DRIVERS=y -CONFIG_SND_ARM=y -CONFIG_SND_SOC=y -CONFIG_SND_MXS_SOC=y -CONFIG_SND_SOC_MXS_SGTL5000=y -CONFIG_SND_SOC_I2C_AND_SPI=y -CONFIG_SND_SOC_SGTL5000=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_FB=y @@ -117,13 +109,16 @@ CONFIG_BACKLIGHT_PWM=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FONTS=y CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_MXS_SOC=y +CONFIG_SND_SOC_MXS_SGTL5000=y CONFIG_USB=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_HOST=y CONFIG_USB_STORAGE=y CONFIG_USB_MXS_PHY=y -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y CONFIG_MMC=y CONFIG_MMC_MXS=y CONFIG_NEW_LEDS=y @@ -147,16 +142,23 @@ CONFIG_COMMON_CLK_DEBUG=y CONFIG_IIO=y CONFIG_PWM=y CONFIG_PWM_MXS=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y # CONFIG_DNOTIFY is not set CONFIG_FSCACHE=m CONFIG_FSCACHE_STATS=y CONFIG_CACHEFILES=m CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RUBIN=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y @@ -170,17 +172,12 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_UNUSED_SYMBOLS=y CONFIG_DEBUG_KERNEL=y CONFIG_LOCKUP_DETECTOR=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_TIMER_STATS=y CONFIG_PROVE_LOCKING=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y CONFIG_DEBUG_INFO=y -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_STRICT_DEVMEM=y CONFIG_DEBUG_USER=y -CONFIG_CRYPTO=y -CONFIG_CRYPTO_CRC32C=m # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_HW is not set CONFIG_CRC_ITU_T=m From 2fb318ff75d7c4d5ccc418ab4dcce19aa40fc059 Mon Sep 17 00:00:00 2001 From: Torben Hohn Date: Fri, 21 Dec 2012 15:06:15 +0100 Subject: [PATCH 129/148] ARM: mxs: use apbx bus clock to drive the timers on timrotv2 timer resolution of ~32us is pretty low. v2 has 32bits resolution, so we have quite some headroom, and can use the 24MHz clock. v1 has only 16bits, so we only increase v2. So we just exchange the timrot clock in imx28. On imx23 we have timrotv1 and everything stays the same. Signed-off-by: Torben Hohn Signed-off-by: Shawn Guo --- arch/arm/mach-mxs/timer.c | 9 +++++---- drivers/clk/mxs/clk-imx28.c | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-mxs/timer.c b/arch/arm/mach-mxs/timer.c index 27451b1ba3f1..1f8ec8cd9182 100644 --- a/arch/arm/mach-mxs/timer.c +++ b/arch/arm/mach-mxs/timer.c @@ -72,8 +72,9 @@ #define BM_TIMROT_TIMCTRLn_IRQ_EN (1 << 14) #define BM_TIMROT_TIMCTRLn_IRQ (1 << 15) #define BP_TIMROT_TIMCTRLn_SELECT 0 -#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL 0x8 -#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL 0xb +#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL 0x8 +#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL 0xb +#define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS 0xf static struct clock_event_device mxs_clockevent_device; static enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED; @@ -274,7 +275,7 @@ void __init mxs_timer_init(void) /* one for clock_event */ __raw_writel((timrot_is_v1() ? BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL : - BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL) | + BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) | BM_TIMROT_TIMCTRLn_UPDATE | BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base + HW_TIMROT_TIMCTRLn(0)); @@ -282,7 +283,7 @@ void __init mxs_timer_init(void) /* another for clocksource */ __raw_writel((timrot_is_v1() ? BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL : - BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL) | + BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) | BM_TIMROT_TIMCTRLn_RELOAD, mxs_timrot_base + HW_TIMROT_TIMCTRLn(1)); diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index db3af0874121..0174270abfe7 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -238,7 +238,7 @@ int __init mx28_clocks_init(void) of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); } - clk_register_clkdev(clks[clk32k], NULL, "timrot"); + clk_register_clkdev(clks[xbus], NULL, "timrot"); clk_register_clkdev(clks[enet_out], NULL, "enet_out"); for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) From 93044fa1527518cfba022b62d2c4b407891d1ff7 Mon Sep 17 00:00:00 2001 From: Torben Hohn Date: Fri, 21 Dec 2012 15:06:16 +0100 Subject: [PATCH 130/148] ARM: mxs: decrease mxs_clockevent_device.min_delta_ns to 2 clock cycles Signed-off-by: Torben Hohn Signed-off-by: Shawn Guo --- arch/arm/mach-mxs/timer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-mxs/timer.c b/arch/arm/mach-mxs/timer.c index 1f8ec8cd9182..421020498a1b 100644 --- a/arch/arm/mach-mxs/timer.c +++ b/arch/arm/mach-mxs/timer.c @@ -207,7 +207,8 @@ static int __init mxs_clockevent_init(struct clk *timer_clk) mxs_clockevent_device.set_next_event = timrotv1_set_next_event; mxs_clockevent_device.cpumask = cpumask_of(0); clockevents_config_and_register(&mxs_clockevent_device, - clk_get_rate(timer_clk), 0xf, + clk_get_rate(timer_clk), + timrot_is_v1() ? 0xf : 0x2, timrot_is_v1() ? 0xfffe : 0xfffffffe); return 0; From e1ab0056df613662929290f385590da2cccb8c19 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 16 Jan 2013 23:32:04 -0200 Subject: [PATCH 131/148] ARM: mxs_defconfig: Select CONFIG_DEVTMPFS_MOUNT Newer versions of udev (such as 182) requires CONFIG_DEVTMPFS_MOUNT to be selected, otherwise we get a stuck console: Starting udev Starting Bootlog daemon: bootlogd: cannot deduce real console device Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/mxs_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index dfd5c82e9613..fbbc5bb022d5 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -48,6 +48,7 @@ CONFIG_CAN_BCM=m CONFIG_CAN_FLEXCAN=m # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y From 58079fa7d54a0929d304054ee759187a2ccd3cdf Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 5 Feb 2013 12:24:59 +0900 Subject: [PATCH 132/148] ARM: shmobile: r8a7779: Correct TMU clock support During code review it was noticed that the clock value for TMU01 was incorrect and the value for TMU02 was missing. For reference: As of 3.8-rc6 there are no in-tree consumes of these clocks. Reported-by: Denis Oliver Kropp Reviewed-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7779.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index c019609da660..202370de32f0 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -161,7 +161,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("ehci-platform.0", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */ CLKDEV_DEV_ID("ohci-platform.0", &mstp_clks[MSTP100]), /* USB OHCI port0/1 */ CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP016]), /* TMU00 */ - CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP016]), /* TMU01 */ + CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP015]), /* TMU01 */ + CLKDEV_DEV_ID("sh_tmu.2", &mstp_clks[MSTP014]), /* TMU02 */ CLKDEV_DEV_ID("i2c-rcar.0", &mstp_clks[MSTP030]), /* I2C0 */ CLKDEV_DEV_ID("i2c-rcar.1", &mstp_clks[MSTP029]), /* I2C1 */ CLKDEV_DEV_ID("i2c-rcar.2", &mstp_clks[MSTP028]), /* I2C2 */ From ef4acb75a019783fc5132a5066232ef80209d7ec Mon Sep 17 00:00:00 2001 From: Barry Song Date: Mon, 4 Feb 2013 13:41:36 +0800 Subject: [PATCH 133/148] ARM: MARCO: fix the build issue due to gic-vic-to-irqchip move Fix the issue: tree: git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git next/soc head: 6ed05a2aab3763b58922247543d7079106b254dc commit: af70fdc947dbe835acc26c6ee9e8e930f38935f8 [4/8] Merge branch 'marco-timer-cleanup-rebase' of git://gitorious.org/sirfprima2-kernel/sirfprima2-kernel into next/soc config: make ARCH=arm prima2_defconfig All error/warnings: >> arch/arm/mach-prima2/platsmp.c:20:30: fatal error: asm/hardware/gic.h: No such file or directory compilation terminated. -- >> arch/arm/mach-prima2/common.c:15:30: fatal error: asm/hardware/gic.h: No such file or directory compilation terminated. Signed-off-by: Barry Song Cc: Xie ChanglongX Signed-off-by: Olof Johansson --- arch/arm/mach-prima2/common.c | 16 ++-------------- arch/arm/mach-prima2/platsmp.c | 8 +------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c index 00a65649a7e2..2d57aa479a7b 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c @@ -8,11 +8,10 @@ #include #include -#include +#include #include #include #include -#include #include #include #include "common.h" @@ -61,16 +60,6 @@ MACHINE_END #endif #ifdef CONFIG_ARCH_MARCO -static const struct of_device_id marco_irq_match[] __initconst = { - { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, - { /* sentinel */ } -}; - -static void __init marco_init_irq(void) -{ - of_irq_init(marco_irq_match); -} - static const char *marco_dt_match[] __initdata = { "sirf,marco", NULL @@ -80,9 +69,8 @@ DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)") /* Maintainer: Barry Song */ .smp = smp_ops(sirfsoc_smp_ops), .map_io = sirfsoc_map_io, - .init_irq = marco_init_irq, + .init_irq = irqchip_init, .init_time = sirfsoc_marco_timer_init, - .handle_irq = gic_handle_irq, .init_machine = sirfsoc_mach_init, .init_late = sirfsoc_init_late, .dt_compat = marco_dt_match, diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c index 2395022bc733..4b788310f6a6 100644 --- a/arch/arm/mach-prima2/platsmp.c +++ b/arch/arm/mach-prima2/platsmp.c @@ -11,13 +11,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include "common.h" @@ -142,18 +142,12 @@ static int __cpuinit sirfsoc_boot_secondary(unsigned int cpu, struct task_struct return pen_release != -1 ? -ENOSYS : 0; } -static void __init sirfsoc_smp_init_cpus(void) -{ - set_smp_cross_call(gic_raise_softirq); -} - static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus) { scu_enable(scu_base); } struct smp_operations sirfsoc_smp_ops __initdata = { - .smp_init_cpus = sirfsoc_smp_init_cpus, .smp_prepare_cpus = sirfsoc_smp_prepare_cpus, .smp_secondary_init = sirfsoc_secondary_init, .smp_boot_secondary = sirfsoc_boot_secondary, From dbe1c3defb3844772634446492ea6c13882596ec Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 5 Feb 2013 16:30:49 +0900 Subject: [PATCH 134/148] ARM: shmobile: Register ARM architected timer Register ARM architected timer by default for all mach-shmobile systems using late timer. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/timer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index fdbe54a11555..3d16d4dff01b 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -20,6 +20,7 @@ */ #include #include +#include #include #include @@ -62,4 +63,6 @@ void __init shmobile_earlytimer_init(void) void __init shmobile_timer_init(void) { + arch_timer_of_register(); + arch_timer_sched_clock_init(); } From f7c66dc0bf0f4ecd349c79315c87841c67e27aef Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 5 Feb 2013 13:12:59 -0800 Subject: [PATCH 135/148] ARM: tegra: remove empty tegra_smp_init_cpus() Based on two separate cleanup branches, it's now empty and can be removed. Signed-off-by: Olof Johansson Cc: Stephen Warren --- arch/arm/mach-tegra/platsmp.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index f06fc51cc27a..2c6b3d55213b 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -176,10 +176,6 @@ done: return status; } -static void __init tegra_smp_init_cpus(void) -{ -} - static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) { /* Always mark the boot CPU (CPU0) as initialized. */ @@ -190,7 +186,6 @@ static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) } struct smp_operations tegra_smp_ops __initdata = { - .smp_init_cpus = tegra_smp_init_cpus, .smp_prepare_cpus = tegra_smp_prepare_cpus, .smp_secondary_init = tegra_secondary_init, .smp_boot_secondary = tegra_boot_secondary, From 7e61114963233c0863fca12ad9c25711251759dd Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Mon, 4 Feb 2013 13:08:18 +0200 Subject: [PATCH 136/148] ARM: tegra: Fix build error for gic update Fix build error in board-dt-tegra114.c(next-20130204) Signed-off-by: Hiroshi Doyu Reported-by: Sami Liedes Signed-off-by: Olof Johansson --- arch/arm/mach-tegra/board-dt-tegra114.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra114.c b/arch/arm/mach-tegra/board-dt-tegra114.c index 3ed17ce884df..72598e298667 100644 --- a/arch/arm/mach-tegra/board-dt-tegra114.c +++ b/arch/arm/mach-tegra/board-dt-tegra114.c @@ -19,7 +19,6 @@ #include #include -#include #include "board.h" #include "common.h" @@ -39,7 +38,6 @@ DT_MACHINE_START(TEGRA114_DT, "NVIDIA Tegra114 (Flattened Device Tree)") .map_io = tegra_map_common_io, .init_early = tegra30_init_early, .init_irq = tegra_dt_init_irq, - .handle_irq = gic_handle_irq, .init_time = clocksource_of_init, .init_machine = tegra114_dt_init, .init_late = tegra_init_late, From d2ffb918f74bf6f596209491babde9df0c7fb4b8 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 9 Feb 2013 17:45:28 -0800 Subject: [PATCH 137/148] ARM: tegra: Fix build error w/ ARCH_TEGRA_114_SOC w/o ARCH_TEGRA_3x_SOC This patch fixes the build error when ARCH_TEGRA_114_SOC is enabled and ARCH_TEGRA_3x_SOC is disabled. This provides Tegra114 with its own tegra114_init_early() instead of making use of tegra30_init_early() so that T114 build doesn't depend on T3x anymore. Signed-off-by: Hiroshi Doyu Acked-by: Stephen Warren Signed-off-by: Olof Johansson --- arch/arm/mach-tegra/board-dt-tegra114.c | 2 +- arch/arm/mach-tegra/board.h | 2 ++ arch/arm/mach-tegra/common.c | 33 ++++++++++++++++--------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-tegra/board-dt-tegra114.c b/arch/arm/mach-tegra/board-dt-tegra114.c index 3ed17ce884df..b920df1b69fa 100644 --- a/arch/arm/mach-tegra/board-dt-tegra114.c +++ b/arch/arm/mach-tegra/board-dt-tegra114.c @@ -37,7 +37,7 @@ static const char * const tegra114_dt_board_compat[] = { DT_MACHINE_START(TEGRA114_DT, "NVIDIA Tegra114 (Flattened Device Tree)") .smp = smp_ops(tegra_smp_ops), .map_io = tegra_map_common_io, - .init_early = tegra30_init_early, + .init_early = tegra114_init_early, .init_irq = tegra_dt_init_irq, .handle_irq = gic_handle_irq, .init_time = clocksource_of_init, diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index da8f5a3c4240..86851c81a350 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -1,6 +1,7 @@ /* * arch/arm/mach-tegra/board.h * + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. * Copyright (C) 2010 Google, Inc. * * Author: @@ -27,6 +28,7 @@ void tegra_assert_system_reset(char mode, const char *cmd); void __init tegra20_init_early(void); void __init tegra30_init_early(void); +void __init tegra114_init_early(void); void __init tegra_map_common_io(void); void __init tegra_init_irq(void); void __init tegra_dt_init_irq(void); diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 2f1351359a35..427045b9dfb1 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -1,6 +1,7 @@ /* * arch/arm/mach-tegra/common.c * + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. * Copyright (C) 2010 Google, Inc. * * Author: @@ -100,31 +101,39 @@ static void __init tegra_init_cache(void) } +static void __init tegra_init_early(void) +{ + tegra_cpu_reset_handler_init(); + tegra_apb_io_init(); + tegra_init_fuse(); + tegra_init_cache(); + tegra_pmc_init(); + tegra_powergate_init(); +} + #ifdef CONFIG_ARCH_TEGRA_2x_SOC void __init tegra20_init_early(void) { - tegra_cpu_reset_handler_init(); - tegra_apb_io_init(); - tegra_init_fuse(); - tegra_init_cache(); - tegra_pmc_init(); - tegra_powergate_init(); + tegra_init_early(); tegra20_hotplug_init(); } #endif + #ifdef CONFIG_ARCH_TEGRA_3x_SOC void __init tegra30_init_early(void) { - tegra_cpu_reset_handler_init(); - tegra_apb_io_init(); - tegra_init_fuse(); - tegra_init_cache(); - tegra_pmc_init(); - tegra_powergate_init(); + tegra_init_early(); tegra30_hotplug_init(); } #endif +#ifdef CONFIG_ARCH_TEGRA_114_SOC +void __init tegra114_init_early(void) +{ + tegra_init_early(); +} +#endif + void __init tegra_init_late(void) { tegra_powergate_debugfs_init(); From 23c8c4b4e0ae21852e366206aa4981380b863799 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 7 Feb 2013 14:43:23 -0700 Subject: [PATCH 138/148] ARM: tegra: enable ARCH_REQUIRE_GPIOLIB for Tegra114 CONFIG_ARCH_TEGRA_114_SOC doesn't currently enable gpiolib, which causes numerous build problems building a Tegra kernel with only Tegra114 enabled, and not Tegra20 or Tegra30. Enable ARCH_REQUIRE_GPIOLIB to solve this. However, all Tegra will use gpiolib, so select this option from ARCH_TEGRA rather than each individual ARCH_TEGRA_*_SOC, to prevent this problem for any future chips. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson --- arch/arm/Kconfig | 1 + arch/arm/mach-tegra/Kconfig | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index eb9fc2f8acf1..25541a1971aa 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -640,6 +640,7 @@ config ARCH_LPC32XX config ARCH_TEGRA bool "NVIDIA Tegra" select ARCH_HAS_CPUFREQ + select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP select CLKSRC_MMIO select CLKSRC_OF diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index bde8197c8db8..86543241f5bb 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -5,7 +5,6 @@ comment "NVIDIA Tegra options" config ARCH_TEGRA_2x_SOC bool "Enable support for Tegra20 family" select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP - select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_720789 select ARM_ERRATA_742230 if SMP select ARM_ERRATA_751472 @@ -27,7 +26,6 @@ config ARCH_TEGRA_2x_SOC config ARCH_TEGRA_3x_SOC bool "Enable support for Tegra30 family" - select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_743622 select ARM_ERRATA_751472 select ARM_ERRATA_754322 From 1d7e5c2c815dda6eb7a0e41a6b27ea61cd927f99 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 7 Feb 2013 14:43:24 -0700 Subject: [PATCH 139/148] ARM: tegra: sort Kconfig selects for Tegra114 The Kconfig options selected by ARCH_TEGRA_*_SOC were recently sorted. Update the newly added ARCH_TEGRA_114_SOC's select statements to match. Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson --- arch/arm/mach-tegra/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 86543241f5bb..d1c4893894ce 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -45,10 +45,10 @@ config ARCH_TEGRA_3x_SOC config ARCH_TEGRA_114_SOC bool "Enable support for Tegra114 family" - select ARM_GIC - select CPU_V7 - select ARM_L1_CACHE_SHIFT_6 select ARM_ARCH_TIMER + select ARM_GIC + select ARM_L1_CACHE_SHIFT_6 + select CPU_V7 select PINCTRL select PINCTRL_TEGRA114 help From c2ad284412e495318d3b6a338ffdbbe42a594b97 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 11 Feb 2013 17:30:30 -0600 Subject: [PATCH 140/148] arm: socfpga: Add new device tree source for actual socfpga HW Up to this point, support for socfpga has only been on a virtual platform. Now that actual hardware is available, we add the appropriate device tree source files. Signed-off-by: Dinh Nguyen Tested-by: Pavel Machek Reviewed-by: Pavel Machek Cc: Russell King Cc: Arnd Bergmann Cc: Olof Johansson Signed-off-by: Olof Johansson --- arch/arm/boot/dts/socfpga.dtsi | 22 +++++----- arch/arm/boot/dts/socfpga_cyclone5.dts | 30 ++++++++++++- arch/arm/boot/dts/socfpga_vt.dts | 60 ++++++++++++++++++++++++++ arch/arm/mach-socfpga/socfpga.c | 1 - 4 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 arch/arm/boot/dts/socfpga_vt.dts diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 19aec421bb26..936d2306e7e1 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -25,6 +25,10 @@ ethernet0 = &gmac0; serial0 = &uart0; serial1 = &uart1; + timer0 = &timer0; + timer1 = &timer1; + timer2 = &timer2; + timer3 = &timer3; }; cpus { @@ -98,47 +102,41 @@ interrupts = <1 13 0xf04>; }; - timer0: timer@ffc08000 { + timer0: timer0@ffc08000 { compatible = "snps,dw-apb-timer-sp"; interrupts = <0 167 4>; - clock-frequency = <200000000>; reg = <0xffc08000 0x1000>; }; - timer1: timer@ffc09000 { + timer1: timer1@ffc09000 { compatible = "snps,dw-apb-timer-sp"; interrupts = <0 168 4>; - clock-frequency = <200000000>; reg = <0xffc09000 0x1000>; }; - timer2: timer@ffd00000 { + timer2: timer2@ffd00000 { compatible = "snps,dw-apb-timer-osc"; interrupts = <0 169 4>; - clock-frequency = <200000000>; reg = <0xffd00000 0x1000>; }; - timer3: timer@ffd01000 { + timer3: timer3@ffd01000 { compatible = "snps,dw-apb-timer-osc"; interrupts = <0 170 4>; - clock-frequency = <200000000>; reg = <0xffd01000 0x1000>; }; - uart0: uart@ffc02000 { + uart0: serial0@ffc02000 { compatible = "snps,dw-apb-uart"; reg = <0xffc02000 0x1000>; - clock-frequency = <7372800>; interrupts = <0 162 4>; reg-shift = <2>; reg-io-width = <4>; }; - uart1: uart@ffc03000 { + uart1: serial1@ffc03000 { compatible = "snps,dw-apb-uart"; reg = <0xffc03000 0x1000>; - clock-frequency = <7372800>; interrupts = <0 163 4>; reg-shift = <2>; reg-io-width = <4>; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts index ab7e4a94299f..7ad3cc69df5a 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5.dts @@ -20,7 +20,7 @@ / { model = "Altera SOCFPGA Cyclone V"; - compatible = "altr,socfpga-cyclone5"; + compatible = "altr,socfpga-cyclone5", "altr,socfpga"; chosen { bootargs = "console=ttyS0,57600"; @@ -29,6 +29,32 @@ memory { name = "memory"; device_type = "memory"; - reg = <0x0 0x10000000>; /* 256MB */ + reg = <0x0 0x40000000>; /* 1GB */ + }; + + soc { + timer0@ffc08000 { + clock-frequency = <100000000>; + }; + + timer1@ffc09000 { + clock-frequency = <100000000>; + }; + + timer2@ffd00000 { + clock-frequency = <25000000>; + }; + + timer3@ffd01000 { + clock-frequency = <25000000>; + }; + + serial0@ffc02000 { + clock-frequency = <100000000>; + }; + + serial1@ffc03000 { + clock-frequency = <100000000>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts new file mode 100644 index 000000000000..a0c6c651850f --- /dev/null +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/dts-v1/; +/include/ "socfpga.dtsi" + +/ { + model = "Altera SOCFPGA VT"; + compatible = "altr,socfpga-vt", "altr,socfpga"; + + chosen { + bootargs = "console=ttyS0,57600"; + }; + + memory { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1 GB */ + }; + + soc { + timer0@ffc08000 { + clock-frequency = <7000000>; + }; + + timer1@ffc09000 { + clock-frequency = <7000000>; + }; + + timer2@ffd00000 { + clock-frequency = <7000000>; + }; + + timer3@ffd01000 { + clock-frequency = <7000000>; + }; + + serial0@ffc02000 { + clock-frequency = <7372800>; + }; + + serial1@ffc03000 { + clock-frequency = <7372800>; + }; + }; +}; diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c index 6732924a5fee..94aa6add6443 100644 --- a/arch/arm/mach-socfpga/socfpga.c +++ b/arch/arm/mach-socfpga/socfpga.c @@ -98,7 +98,6 @@ static void __init socfpga_cyclone5_init(void) static const char *altera_dt_match[] = { "altr,socfpga", - "altr,socfpga-cyclone5", NULL }; From 90c294557d411100d3557bc2762a98a93f989430 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 11 Feb 2013 17:30:31 -0600 Subject: [PATCH 141/148] arm: socfpga: Add entries to enable make dtbs socfpga Signed-off-by: Dinh Nguyen Tested-by: Pavel Machek Reviewed-by: Pavel Machek Cc: Russell King Cc: Arnd Bergmann Cc: Olof Johansson Cc: Pavel Machek Signed-off-by: Olof Johansson --- arch/arm/boot/dts/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 5ebb44fe826a..1b8276c14023 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -124,6 +124,8 @@ dtb-$(CONFIG_ARCH_SHMOBILE) += emev2-kzm9d.dtb \ r8a7740-armadillo800eva.dtb \ sh73a0-kzm9g.dtb \ sh7372-mackerel.dtb +dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_cyclone5.dtb \ + socfpga_vt.dtb dtb-$(CONFIG_ARCH_SPEAR13XX) += spear1310-evb.dtb \ spear1340-evb.dtb dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \ From c08e20d246ded319fc77616c64dcbf69456cb4be Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 11 Feb 2013 17:30:32 -0600 Subject: [PATCH 142/148] arm: Add v7_invalidate_l1 to cache-v7.S mach-socfpga is another platform that needs to use v7_invalidate_l1 to bringup additional cores. There was a comment that the ideal place for v7_invalidate_l1 should be in arm/mm/cache-v7.S Signed-off-by: Dinh Nguyen Acked-by: Simon Horman Acked-by: Stephen Warren Reviewed-by: Pavel Machek Reviewed-by: Santosh Shilimkar Tested-by: Pavel Machek Tested-by: Stephen Warren Cc: Arnd Bergmann Cc: Russell King Cc: Olof Johansson Cc: Thomas Gleixner Cc: Rob Herring Cc: Sascha Hauer Cc: Magnus Damm Signed-off-by: Olof Johansson --- arch/arm/mach-imx/headsmp.S | 47 ------------------------------- arch/arm/mach-shmobile/headsmp.S | 48 -------------------------------- arch/arm/mach-tegra/headsmp.S | 43 ---------------------------- arch/arm/mm/cache-v7.S | 46 ++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 138 deletions(-) diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S index 7e49deb128a4..921fc1555854 100644 --- a/arch/arm/mach-imx/headsmp.S +++ b/arch/arm/mach-imx/headsmp.S @@ -17,53 +17,6 @@ .section ".text.head", "ax" -/* - * The secondary kernel init calls v7_flush_dcache_all before it enables - * the L1; however, the L1 comes out of reset in an undefined state, so - * the clean + invalidate performed by v7_flush_dcache_all causes a bunch - * of cache lines with uninitialized data and uninitialized tags to get - * written out to memory, which does really unpleasant things to the main - * processor. We fix this by performing an invalidate, rather than a - * clean + invalidate, before jumping into the kernel. - * - * This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs - * to be called for both secondary cores startup and primary core resume - * procedures. Ideally, it should be moved into arch/arm/mm/cache-v7.S. - */ -ENTRY(v7_invalidate_l1) - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache - mcr p15, 2, r0, c0, c0, 0 - mrc p15, 1, r0, c0, c0, 0 - - ldr r1, =0x7fff - and r2, r1, r0, lsr #13 - - ldr r1, =0x3ff - - and r3, r1, r0, lsr #3 @ NumWays - 1 - add r2, r2, #1 @ NumSets - - and r0, r0, #0x7 - add r0, r0, #4 @ SetShift - - clz r1, r3 @ WayShift - add r4, r3, #1 @ NumWays -1: sub r2, r2, #1 @ NumSets-- - mov r3, r4 @ Temp = NumWays -2: subs r3, r3, #1 @ Temp-- - mov r5, r3, lsl r1 - mov r6, r2, lsl r0 - orr r5, r5, r6 @ Reg = (Temp< Date: Mon, 11 Feb 2013 17:30:33 -0600 Subject: [PATCH 143/148] arm: socfpga: Add SMP support for actual socfpga harware Because the CPU1 start address is different for socfpga-vt and socfpga-cyclone5, we add code to use the correct CPU1 start addr. Signed-off-by: Dinh Nguyen Signed-off-by: Pavel Machek Cc: Russell King Cc: Arnd Bergmann Cc: Olof Johansson Cc: Rob Herring Cc: Grant Likely Signed-off-by: Olof Johansson --- .../bindings/arm/altera/socfpga-system.txt | 2 ++ arch/arm/boot/dts/socfpga_cyclone5.dts | 4 ++++ arch/arm/boot/dts/socfpga_vt.dts | 4 ++++ arch/arm/mach-socfpga/core.h | 4 +++- arch/arm/mach-socfpga/headsmp.S | 16 ++++++++++++---- arch/arm/mach-socfpga/platsmp.c | 17 ++++++++++------- arch/arm/mach-socfpga/socfpga.c | 6 ++++++ 7 files changed, 41 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt index 07c65e3cdcbe..f4d04a067282 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt @@ -3,9 +3,11 @@ Altera SOCFPGA System Manager Required properties: - compatible : "altr,sys-mgr" - reg : Should contain 1 register ranges(address and length) +- cpu1-start-addr : CPU1 start address in hex. Example: sysmgr@ffd08000 { compatible = "altr,sys-mgr"; reg = <0xffd08000 0x1000>; + cpu1-start-addr = <0xffd080c4>; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts index 7ad3cc69df5a..3ae8a83a0875 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5.dts @@ -56,5 +56,9 @@ serial1@ffc03000 { clock-frequency = <100000000>; }; + + sysmgr@ffd08000 { + cpu1-start-addr = <0xffd080c4>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index a0c6c651850f..1036eba40bbf 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -56,5 +56,9 @@ serial1@ffc03000 { clock-frequency = <7372800>; }; + + sysmgr@ffd08000 { + cpu1-start-addr = <0xffd08010>; + }; }; }; diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h index 9941caa94931..315edff610f2 100644 --- a/arch/arm/mach-socfpga/core.h +++ b/arch/arm/mach-socfpga/core.h @@ -20,7 +20,7 @@ #ifndef __MACH_CORE_H #define __MACH_CORE_H -extern void secondary_startup(void); +extern void socfpga_secondary_startup(void); extern void __iomem *socfpga_scu_base_addr; extern void socfpga_init_clocks(void); @@ -29,6 +29,8 @@ extern void socfpga_sysmgr_init(void); extern struct smp_operations socfpga_smp_ops; extern char secondary_trampoline, secondary_trampoline_end; +extern unsigned long cpu1start_addr; + #define SOCFPGA_SCU_VIRT_BASE 0xfffec000 #endif diff --git a/arch/arm/mach-socfpga/headsmp.S b/arch/arm/mach-socfpga/headsmp.S index f09b1283ffca..9004bfb1756e 100644 --- a/arch/arm/mach-socfpga/headsmp.S +++ b/arch/arm/mach-socfpga/headsmp.S @@ -13,13 +13,21 @@ __CPUINIT .arch armv7-a -#define CPU1_START_ADDR 0xffd08010 - ENTRY(secondary_trampoline) - movw r0, #:lower16:CPU1_START_ADDR - movt r0, #:upper16:CPU1_START_ADDR + movw r2, #:lower16:cpu1start_addr + movt r2, #:upper16:cpu1start_addr + /* The socfpga VT cannot handle a 0xC0000000 page offset when loading + the cpu1start_addr, we bit clear it. Tested on HW and VT. */ + bic r2, r2, #0x40000000 + + ldr r0, [r2] ldr r1, [r0] bx r1 ENTRY(secondary_trampoline_end) + +ENTRY(socfpga_secondary_startup) + bl v7_invalidate_l1 + b secondary_startup +ENDPROC(socfpga_secondary_startup) diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c index 68dd1b69512a..248196809202 100644 --- a/arch/arm/mach-socfpga/platsmp.c +++ b/arch/arm/mach-socfpga/platsmp.c @@ -47,16 +47,19 @@ static int __cpuinit socfpga_boot_secondary(unsigned int cpu, struct task_struct { int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; - memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); + if (cpu1start_addr) { + memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); - __raw_writel(virt_to_phys(secondary_startup), (sys_manager_base_addr+0x10)); + __raw_writel(virt_to_phys(socfpga_secondary_startup), + (sys_manager_base_addr + (cpu1start_addr & 0x000000ff))); - flush_cache_all(); - smp_wmb(); - outer_clean_range(0, trampoline_size); + flush_cache_all(); + smp_wmb(); + outer_clean_range(0, trampoline_size); - /* This will release CPU #1 out of reset.*/ - __raw_writel(0, rst_manager_base_addr + 0x10); + /* This will release CPU #1 out of reset.*/ + __raw_writel(0, rst_manager_base_addr + 0x10); + } return 0; } diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c index 94aa6add6443..cec126679ec3 100644 --- a/arch/arm/mach-socfpga/socfpga.c +++ b/arch/arm/mach-socfpga/socfpga.c @@ -29,6 +29,7 @@ void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE)); void __iomem *sys_manager_base_addr; void __iomem *rst_manager_base_addr; +unsigned long cpu1start_addr; static struct map_desc scu_io_desc __initdata = { .virtual = SOCFPGA_SCU_VIRT_BASE, @@ -72,6 +73,11 @@ void __init socfpga_sysmgr_init(void) struct device_node *np; np = of_find_compatible_node(NULL, NULL, "altr,sys-mgr"); + + if (of_property_read_u32(np, "cpu1-start-addr", + (u32 *) &cpu1start_addr)) + pr_err("SMP: Need cpu1-start-addr in device tree.\n"); + sys_manager_base_addr = of_iomap(np, 0); np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr"); From 7f07863ec60f7d3dbeec5aff881ea074db3925ed Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 13 Feb 2013 13:12:35 +0200 Subject: [PATCH 144/148] ARM: OMAP: Consolidate OMAP USB-HS platform data (part 1/3) Let's have a single platform data structure for the OMAP's High-Speed USB host subsystem instead of having 3 separate ones i.e. one for board data, one for USB Host (UHH) module and one for USB-TLL module. This makes the code much simpler and avoids creating multiple copies of platform data. Part 1 touches platform headers Part 2 touches drivers Part 3 touches platform data Signed-off-by: Roger Quadros Reviewed-by: Felipe Balbi --- include/linux/platform_data/usb-omap.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h index ef65b67c56c3..e697c85ad3bc 100644 --- a/include/linux/platform_data/usb-omap.h +++ b/include/linux/platform_data/usb-omap.h @@ -55,13 +55,17 @@ struct ohci_hcd_omap_platform_data { }; struct usbhs_omap_platform_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; + enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; + int reset_gpio_port[OMAP3_HS_USB_PORTS]; + struct regulator *regulator[OMAP3_HS_USB_PORTS]; struct ehci_hcd_omap_platform_data *ehci_data; struct ohci_hcd_omap_platform_data *ohci_data; /* OMAP3 <= ES2.1 have a single ulpi bypass control bit */ - unsigned single_ulpi_bypass:1; + unsigned single_ulpi_bypass:1; + unsigned es2_compatibility:1; + unsigned phy_reset:1; }; /*-------------------------------------------------------------------------*/ From 42973159599086c48c58ad79b9ad0758da6bc256 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 14 Feb 2013 10:13:48 +0200 Subject: [PATCH 145/148] ARM: OMAP: Consolidate OMAP USB-HS platform data (part 3/3) Let's have a single platform data structure for the OMAP's High-Speed USB host subsystem instead of having 3 separate ones i.e. one for board data, one for USB Host (UHH) module and one for USB-TLL module. This makes the code much simpler and avoids creating multiple copies of platform data. Signed-off-by: Roger Quadros Reviewed-by: Felipe Balbi --- arch/arm/mach-omap2/board-3430sdp.c | 2 +- arch/arm/mach-omap2/board-3630sdp.c | 2 +- arch/arm/mach-omap2/board-am3517crane.c | 2 +- arch/arm/mach-omap2/board-am3517evm.c | 2 +- arch/arm/mach-omap2/board-cm-t35.c | 2 +- arch/arm/mach-omap2/board-cm-t3517.c | 2 +- arch/arm/mach-omap2/board-devkit8000.c | 2 +- arch/arm/mach-omap2/board-igep0020.c | 4 +-- arch/arm/mach-omap2/board-omap3beagle.c | 2 +- arch/arm/mach-omap2/board-omap3evm.c | 2 +- arch/arm/mach-omap2/board-omap3pandora.c | 2 +- arch/arm/mach-omap2/board-omap3stalker.c | 2 +- arch/arm/mach-omap2/board-omap3touchbook.c | 2 +- arch/arm/mach-omap2/board-omap4panda.c | 2 +- arch/arm/mach-omap2/board-overo.c | 2 +- arch/arm/mach-omap2/board-zoom.c | 2 +- arch/arm/mach-omap2/usb-host.c | 29 ++++------------------ arch/arm/mach-omap2/usb.h | 20 +-------------- 18 files changed, 23 insertions(+), 60 deletions(-) diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index bb73afc9ac17..46147c88781f 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -424,7 +424,7 @@ static void enable_board_wakeup_source(void) OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); } -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c index 050aaa771254..78b17247f1a6 100644 --- a/arch/arm/mach-omap2/board-3630sdp.c +++ b/arch/arm/mach-omap2/board-3630sdp.c @@ -53,7 +53,7 @@ static void enable_board_wakeup_source(void) OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); } -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c index 51b96a1206d1..26f19168be7a 100644 --- a/arch/arm/mach-omap2/board-am3517crane.c +++ b/arch/arm/mach-omap2/board-am3517crane.c @@ -40,7 +40,7 @@ static struct omap_board_mux board_mux[] __initdata = { }; #endif -static struct usbhs_omap_board_data usbhs_bdata __initdata = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index f81a303b87ff..c76725d21b02 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -274,7 +274,7 @@ static __init void am3517_evm_mcbsp1_init(void) omap_ctrl_writel(devconf0, OMAP2_CONTROL_DEVCONF0); } -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, #if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \ defined(CONFIG_PANEL_SHARP_LQ043T1DG01_MODULE) diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index b3102c2f4a3c..cdf1d6e70bdb 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -418,7 +418,7 @@ static struct omap2_hsmmc_info mmc[] = { {} /* Terminator */ }; -static struct usbhs_omap_board_data usbhs_bdata __initdata = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c index ebbc2adb499e..cfa9098c007b 100644 --- a/arch/arm/mach-omap2/board-cm-t3517.c +++ b/arch/arm/mach-omap2/board-cm-t3517.c @@ -166,7 +166,7 @@ static inline void cm_t3517_init_rtc(void) {} #define HSUSB2_RESET_GPIO (147) #define USB_HUB_RESET_GPIO (152) -static struct usbhs_omap_board_data cm_t3517_ehci_pdata __initdata = { +static struct usbhs_omap_platform_data cm_t3517_ehci_pdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c index 12865af25d3a..051ec0d867d5 100644 --- a/arch/arm/mach-omap2/board-devkit8000.c +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -435,7 +435,7 @@ static struct platform_device *devkit8000_devices[] __initdata = { &omap_dm9000_dev, }; -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index 0f24cb84ba5a..cfba790a29aa 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -526,7 +526,7 @@ static void __init igep_i2c_init(void) omap3_pmic_init("twl4030", &igep_twldata); } -static const struct usbhs_omap_board_data igep2_usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data igep2_usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, @@ -537,7 +537,7 @@ static const struct usbhs_omap_board_data igep2_usbhs_bdata __initconst = { .reset_gpio_port[2] = -EINVAL, }; -static const struct usbhs_omap_board_data igep3_usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data igep3_usbhs_bdata __initdata = { .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 22c483d5dfa8..1cb114e6fa71 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -430,7 +430,7 @@ static struct platform_device *omap3_beagle_devices[] __initdata = { &madc_hwmon, }; -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 3985f35aee06..7bdc8a4c0d41 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -538,7 +538,7 @@ static int __init omap3_evm_i2c_init(void) return 0; } -static struct usbhs_omap_board_data usbhs_bdata __initdata = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index a53a6683c1b8..145a6f87b71a 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -567,7 +567,7 @@ static struct platform_device *omap3pandora_devices[] __initdata = { &pandora_backlight, }; -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c index 53a6cbcf9747..278ae9546e39 100644 --- a/arch/arm/mach-omap2/board-omap3stalker.c +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -361,7 +361,7 @@ static struct platform_device *omap3_stalker_devices[] __initdata = { &keys_gpio, }; -static struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c index 263cb9cfbf37..65a285ffeb7b 100644 --- a/arch/arm/mach-omap2/board-omap3touchbook.c +++ b/arch/arm/mach-omap2/board-omap3touchbook.c @@ -309,7 +309,7 @@ static struct platform_device *omap3_touchbook_devices[] __initdata = { &keys_gpio, }; -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 769c1feee1c4..135148995dcc 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -139,7 +139,7 @@ static struct platform_device *panda_devices[] __initdata = { &btwilink_device, }; -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index c8fde3e56441..b1b0f0926318 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -457,7 +457,7 @@ static int __init overo_spi_init(void) return 0; } -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/board-zoom.c b/arch/arm/mach-omap2/board-zoom.c index d7fa31e67238..2d7a45747f40 100644 --- a/arch/arm/mach-omap2/board-zoom.c +++ b/arch/arm/mach-omap2/board-zoom.c @@ -92,7 +92,7 @@ static struct mtd_partition zoom_nand_partitions[] = { }, }; -static const struct usbhs_omap_board_data usbhs_bdata __initconst = { +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 2e44e8a22884..940aad401279 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -37,11 +37,6 @@ #define USBHS_UHH_HWMODNAME "usb_host_hs" #define USBHS_TLL_HWMODNAME "usb_tll_hs" -static struct usbhs_omap_platform_data usbhs_data; -static struct usbtll_omap_platform_data usbtll_data; -static struct ehci_hcd_omap_platform_data ehci_data; -static struct ohci_hcd_omap_platform_data ohci_data; - static struct omap_device_pm_latency omap_uhhtll_latency[] = { { .deactivate_func = omap_device_idle_hwmods, @@ -485,32 +480,18 @@ void __init setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode) } } -void __init usbhs_init(const struct usbhs_omap_board_data *pdata) +void __init usbhs_init(struct usbhs_omap_platform_data *pdata) { struct omap_hwmod *uhh_hwm, *tll_hwm; struct platform_device *pdev; int bus_id = -1; - int i; - - for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { - usbhs_data.port_mode[i] = pdata->port_mode[i]; - usbtll_data.port_mode[i] = pdata->port_mode[i]; - ohci_data.port_mode[i] = pdata->port_mode[i]; - ehci_data.port_mode[i] = pdata->port_mode[i]; - ehci_data.reset_gpio_port[i] = pdata->reset_gpio_port[i]; - ehci_data.regulator[i] = pdata->regulator[i]; - } - ehci_data.phy_reset = pdata->phy_reset; - ohci_data.es2_compatibility = pdata->es2_compatibility; - usbhs_data.ehci_data = &ehci_data; - usbhs_data.ohci_data = &ohci_data; if (cpu_is_omap34xx()) { setup_ehci_io_mux(pdata->port_mode); setup_ohci_io_mux(pdata->port_mode); if (omap_rev() <= OMAP3430_REV_ES2_1) - usbhs_data.single_ulpi_bypass = true; + pdata->single_ulpi_bypass = true; } else if (cpu_is_omap44xx()) { setup_4430ehci_io_mux(pdata->port_mode); @@ -530,7 +511,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) } pdev = omap_device_build(OMAP_USBTLL_DEVICE, bus_id, tll_hwm, - &usbtll_data, sizeof(usbtll_data), + pdata, sizeof(*pdata), omap_uhhtll_latency, ARRAY_SIZE(omap_uhhtll_latency), false); if (IS_ERR(pdev)) { @@ -540,7 +521,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) } pdev = omap_device_build(OMAP_USBHS_DEVICE, bus_id, uhh_hwm, - &usbhs_data, sizeof(usbhs_data), + pdata, sizeof(*pdata), omap_uhhtll_latency, ARRAY_SIZE(omap_uhhtll_latency), false); if (IS_ERR(pdev)) { @@ -552,7 +533,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) #else -void __init usbhs_init(const struct usbhs_omap_board_data *pdata) +void __init usbhs_init(struct usbhs_omap_platform_data *pdata) { } diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h index 9b986ead7c45..3319f5cf47a3 100644 --- a/arch/arm/mach-omap2/usb.h +++ b/arch/arm/mach-omap2/usb.h @@ -53,26 +53,8 @@ #define USBPHY_OTGSESSEND_EN (1 << 20) #define USBPHY_DATA_POLARITY (1 << 23) -struct usbhs_omap_board_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; - - /* have to be valid if phy_reset is true and portx is in phy mode */ - int reset_gpio_port[OMAP3_HS_USB_PORTS]; - - /* Set this to true for ES2.x silicon */ - unsigned es2_compatibility:1; - - unsigned phy_reset:1; - - /* - * Regulators for USB PHYs. - * Each PHY can have a separate regulator. - */ - struct regulator *regulator[OMAP3_HS_USB_PORTS]; -}; - extern void usb_musb_init(struct omap_musb_board_data *board_data); -extern void usbhs_init(const struct usbhs_omap_board_data *pdata); +extern void usbhs_init(struct usbhs_omap_platform_data *pdata); extern void am35x_musb_reset(void); extern void am35x_musb_phy_power(u8 on); From b0db321ba14daca748d5c8ca89298fdb637f9ba8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 13 Feb 2013 22:49:04 +0100 Subject: [PATCH 146/148] ARM: prima2: fix __init section for cpu hotplug The code in arch/arm/mach-prima2/headsmp.S is used for both boot time initialization and for cpu hotplug, so it must not be discarded after the initial boot is complete. This replaces the __INIT annotation with __CPUINIT, and marks the sirfsoc_cpu_die as __ref to annotate that it correctly uses the sections. Without this patch, building prima2_defconfig results in: WARNING: arch/arm/mach-prima2/built-in.o(.cpuinit.text+0x130): Section mismatch in reference from the function sirfsoc_boot_secondary() to the function .init.text:sirfsoc_secondary_startup() The function __cpuinit sirfsoc_boot_secondary() references a function __init sirfsoc_secondary_startup(). If sirfsoc_secondary_startup is only used by sirfsoc_boot_secondary then annotate sirfsoc_secondary_startup with a matching annotation. Signed-off-by: Arnd Bergmann Cc: Barry Song --- arch/arm/mach-prima2/headsmp.S | 3 ++- arch/arm/mach-prima2/hotplug.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S index 6ec19d51a271..ada82d0917ef 100644 --- a/arch/arm/mach-prima2/headsmp.S +++ b/arch/arm/mach-prima2/headsmp.S @@ -9,7 +9,8 @@ #include #include - __INIT + __CPUINIT + /* * Cold boot and hardware reset show different behaviour, * system will be always panic if we warm-reset the board diff --git a/arch/arm/mach-prima2/hotplug.c b/arch/arm/mach-prima2/hotplug.c index 97c1ee586442..f4b17cbababd 100644 --- a/arch/arm/mach-prima2/hotplug.c +++ b/arch/arm/mach-prima2/hotplug.c @@ -35,7 +35,7 @@ static inline void platform_do_lowpower(unsigned int cpu) * * Called with IRQs disabled */ -void sirfsoc_cpu_die(unsigned int cpu) +void __ref sirfsoc_cpu_die(unsigned int cpu) { platform_do_lowpower(cpu); } From f9047306fd7332d682898dd689152bb3b45a3e73 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 15 Feb 2013 22:32:02 +0900 Subject: [PATCH 147/148] ARM: shmobile: r8a7779: Correct TMU clock support again After discussion on the linux-sh mailing list and reference to the hardware documentation it appears that 'TMU00', 'TMU01' and 'TMU02' use a common clock. The sh_tmu.1 portion of this change resolves a regression introduced in 58079fa7d54a0929d304054ee759187a2ccd3cdf (ARM: shmobile: r8a7779: Correct TMU clock support) and fixes a regression introduced by that patch. That patch is queued up for v3.9. ... hub 4-0:1.0: USB hub found hub 4-0:1.0: 2 ports detected INFO: rcu_sched self-detected stall on CPUINFO: rcu_sched detected stalls on +CPUs/tasks: { 1} (detected by 2, t=279640 jiffies, g=4294967052, c=4294967051, +q=38) Task dump for CPU 1: swapper/0 R running 0 1 0 0x00000002 [] (__schedule+0x1b0/0x4c0) from [] (__loop_delay+0x4/0xc) { 1} (t=279640 jiffies g=4294967052 c=4294967052 q=37) [] (unwind_backtrace+0x0/0xf8) from [] +(rcu_check_callbacks+0x218/0x6b8) [] (rcu_check_callbacks+0x218/0x6b8) from [] +(update_process_times+0x38/0x4c) [] (update_process_times+0x38/0x4c) from [] +(tick_nohz_handler+0xb4/0x11c) [] (tick_nohz_handler+0xb4/0x11c) from [] +(twd_handler+0x34/0x44) [] (twd_handler+0x34/0x44) from [] +(handle_percpu_devid_irq+0x68/0x80) [] (handle_percpu_devid_irq+0x68/0x80) from [] +(generic_handle_irq+0x20/0x30) [] (generic_handle_irq+0x20/0x30) from [] +(handle_IRQ+0x40/0x90) [] (handle_IRQ+0x40/0x90) from [] (gic_handle_irq+0x2c/0x5c) [] (gic_handle_irq+0x2c/0x5c) from [] (__irq_svc+0x40/0x50) Exception stack(0xef03ddf8 to 0xef03de40) dde0: 000001c1 ffffffff de00: 000001d8 01bf01bf ef35ec40 ef35e800 ef35ec6c 0000002b ef35ec68 c013c560 de20: c0392994 60000113 00000000 ef03de40 c01a5d40 c013c590 20000113 ffffffff [] (__irq_svc+0x40/0x50) from [] (__loop_delay+0x4/0xc) Cc: Denis Oliver Kropp Cc: Magnus Damm Cc: Kuninori Morimoto Cc: Paul Mundt Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-r8a7779.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index 202370de32f0..1db36537255c 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -161,8 +161,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("ehci-platform.0", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */ CLKDEV_DEV_ID("ohci-platform.0", &mstp_clks[MSTP100]), /* USB OHCI port0/1 */ CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP016]), /* TMU00 */ - CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP015]), /* TMU01 */ - CLKDEV_DEV_ID("sh_tmu.2", &mstp_clks[MSTP014]), /* TMU02 */ + CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP016]), /* TMU01 */ + CLKDEV_DEV_ID("sh_tmu.2", &mstp_clks[MSTP016]), /* TMU02 */ CLKDEV_DEV_ID("i2c-rcar.0", &mstp_clks[MSTP030]), /* I2C0 */ CLKDEV_DEV_ID("i2c-rcar.1", &mstp_clks[MSTP029]), /* I2C1 */ CLKDEV_DEV_ID("i2c-rcar.2", &mstp_clks[MSTP028]), /* I2C2 */ From 9cb0d1babfcb1b4ac248c09425f7d5de1e771133 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 20 Feb 2013 18:21:58 +0100 Subject: [PATCH 148/148] ARM: prima2: remove duplicate v7_invalidate_l1 Patch c08e20d "arm: Add v7_invalidate_l1 to cache-v7.S" added a generic version of this function and removed all platform specific versions, while 4898de3 "ARM: PRIMA2: add new SiRFmarco SMP SoC infrastructures" added another one, leading to a link error. I verified that the two are identical, so we can just remove the one in mach-prima2. Signed-off-by: Arnd Bergmann --- arch/arm/mach-prima2/headsmp.S | 40 ---------------------------------- 1 file changed, 40 deletions(-) diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S index ada82d0917ef..5b8a408d8921 100644 --- a/arch/arm/mach-prima2/headsmp.S +++ b/arch/arm/mach-prima2/headsmp.S @@ -11,46 +11,6 @@ __CPUINIT -/* - * Cold boot and hardware reset show different behaviour, - * system will be always panic if we warm-reset the board - * Here we invalidate L1 of CPU1 to make sure there isn't - * uninitialized data written into memory later - */ -ENTRY(v7_invalidate_l1) - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache - mcr p15, 2, r0, c0, c0, 0 - mrc p15, 1, r0, c0, c0, 0 - - ldr r1, =0x7fff - and r2, r1, r0, lsr #13 - - ldr r1, =0x3ff - - and r3, r1, r0, lsr #3 @ NumWays - 1 - add r2, r2, #1 @ NumSets - - and r0, r0, #0x7 - add r0, r0, #4 @ SetShift - - clz r1, r3 @ WayShift - add r4, r3, #1 @ NumWays -1: sub r2, r2, #1 @ NumSets-- - mov r3, r4 @ Temp = NumWays -2: subs r3, r3, #1 @ Temp-- - mov r5, r3, lsl r1 - mov r6, r2, lsl r0 - orr r5, r5, r6 @ Reg = (Temp<