diff options
255 files changed, 11510 insertions, 9681 deletions
diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt index 07c65e3cdcb..f4d04a06728 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/Documentation/devicetree/bindings/arm/sirf.txt b/Documentation/devicetree/bindings/arm/sirf.txt index 1881e1c6dda..c6ba6d3c747 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/Documentation/devicetree/bindings/arm/vt8500.txt b/Documentation/devicetree/bindings/arm/vt8500.txt index d657832c681..87dc1ddf477 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/Documentation/devicetree/bindings/clock/imx31-clock.txt b/Documentation/devicetree/bindings/clock/imx31-clock.txt new file mode 100644 index 00000000000..19df842c694 --- /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/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt new file mode 100644 index 00000000000..0921fac7352 --- /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/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt new file mode 100644 index 00000000000..f3da3be5fca --- /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/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index e9b005dc762..34c95288327 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. @@ -27,3 +28,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/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt new file mode 100644 index 00000000000..6bdaba2f0aa --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -0,0 +1,17 @@ +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". + +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 +    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/Kconfig b/arch/arm/Kconfig index bfd7c69c85a..2c370c869be 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -393,6 +393,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 @@ -640,6 +641,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/Kconfig.debug b/arch/arm/Kconfig.debug index 5f0cdf28c22..acddddac7ee 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" @@ -393,6 +400,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 @@ -464,11 +485,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. @@ -557,7 +583,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 diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 5ebb44fe826..042f2111485 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 \ @@ -124,6 +125,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 \ @@ -143,7 +146,9 @@ 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 \ +	tegra114-pluto.dtb  dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \  	vexpress-v2p-ca9.dtb \  	vexpress-v2p-ca15-tc1.dtb \ @@ -151,7 +156,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/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi index eb504a6c0f4..c8a8c08b48d 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>;  		};  	}; diff --git a/arch/arm/boot/dts/imx31.dtsi b/arch/arm/boot/dts/imx31.dtsi index eef7099f3e3..454c2d17540 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/boot/dts/marco-evb.dts b/arch/arm/boot/dts/marco-evb.dts new file mode 100644 index 00000000000..5130aeacfca --- /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 00000000000..1579c3491cc --- /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>; +			}; +		}; +	}; +}; diff --git a/arch/arm/boot/dts/sh73a0-reference.dtsi b/arch/arm/boot/dts/sh73a0-reference.dtsi new file mode 100644 index 00000000000..d4bb0125b2b --- /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/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi new file mode 100644 index 00000000000..8a59465d023 --- /dev/null +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -0,0 +1,100 @@ +/* + * 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 { +		#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>; +		}; +	}; + +	gic: interrupt-controller@f0001000 { +		compatible = "arm,cortex-a9-gic"; +		#interrupt-cells = <3>; +		#address-cells = <1>; +		interrupt-controller; +		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/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 19aec421bb2..936d2306e7e 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 ab7e4a94299..3ae8a83a087 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,36 @@  	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>; +		}; + +		sysmgr@ffd08000 { +			cpu1-start-addr = <0xffd080c4>; +		};  	};  }; diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts new file mode 100644 index 00000000000..1036eba40bb --- /dev/null +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -0,0 +1,64 @@ +/* + *  Copyright (C) 2013 Altera Corporation <www.altera.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/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>; +		}; + +		sysmgr@ffd08000 { +			cpu1-start-addr = <0xffd08010>; +		}; +	}; +}; diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts new file mode 100644 index 00000000000..a30aca62658 --- /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; +	}; +}; diff --git a/arch/arm/boot/dts/tegra114-pluto.dts b/arch/arm/boot/dts/tegra114-pluto.dts new file mode 100644 index 00000000000..9bea8f57aa4 --- /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; +	}; +}; diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi new file mode 100644 index 00000000000..1dfaf2874c5 --- /dev/null +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -0,0 +1,153 @@ +/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>; +	}; + +	ahb: ahb { +		compatible = "nvidia,tegra114-ahb", "nvidia,tegra30-ahb"; +		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; +	}; + +	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>; +		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>; +	}; + +	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>; + +		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>; +	}; +}; diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index 43eb72af894..2b4169702c8 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 6a93d1404c7..11b30db63ff 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 { @@ -418,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 420459825b4..607bf0c6bf9 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 b70b4cb754c..e47cf6a58b6 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 adc47547eaa..f6c61d10fd2 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 */ diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index b8effa1cbda..2e7c83c7253 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";  		};  	}; @@ -123,6 +138,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>; @@ -142,6 +163,7 @@  			      0 117 0x04  			      0 118 0x04  			      0 119 0x04>; +		clocks = <&tegra_car 34>;  	};  	ahb { @@ -183,6 +205,7 @@  		reg = <0x70002800 0x200>;  		interrupts = <0 13 0x04>;  		nvidia,dma-request-selector = <&apbdma 2>; +		clocks = <&tegra_car 11>;  		status = "disabled";  	}; @@ -191,6 +214,7 @@  		reg = <0x70002a00 0x200>;  		interrupts = <0 3 0x04>;  		nvidia,dma-request-selector = <&apbdma 1>; +		clocks = <&tegra_car 18>;  		status = "disabled";  	}; @@ -199,6 +223,7 @@  		reg = <0x70006000 0x40>;  		reg-shift = <2>;  		interrupts = <0 36 0x04>; +		clocks = <&tegra_car 6>;  		status = "disabled";  	}; @@ -207,6 +232,7 @@  		reg = <0x70006040 0x40>;  		reg-shift = <2>;  		interrupts = <0 37 0x04>; +		clocks = <&tegra_car 96>;  		status = "disabled";  	}; @@ -215,6 +241,7 @@  		reg = <0x70006200 0x100>;  		reg-shift = <2>;  		interrupts = <0 46 0x04>; +		clocks = <&tegra_car 55>;  		status = "disabled";  	}; @@ -223,6 +250,7 @@  		reg = <0x70006300 0x100>;  		reg-shift = <2>;  		interrupts = <0 90 0x04>; +		clocks = <&tegra_car 65>;  		status = "disabled";  	}; @@ -231,6 +259,7 @@  		reg = <0x70006400 0x100>;  		reg-shift = <2>;  		interrupts = <0 91 0x04>; +		clocks = <&tegra_car 66>;  		status = "disabled";  	}; @@ -238,6 +267,7 @@  		compatible = "nvidia,tegra20-pwm";  		reg = <0x7000a000 0x100>;  		#pwm-cells = <2>; +		clocks = <&tegra_car 17>;  	};  	rtc { @@ -252,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";  	}; @@ -262,6 +294,7 @@  		nvidia,dma-request-selector = <&apbdma 11>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 43>;  		status = "disabled";  	}; @@ -271,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";  	}; @@ -280,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";  	}; @@ -289,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";  	}; @@ -299,6 +338,7 @@  		nvidia,dma-request-selector = <&apbdma 15>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 41>;  		status = "disabled";  	}; @@ -309,6 +349,7 @@  		nvidia,dma-request-selector = <&apbdma 16>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 44>;  		status = "disabled";  	}; @@ -319,6 +360,7 @@  		nvidia,dma-request-selector = <&apbdma 17>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 46>;  		status = "disabled";  	}; @@ -329,6 +371,7 @@  		nvidia,dma-request-selector = <&apbdma 18>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 68>;  		status = "disabled";  	}; @@ -357,12 +400,40 @@  		#size-cells = <0>;  	}; +	phy1: usb-phy@c5000400 { +		compatible = "nvidia,tegra20-usb-phy"; +		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 {  		compatible = "nvidia,tegra20-ehci", "usb-ehci";  		reg = <0xc5000000 0x4000>;  		interrupts = <0 20 0x04>;  		phy_type = "utmi";  		nvidia,has-legacy-mode; +		clocks = <&tegra_car 22>; +		nvidia,needs-double-reset; +		nvidia,phy = <&phy1>;  		status = "disabled";  	}; @@ -371,6 +442,8 @@  		reg = <0xc5004000 0x4000>;  		interrupts = <0 21 0x04>;  		phy_type = "ulpi"; +		clocks = <&tegra_car 58>; +		nvidia,phy = <&phy2>;  		status = "disabled";  	}; @@ -379,6 +452,8 @@  		reg = <0xc5008000 0x4000>;  		interrupts = <0 97 0x04>;  		phy_type = "utmi"; +		clocks = <&tegra_car 59>; +		nvidia,phy = <&phy3>;  		status = "disabled";  	}; @@ -386,6 +461,7 @@  		compatible = "nvidia,tegra20-sdhci";  		reg = <0xc8000000 0x200>;  		interrupts = <0 14 0x04>; +		clocks = <&tegra_car 14>;  		status = "disabled";  	}; @@ -393,6 +469,7 @@  		compatible = "nvidia,tegra20-sdhci";  		reg = <0xc8000200 0x200>;  		interrupts = <0 15 0x04>; +		clocks = <&tegra_car 9>;  		status = "disabled";  	}; @@ -400,6 +477,7 @@  		compatible = "nvidia,tegra20-sdhci";  		reg = <0xc8000400 0x200>;  		interrupts = <0 19 0x04>; +		clocks = <&tegra_car 69>;  		status = "disabled";  	}; @@ -407,9 +485,27 @@  		compatible = "nvidia,tegra20-sdhci";  		reg = <0xc8000600 0x200>;  		interrupts = <0 31 0x04>; +		clocks = <&tegra_car 15>;  		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 diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 529fdb82dfd..2de8b919d78 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";  		};  	}; @@ -125,6 +141,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>; @@ -160,6 +182,7 @@  			      0 141 0x04  			      0 142 0x04  			      0 143 0x04>; +		clocks = <&tegra_car 34>;  	};  	ahb: ahb { @@ -195,6 +218,7 @@  		reg = <0x70006000 0x40>;  		reg-shift = <2>;  		interrupts = <0 36 0x04>; +		clocks = <&tegra_car 6>;  		status = "disabled";  	}; @@ -203,6 +227,7 @@  		reg = <0x70006040 0x40>;  		reg-shift = <2>;  		interrupts = <0 37 0x04>; +		clocks = <&tegra_car 160>;  		status = "disabled";  	}; @@ -211,6 +236,7 @@  		reg = <0x70006200 0x100>;  		reg-shift = <2>;  		interrupts = <0 46 0x04>; +		clocks = <&tegra_car 55>;  		status = "disabled";  	}; @@ -219,6 +245,7 @@  		reg = <0x70006300 0x100>;  		reg-shift = <2>;  		interrupts = <0 90 0x04>; +		clocks = <&tegra_car 65>;  		status = "disabled";  	}; @@ -227,6 +254,7 @@  		reg = <0x70006400 0x100>;  		reg-shift = <2>;  		interrupts = <0 91 0x04>; +		clocks = <&tegra_car 66>;  		status = "disabled";  	}; @@ -234,6 +262,7 @@  		compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";  		reg = <0x7000a000 0x100>;  		#pwm-cells = <2>; +		clocks = <&tegra_car 17>;  	};  	rtc { @@ -248,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";  	}; @@ -257,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";  	}; @@ -266,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";  	}; @@ -275,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";  	}; @@ -284,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";  	}; @@ -294,6 +333,7 @@  		nvidia,dma-request-selector = <&apbdma 15>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 41>;  		status = "disabled";  	}; @@ -304,6 +344,7 @@  		nvidia,dma-request-selector = <&apbdma 16>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 44>;  		status = "disabled";  	}; @@ -314,6 +355,7 @@  		nvidia,dma-request-selector = <&apbdma 17>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 46>;  		status = "disabled";  	}; @@ -324,6 +366,7 @@  		nvidia,dma-request-selector = <&apbdma 18>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 68>;  		status = "disabled";  	}; @@ -334,6 +377,7 @@  		nvidia,dma-request-selector = <&apbdma 27>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 104>;  		status = "disabled";  	}; @@ -344,6 +388,7 @@  		nvidia,dma-request-selector = <&apbdma 28>;  		#address-cells = <1>;  		#size-cells = <0>; +		clocks = <&tegra_car 105>;  		status = "disabled";  	}; @@ -377,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>; @@ -386,6 +437,7 @@  			compatible = "nvidia,tegra30-i2s";  			reg = <0x70080300 0x100>;  			nvidia,ahub-cif-ids = <4 4>; +			clocks = <&tegra_car 30>;  			status = "disabled";  		}; @@ -393,6 +445,7 @@  			compatible = "nvidia,tegra30-i2s";  			reg = <0x70080400 0x100>;  			nvidia,ahub-cif-ids = <5 5>; +			clocks = <&tegra_car 11>;  			status = "disabled";  		}; @@ -400,6 +453,7 @@  			compatible = "nvidia,tegra30-i2s";  			reg = <0x70080500 0x100>;  			nvidia,ahub-cif-ids = <6 6>; +			clocks = <&tegra_car 18>;  			status = "disabled";  		}; @@ -407,6 +461,7 @@  			compatible = "nvidia,tegra30-i2s";  			reg = <0x70080600 0x100>;  			nvidia,ahub-cif-ids = <7 7>; +			clocks = <&tegra_car 101>;  			status = "disabled";  		}; @@ -414,6 +469,7 @@  			compatible = "nvidia,tegra30-i2s";  			reg = <0x70080700 0x100>;  			nvidia,ahub-cif-ids = <8 8>; +			clocks = <&tegra_car 102>;  			status = "disabled";  		};  	}; @@ -422,6 +478,7 @@  		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";  		reg = <0x78000000 0x200>;  		interrupts = <0 14 0x04>; +		clocks = <&tegra_car 14>;  		status = "disabled";  	}; @@ -429,6 +486,7 @@  		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";  		reg = <0x78000200 0x200>;  		interrupts = <0 15 0x04>; +		clocks = <&tegra_car 9>;  		status = "disabled";  	}; @@ -436,6 +494,7 @@  		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";  		reg = <0x78000400 0x200>;  		interrupts = <0 19 0x04>; +		clocks = <&tegra_car 69>;  		status = "disabled";  	}; @@ -443,9 +502,39 @@  		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";  		reg = <0x78000600 0x200>;  		interrupts = <0 31 0x04>; +		clocks = <&tegra_car 15>;  		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 diff --git a/arch/arm/boot/dts/wm8850-w70v2.dts b/arch/arm/boot/dts/wm8850-w70v2.dts new file mode 100644 index 00000000000..fcc660c8954 --- /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 <linux@prisktech.co.nz> + * + * 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 00000000000..e8cbfdc87bb --- /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 <linux@prisktech.co.nz> + * + * 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; +		}; +	}; +}; diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 6dddbf877b0..0a396678756 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 @@ -150,6 +151,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 @@ -158,6 +160,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 @@ -196,9 +199,14 @@ 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 +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 diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig index 93f3794ba5c..13482ea58b0 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/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 7bf535104e2..fbbc5bb022d 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,34 @@ 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_DEVTMPFS_MOUNT=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 +99,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 +110,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 +143,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 +173,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 diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig index 6a936c7c078..002a1ceadce 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/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h index 86dff32a073..18d16937361 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 <asm/cputype.h> + +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 *);  int scu_power_mode(void __iomem *, unsigned int); diff --git a/arch/arm/include/debug/imx-uart.h b/arch/arm/include/debug/imx-uart.h new file mode 100644 index 00000000000..91d38e38a0b --- /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 c6f294cf18f..619d8cc1ac1 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 diff --git a/arch/arm/mach-bcm2835/bcm2835.c b/arch/arm/mach-bcm2835/bcm2835.c index d615a61e902..6f5785985dd 100644 --- a/arch/arm/mach-bcm2835/bcm2835.c +++ b/arch/arm/mach-bcm2835/bcm2835.c @@ -26,11 +26,13 @@  #include <mach/bcm2835_soc.h>  #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, diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index e3742716cba..6da25eebf91 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 3b3356097bb..3a76a47df39 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 b0df578bf74..9549d53aa63 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/clock.c b/arch/arm/mach-davinci/clock.c index 34668ead53c..d458558ee84 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 46f0f1bf1a4..8694b395fc9 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/da850.c b/arch/arm/mach-davinci/da850.c index 6b9154e9f90..0c4a26ddebb 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),  }; diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 2d5502d84a2..aa402bc160c 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;  } @@ -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/clock.h b/arch/arm/mach-davinci/include/mach/clock.h index a3b04021987..3e8af6a0b64 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/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 700d311c685..1b14aea4031 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; diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 40a0027838e..0a22710493f 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 d7e210f4b55..82fdc69d572 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;  	} @@ -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) @@ -58,7 +83,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;  	} diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 240e0294c37..c4ce0906d76 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/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index e30369a58e4..30b3242a7d4 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) diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c index 16ccbd41dea..b5b65f3efaf 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, @@ -46,12 +46,15 @@ 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);  	clk[ckil] = imx_clk_fixed("ckil", 32768);  	clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MXC_CCM_MPCTL); @@ -116,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/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c index f0727e80815..74e3a34d78b 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; diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 19644f6524d..540138c4606 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 76c42004328..5a800bfcec5 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -116,9 +116,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); @@ -128,6 +130,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);  extern int imx_cpu_kill(unsigned int cpu); diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c new file mode 100644 index 00000000000..d533e2695f0 --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -0,0 +1,95 @@ +/* + * 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 <linux/clockchips.h> +#include <linux/cpuidle.h> +#include <linux/module.h> +#include <asm/cpuidle.h> +#include <asm/proc-fns.h> + +#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 = { +		/* 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/cpuidle.h b/arch/arm/mach-imx/cpuidle.h index bc932d1af37..e092d1359d9 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/gpc.c b/arch/arm/mach-imx/gpc.c index ff24920699e..a96ccc7f501 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; diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S index 7e49deb128a..921fc155585 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<<WayShift)|(NumSets<<SetShift) -	mcr	p15, 0, r5, c7, c6, 2 -	bgt	2b -	cmp	r2, #0 -	bgt	1b -	dsb -	isb -	mov	pc, lr -ENDPROC(v7_invalidate_l1) -  #ifdef CONFIG_SMP  ENTRY(v7_secondary_startup)  	bl	v7_invalidate_l1 diff --git a/arch/arm/mach-imx/imx31-dt.c b/arch/arm/mach-imx/imx31-dt.c index b5c04eece78..67de611e29a 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 const char *imx31_dt_board_compat[] __initdata = { diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 5a18e7e5c56..1786b2d1257 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -12,7 +12,6 @@  #include <linux/clk.h>  #include <linux/clkdev.h> -#include <linux/cpuidle.h>  #include <linux/delay.h>  #include <linux/export.h>  #include <linux/init.h> @@ -27,7 +26,6 @@  #include <linux/regmap.h>  #include <linux/micrel_phy.h>  #include <linux/mfd/syscon.h> -#include <asm/cpuidle.h>  #include <asm/smp_twd.h>  #include <asm/hardware/cache-l2x0.h>  #include <asm/mach/arch.h> @@ -202,17 +200,14 @@ 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); +	/* +	 * 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 b2872ec614a..7c0b03f67b0 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)  {  	/* diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index 62769df36db..fea91313678 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;  } diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile index 8d2e5a96247..d6653095a1e 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 d4af5c191c2..95cc04d14b6 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 b5ad4dff6b1..49792a0cd2d 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 @@ -667,6 +689,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 283ab611e8d..e956d0277dd 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 041653a04a9..a05563a31c9 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/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index a1c3ab6fc80..d96ad4c0997 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) diff --git a/arch/arm/mach-mxs/timer.c b/arch/arm/mach-mxs/timer.c index 27451b1ba3f..421020498a1 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; @@ -206,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; @@ -274,7 +276,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 +284,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/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c index af11dcdb7e2..a00d39107a2 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/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index e71ebdefc67..15a3914ab49 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -425,7 +425,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 33846274bb8..67447bd4564 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 07f0be24a5d..52cc2c59731 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 6f5b2a05f4b..9fb85908a61 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 231a7d825f9..10054e3c348 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -419,7 +419,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 6a9529ab95c..5e54f565a29 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 a37514ecc38..4dadb0b7b80 100644 --- a/arch/arm/mach-omap2/board-devkit8000.c +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -436,7 +436,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 3f97f30d788..c10738a067c 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -527,7 +527,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, @@ -538,7 +538,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 284500ddacd..70bc1fc808c 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -431,7 +431,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 f43763647d5..8258a78c3df 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -539,7 +539,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 07cc0884e76..2bba362148a 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -568,7 +568,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 0490acbc433..95c10b3aa67 100644 --- a/arch/arm/mach-omap2/board-omap3stalker.c +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -362,7 +362,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 91daf71190c..bcd44fbcd87 100644 --- a/arch/arm/mach-omap2/board-omap3touchbook.c +++ b/arch/arm/mach-omap2/board-omap3touchbook.c @@ -310,7 +310,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 7b152d04a60..b02c2f00609 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -140,7 +140,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 6975a8585da..1bcf39671c3 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -458,7 +458,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 d257cf1e0ab..5e4d4c9fe61 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/cclock2420_data.c b/arch/arm/mach-omap2/cclock2420_data.c index ab7e952d207..0f0a97c1fcc 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 eb3dab68d53..aed8f74ca07 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 */ diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c index a2cc046b47f..cebe2b31943 100644 --- a/arch/arm/mach-omap2/cclock44xx_data.c +++ b/arch/arm/mach-omap2/cclock44xx_data.c @@ -16,6 +16,10 @@   * 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 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 <linux/kernel.h> @@ -315,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, @@ -325,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",  }; @@ -340,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, @@ -547,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, @@ -749,10 +759,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 +780,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",  }; @@ -795,23 +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_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_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, @@ -833,177 +824,57 @@ 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 },  	{ .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_GATE(hdq1w_fck, "func_12m_fclk", &func_12m_fclk, 0x0, -		OMAP4430_CM_L4PER_HDQ1W_CLKCTRL, -		OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL); +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,  		   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, @@ -1016,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, @@ -1040,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, @@ -1064,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, @@ -1088,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", @@ -1115,37 +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_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); +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 }, @@ -1153,69 +988,22 @@ 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); - -/* 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_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); +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); -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_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,  		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 +1020,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 +1033,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); @@ -1271,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 }, @@ -1324,61 +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_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); +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; @@ -1512,18 +1244,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,106 +1494,61 @@ 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,	"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),  	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,	"sgx_clk_mux",			&sgx_clk_mux,	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,	"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,	"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,	"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,	"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), -	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,	"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,	"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), @@ -1901,9 +1576,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 +1652,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 +1682,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/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 7faf82d4e85..2da3b5ec010 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; @@ -122,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   * @@ -154,88 +152,206 @@ 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 * +/** + * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms + * @clkdm: clockdomain that we are resolving dependencies for + * @clkdm_deps: ptr to array of struct clkdm_deps to resolve   * - * 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. + * Iterates through @clkdm_deps, looking up the struct clockdomain named by + * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. + * No return value. + */ +static void _resolve_clkdm_deps(struct clockdomain *clkdm, +				struct clkdm_dep *clkdm_deps) +{ +	struct clkdm_dep *cd; + +	for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { +		if (cd->clkdm) +			continue; +		cd->clkdm = _clkdm_lookup(cd->clkdm_name); + +		WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", +		     clkdm->name, cd->clkdm_name); +	} +} + +/** + * _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)   * - * XXX autodeps are deprecated and should be removed at the earliest - * opportunity + * 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.   */ -void _clkdm_add_autodeps(struct clockdomain *clkdm) +static int _clkdm_add_wkdep(struct clockdomain *clkdm1, +			    struct clockdomain *clkdm2)  { -	struct clkdm_autodep *autodep; +	struct clkdm_dep *cd; +	int ret = 0; -	if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) -		return; +	if (!clkdm1 || !clkdm2) +		return -EINVAL; -	for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { -		if (IS_ERR(autodep->clkdm.ptr)) -			continue; +	cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); +	if (IS_ERR(cd)) +		ret = PTR_ERR(cd); -		pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", -			 clkdm->name, autodep->clkdm.ptr->name); +	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; +	} + +	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); -		clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); -		clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); +		ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);  	} + +	return ret;  } -/* - * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm - * @clkdm: struct clockdomain * +/** + * _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 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. + * 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; +	} + +	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); + +		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)   * - * XXX autodeps are deprecated and should be removed at the earliest - * opportunity + * 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.   */ -void _clkdm_del_autodeps(struct clockdomain *clkdm) +static int _clkdm_add_sleepdep(struct clockdomain *clkdm1, +			       struct clockdomain *clkdm2)  { -	struct clkdm_autodep *autodep; +	struct clkdm_dep *cd; +	int ret = 0; -	if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) -		return; +	if (!clkdm1 || !clkdm2) +		return -EINVAL; -	for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { -		if (IS_ERR(autodep->clkdm.ptr)) -			continue; +	cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); +	if (IS_ERR(cd)) +		ret = PTR_ERR(cd); -		pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", -			 clkdm->name, autodep->clkdm.ptr->name); +	if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) +		ret = -EINVAL; -		clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); -		clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); +	if (ret) { +		pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", +			 clkdm1->name, clkdm2->name); +		return ret; +	} + +	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); + +		ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);  	} + +	return ret;  }  /** - * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms - * @clkdm: clockdomain that we are resolving dependencies for - * @clkdm_deps: ptr to array of struct clkdm_deps to resolve + * _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)   * - * Iterates through @clkdm_deps, looking up the struct clockdomain named by - * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. - * No return value. + * 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 void _resolve_clkdm_deps(struct clockdomain *clkdm, -				struct clkdm_dep *clkdm_deps) +static int _clkdm_del_sleepdep(struct clockdomain *clkdm1, +			       struct clockdomain *clkdm2)  {  	struct clkdm_dep *cd; +	int ret = 0; -	for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { -		if (cd->clkdm) -			continue; -		cd->clkdm = _clkdm_lookup(cd->clkdm_name); +	if (!clkdm1 || !clkdm2) +		return -EINVAL; -		WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", -		     clkdm->name, cd->clkdm_name); +	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;  	} + +	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); + +		ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); +	} + +	return ret;  }  /* Public functions */ @@ -456,30 +572,18 @@ 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; +	int ret;  	if (!clkdm1 || !clkdm2)  		return -EINVAL;  	cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);  	if (IS_ERR(cd)) -		ret = PTR_ERR(cd); +		return 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); -	} +	pwrdm_lock(cd->clkdm->pwrdm.ptr); +	ret = _clkdm_add_wkdep(clkdm1, clkdm2); +	pwrdm_unlock(cd->clkdm->pwrdm.ptr);  	return ret;  } @@ -497,30 +601,18 @@ 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; +	int ret;  	if (!clkdm1 || !clkdm2)  		return -EINVAL;  	cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);  	if (IS_ERR(cd)) -		ret = PTR_ERR(cd); +		return 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); -	} +	pwrdm_lock(cd->clkdm->pwrdm.ptr); +	ret = _clkdm_del_wkdep(clkdm1, clkdm2); +	pwrdm_unlock(cd->clkdm->pwrdm.ptr);  	return ret;  } @@ -560,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);  } @@ -600,30 +692,18 @@ 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; +	int ret;  	if (!clkdm1 || !clkdm2)  		return -EINVAL; -	cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); +	cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);  	if (IS_ERR(cd)) -		ret = PTR_ERR(cd); +		return 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); -	} +	pwrdm_lock(cd->clkdm->pwrdm.ptr); +	ret = _clkdm_add_sleepdep(clkdm1, clkdm2); +	pwrdm_unlock(cd->clkdm->pwrdm.ptr);  	return ret;  } @@ -643,30 +723,18 @@ 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; +	int ret;  	if (!clkdm1 || !clkdm2)  		return -EINVAL; -	cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); +	cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);  	if (IS_ERR(cd)) -		ret = PTR_ERR(cd); +		return 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); -	} +	pwrdm_lock(cd->clkdm->pwrdm.ptr); +	ret = _clkdm_del_sleepdep(clkdm1, clkdm2); +	pwrdm_unlock(cd->clkdm->pwrdm.ptr);  	return ret;  } @@ -708,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);  } @@ -734,18 +802,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,26 +828,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); -	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 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 + * 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_wakeup(struct clockdomain *clkdm) +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.  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_nolock(struct clockdomain *clkdm)  {  	int ret; -	unsigned long flags;  	if (!clkdm)  		return -EINVAL; @@ -796,28 +882,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; @@ -833,11 +937,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);  }  /** @@ -847,12 +966,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; @@ -868,11 +986,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);  }  /** @@ -889,14 +1021,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;  } @@ -918,30 +1047,91 @@ 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)  { -	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  	 * 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) { -		spin_unlock_irqrestore(&clkdm->lock, flags); +	clkdm->usecount++; +	if (clkdm->usecount > 1 && autodeps) { +		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); @@ -990,36 +1180,34 @@ 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) && -	    (atomic_read(&clkdm->usecount) == 0)) +	if ((__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0)  		goto ccd_exit; -	if (atomic_read(&clkdm->usecount) == 0) { -		spin_unlock_irqrestore(&clkdm->lock, flags); +	if (clkdm->usecount == 0) { +		pwrdm_unlock(clkdm->pwrdm.ptr);  		WARN_ON(1); /* underflow */  		return -ERANGE;  	} -	if (atomic_dec_return(&clkdm->usecount) > 0) { -		spin_unlock_irqrestore(&clkdm->lock, flags); +	clkdm->usecount--; +	if (clkdm->usecount > 0) { +		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;  } @@ -1072,8 +1260,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; @@ -1086,22 +1272,23 @@ 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); +	if (clkdm->usecount == 0) { +		pwrdm_unlock(clkdm->pwrdm.ptr);  		WARN_ON(1); /* underflow */  		return -ERANGE;  	} -	if (atomic_dec_return(&clkdm->usecount) > 0) { -		spin_unlock_irqrestore(&clkdm->lock, flags); +	clkdm->usecount--; +	if (clkdm->usecount > 0) { +		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 bc42446e23a..2da37656a69 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 <linux/init.h> -#include <linux/spinlock.h>  #include "powerdomain.h"  #include "clock.h" @@ -92,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 */ @@ -137,9 +136,8 @@ 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; -	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); @@ -214,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/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index db650690e9d..6774a53a387 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;  } diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index c2086f2e86b..9061c307d91 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,8 +209,8 @@ 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); +	if (clkdm->usecount > 0) +		clkdm_add_autodeps(clkdm);  	omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,  				       clkdm->clktrctrl_mask); @@ -221,8 +221,8 @@ 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) -		_clkdm_del_autodeps(clkdm); +	if (clkdm->usecount > 0) +		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 { diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 7f9a464f01e..f0290f5566f 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/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 22590dbe8f1..80392fca86c 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -36,40 +36,66 @@  /* 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; +	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. + */  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, +		.flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE,  	},  	{  		.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,  	},  }; @@ -80,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 */ @@ -110,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; @@ -185,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; @@ -209,10 +231,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 +254,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); diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 342d69399ec..142d9c616f1 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -62,8 +62,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); @@ -97,8 +96,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); @@ -317,7 +315,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", @@ -341,7 +339,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));  } @@ -381,7 +379,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 @@ -402,7 +400,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 @@ -428,8 +426,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"); @@ -473,8 +470,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); @@ -504,7 +500,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");  } @@ -733,8 +729,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 cc75aaf6e76..ff37be1f6f9 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 5cd8d7668be..dab9fc014b9 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 231ed5f2bc8..59a4af779f4 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 40950f5af1f..7a577145b68 100644 --- a/arch/arm/mach-omap2/gpio.c +++ b/arch/arm/mach-omap2/gpio.c @@ -132,8 +132,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 7911e282489..8d70bd03c5d 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1448,7 +1448,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 f6e0e7e68f9..cbc8e3c480e 100644 --- a/arch/arm/mach-omap2/hdq1w.c +++ b/arch/arm/mach-omap2/hdq1w.c @@ -88,7 +88,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 4a964338992..2ef1f8714fc 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 bcb357e948b..ef175acaeaa 100644 --- a/arch/arm/mach-omap2/hwspinlock.c +++ b/arch/arm/mach-omap2/hwspinlock.c @@ -47,8 +47,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 8fd98576f4d..d940e53dd9f 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 1c0968db43b..5d8768075dd 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -102,7 +102,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 aafdd4ca9f4..c52d8b4a3e9 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 c20423955bf..f6daae821eb 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -42,8 +42,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-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index aac46bfdbeb..8bcb64bcdcd 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -87,37 +87,6 @@ static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 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   */  static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state) @@ -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;  } diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 361677983af..d9727218dd0 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 43b927b2e2e..8a515bb7463 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 diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index d109f06785d..381be7ac0c1 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 <linux/kernel.h> -#include <linux/export.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/err.h> @@ -93,155 +40,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)  { @@ -316,9 +116,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   * @@ -357,7 +154,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); @@ -408,6 +205,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 */ @@ -527,18 +357,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; @@ -627,18 +453,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++) { @@ -664,7 +478,6 @@ void omap_device_delete(struct omap_device *od)  		return;  	od->pdev->archdata.od = NULL; -	kfree(od->pm_lats);  	kfree(od->hwmods);  	kfree(od);  } @@ -676,9 +489,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 @@ -686,11 +496,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 }; @@ -698,8 +507,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);  }  /** @@ -709,9 +517,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 @@ -719,11 +524,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; @@ -747,7 +552,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; @@ -755,10 +560,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; @@ -775,24 +577,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)  { @@ -903,10 +687,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)  { @@ -922,14 +705,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_activate(od, IGNORE_WAKEUP_LAT); +	ret = _omap_device_enable_hwmods(od); -	od->dev_wakeup_lat = 0; -	od->_dev_wakeup_lat_limit = UINT_MAX;  	od->_state = OMAP_DEVICE_STATE_ENABLED;  	return ret; @@ -939,14 +716,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)  { @@ -962,7 +735,7 @@ 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; @@ -970,42 +743,6 @@ int omap_device_idle(struct platform_device *pdev)  }  /** - * 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   * @name: const char * name of the reset line @@ -1061,86 +798,6 @@ int omap_device_deassert_hardreset(struct platform_device *pdev,  }  /** - * 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.   * @oh_name: name of the hwmod device @@ -1174,82 +831,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 0933c599bf8..044c31d50e5 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 <linux/device.h> @@ -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/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 6e70707cbb3..a8984989dec 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -139,6 +139,8 @@  #include <linux/slab.h>  #include <linux/bootmem.h> +#include <asm/system_misc.h> +  #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 3ae852a522f..80c00e706d6 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 diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index b5efe58c0be..6a764af6c6d 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/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 624a7e84a68..7ec1083ff60 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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -2718,7 +2718,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, @@ -3155,7 +3155,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, @@ -3178,7 +3178,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, @@ -3199,7 +3199,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, @@ -3220,7 +3220,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, @@ -3241,7 +3241,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, @@ -3263,8 +3263,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, @@ -3286,7 +3285,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, @@ -3308,7 +3307,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, @@ -3330,7 +3329,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, @@ -3353,7 +3352,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, @@ -3375,7 +3374,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, @@ -3426,7 +3425,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, @@ -3454,7 +3453,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, @@ -3483,7 +3482,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, @@ -3511,7 +3510,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, @@ -3790,7 +3789,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, @@ -3811,7 +3810,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, diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index e0ac8a31d4e..1edd000a814 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 9c65eddd97c..cd6682df562 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; @@ -108,80 +106,19 @@ 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)  { +	/* 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;  }  /* - * 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_wait_transition(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   * at the nominal voltage. So this function finds out the rate of diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index c22503b17ab..7bdd22afce6 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/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index c333fa6dffa..b2a4df62354 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,15 +133,10 @@ no_sleep:  	/* Mask future PRCM-to-MPU interrupts */  	omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); -	return 0; -} - -static int omap2_i2c_active(void) -{ -	u32 l; +	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); +	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON); -	l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); -	return l & (OMAP2420_EN_I2C2_MASK | OMAP2420_EN_I2C1_MASK); +	return 0;  }  static int sti_console_enabled; @@ -172,11 +163,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()) { @@ -186,17 +172,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 +236,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); diff --git a/arch/arm/mach-omap2/pmu.c b/arch/arm/mach-omap2/pmu.c index 75052b3bc94..9debf822687 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/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index dea62a9aad0..8e61d80bf6b 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -19,6 +19,7 @@  #include <linux/list.h>  #include <linux/errno.h>  #include <linux/string.h> +#include <linux/spinlock.h>  #include <trace/events/power.h>  #include "cm2xxx_3xxx.h" @@ -42,6 +43,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); @@ -101,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); @@ -112,7 +124,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; @@ -143,7 +155,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 +176,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()); @@ -199,6 +212,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_nolock(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_nolock(pwrdm->pwrdm_clkdms[0]); +		else +			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_nolock(pwrdm); +		break; +	} +} +  /* Public functions */  /** @@ -275,6 +362,30 @@ int pwrdm_complete_init(void)  }  /** + * 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   * @@ -920,65 +1031,27 @@ 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; -} - -/** - * 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 pwrdm_state_switch_nolock(struct powerdomain *pwrdm)  { -	int ret = -EINVAL; +	int ret; -	if (!pwrdm) +	if (!pwrdm || !arch_pwrdm)  		return -EINVAL; -	if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition) -		ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); +	ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); +	if (!ret) +		ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);  	return ret;  } -int pwrdm_state_switch(struct powerdomain *pwrdm) +int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm)  {  	int ret; -	ret = pwrdm_wait_transition(pwrdm); -	if (!ret) -		ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); +	pwrdm_lock(pwrdm); +	ret = pwrdm_state_switch_nolock(pwrdm); +	pwrdm_unlock(pwrdm);  	return ret;  } @@ -1004,6 +1077,61 @@ int pwrdm_post_transition(struct powerdomain *pwrdm)  }  /** + * 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--; +	} + +	pwrdm_lock(pwrdm); + +	curr_pwrst = pwrdm_read_pwrst(pwrdm); +	next_pwrst = pwrdm_read_next_pwrst(pwrdm); +	if (curr_pwrst == pwrst && next_pwrst == pwrst) +		goto osps_out; + +	sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst, +							    pwrst, &hwsup); +	if (sleep_switch == ERROR_SWITCH) { +		ret = -EINVAL; +		goto osps_out; +	} + +	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); + +osps_out: +	pwrdm_unlock(pwrdm); + +	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 5277d56eb37..140c36074fe 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -19,8 +19,7 @@  #include <linux/types.h>  #include <linux/list.h> - -#include <linux/atomic.h> +#include <linux/spinlock.h>  #include "voltage.h" @@ -44,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 @@ -103,6 +104,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 +130,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; @@ -162,6 +166,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); @@ -225,15 +239,15 @@ 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_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); -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); @@ -253,5 +267,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 diff --git a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c index d3a5399091a..7b946f1005b 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 ba520d4f7c7..578eef86fcf 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,13 +53,14 @@ static struct powerdomain mpu_24xx_pwrdm = {  	.pwrsts_mem_on	  = {  		[0] = PWRSTS_ON,  	}, -	.voltdm           = { .name = "core" }, +	.voltdm		  = { .name = "core" },  };  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 */ @@ -71,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" },  }; @@ -93,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 8b23d234fb5..f0e14e9efe5 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 */ diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index a3e121f94a8..947f6adfed0 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, diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 24e9ad3cb99..8396b5b7e91 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 b9753fe2723..bb829e06540 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 72c2ca1e3f7..2bdd4cf17a8 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -683,8 +683,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 2e44e8a2288..5706bdccf45 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -37,19 +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, -		.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 @@ -485,32 +472,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,9 +503,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); +				pdata, sizeof(*pdata));  	if (IS_ERR(pdev)) {  		pr_err("Could not build hwmod device %s\n",  		       USBHS_TLL_HWMODNAME); @@ -540,9 +511,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); +				pdata, sizeof(*pdata));  	if (IS_ERR(pdev)) {  		pr_err("Could not build hwmod devices %s\n",  		       USBHS_UHH_HWMODNAME); @@ -552,7 +521,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-musb.c b/arch/arm/mach-omap2/usb-musb.c index 9d27e3f8a09..3242a554ad6 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -105,7 +105,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/usb.h b/arch/arm/mach-omap2/usb.h index 9b986ead7c4..3319f5cf47a 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); diff --git a/arch/arm/mach-omap2/wd_timer.c b/arch/arm/mach-omap2/wd_timer.c index 70240a54995..d15c7bbab8e 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; diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index 558ccfb8d45..4f7379fe01e 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 fc9ce22e2b5..bfe360cbd17 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,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 ed3570e5eb8..2d57aa479a7 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c @@ -8,6 +8,7 @@  #include <linux/init.h>  #include <linux/kernel.h> +#include <linux/irqchip.h>  #include <asm/sizes.h>  #include <asm/mach-types.h>  #include <asm/mach/arch.h> @@ -30,6 +31,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,9 +45,12 @@ static const char *prima2_dt_match[] __initdata = {  DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")  	/* Maintainer: Barry Song <baohua.song@csr.com> */ -	.map_io         = sirfsoc_map_lluart, +	.map_io         = sirfsoc_map_io,  	.init_irq	= sirfsoc_of_irq_init, -	.init_time	= sirfsoc_timer_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, @@ -48,3 +58,22 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")  	.restart	= sirfsoc_restart,  MACHINE_END  #endif + +#ifdef CONFIG_ARCH_MARCO +static const char *marco_dt_match[] __initdata = { +	"sirf,marco", +	NULL +}; + +DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)") +	/* Maintainer: Barry Song <baohua.song@csr.com> */ +	.smp            = smp_ops(sirfsoc_smp_ops), +	.map_io         = sirfsoc_map_io, +	.init_irq	= irqchip_init, +	.init_time	= sirfsoc_marco_timer_init, +	.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 9c75f124e3c..b7c26b62e4a 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -11,12 +11,19 @@  #include <linux/init.h>  #include <asm/mach/time.h> +#include <asm/exception.h> -extern void sirfsoc_timer_init(void); +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);  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)  {} @@ -24,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 00000000000..5b8a408d892 --- /dev/null +++ b/arch/arm/mach-prima2/headsmp.S @@ -0,0 +1,40 @@ +/* + * 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 <linux/linkage.h> +#include <linux/init.h> + +	__CPUINIT + +/* + * SIRFSOC specific entry point for secondary CPUs.  This provides + * a "holding pen" into which all secondary cores are held until we're + * ready for them to initialise. + */ +ENTRY(sirfsoc_secondary_startup) +	bl v7_invalidate_l1 +        mrc     p15, 0, r0, c0, c0, 5 +        and     r0, r0, #15 +        adr     r4, 1f +        ldmia   r4, {r5, r6} +        sub     r4, r4, r5 +        add     r6, r6, r4 +pen:    ldr     r7, [r6] +        cmp     r7, r0 +        bne     pen + +        /* +         * we've been released from the holding pen: secondary_stack +         * should now contain the SVC stack for this core +         */ +        b       secondary_startup +ENDPROC(sirfsoc_secondary_startup) + +        .align +1:      .long   . +        .long   pen_release diff --git a/arch/arm/mach-prima2/hotplug.c b/arch/arm/mach-prima2/hotplug.c new file mode 100644 index 00000000000..f4b17cbabab --- /dev/null +++ b/arch/arm/mach-prima2/hotplug.c @@ -0,0 +1,41 @@ +/* + * CPU hotplug 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 <linux/kernel.h> +#include <linux/errno.h> +#include <linux/smp.h> + +#include <asm/cacheflush.h> +#include <asm/smp_plat.h> + +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 __ref sirfsoc_cpu_die(unsigned int cpu) +{ +	platform_do_lowpower(cpu); +} diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h index f6014a07541..b778a0f248e 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/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h index c98b4d5ac24..c10510d01a4 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 f72ca26ab4f..d1513a33709 100644 --- a/arch/arm/mach-prima2/include/mach/uncompress.h +++ b/arch/arm/mach-prima2/include/mach/uncompress.h @@ -23,6 +23,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(); diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c index 7dee9176e77..6c0f3e9c43f 100644 --- a/arch/arm/mach-prima2/irq.c +++ b/arch/arm/mach-prima2/irq.c @@ -9,17 +9,19 @@  #include <linux/init.h>  #include <linux/io.h>  #include <linux/irq.h> -#include <mach/hardware.h> -#include <asm/mach/irq.h>  #include <linux/of.h>  #include <linux/of_address.h>  #include <linux/irqdomain.h>  #include <linux/syscore_ops.h> +#include <asm/mach/irq.h> +#include <asm/exception.h> +#include <mach/hardware.h>  #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" },  	{}, diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c index c99837797d7..cbcbe9cb094 100644 --- a/arch/arm/mach-prima2/l2x0.c +++ b/arch/arm/mach-prima2/l2x0.c @@ -11,19 +11,38 @@  #include <linux/of.h>  #include <asm/hardware/cache-l2x0.h> -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; diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c new file mode 100644 index 00000000000..4b788310f6a --- /dev/null +++ b/arch/arm/mach-prima2/platsmp.c @@ -0,0 +1,157 @@ +/* + * 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 <linux/init.h> +#include <linux/smp.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/irqchip/arm-gic.h> +#include <asm/page.h> +#include <asm/mach/map.h> +#include <asm/smp_plat.h> +#include <asm/smp_scu.h> +#include <asm/cacheflush.h> +#include <asm/cputype.h> +#include <mach/map.h> + +#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_prepare_cpus(unsigned int max_cpus) +{ +	scu_enable(scu_base); +} + +struct smp_operations sirfsoc_smp_ops __initdata = { +        .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/rstc.c b/arch/arm/mach-prima2/rstc.c index 762adb73ab7..435019ca0a4 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); diff --git a/arch/arm/mach-prima2/rtciobrg.c b/arch/arm/mach-prima2/rtciobrg.c index 55735360213..9f2da2eec4d 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" },  	{}  }; diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c new file mode 100644 index 00000000000..f4eea2e97eb --- /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 <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/bitops.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <asm/sched_clock.h> +#include <asm/localtimer.h> +#include <asm/mach/time.h> + +#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); +} diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer-prima2.c index a7a2c199c3e..6da584f8a94 100644 --- a/arch/arm/mach-prima2/timer.c +++ b/arch/arm/mach-prima2/timer-prima2.c @@ -181,7 +181,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; @@ -220,14 +220,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"); diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index a1e931337d4..e1fac57514b 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 @@ -30,6 +30,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-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index 6bcf3cbd922..81d91fda2d9 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/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index 5394d804a71..3efff2e7b1e 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/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c index eac49d59782..19ce885a3b4 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/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index c019609da66..1db36537255 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -162,6 +162,7 @@ static struct clk_lookup lookups[] = {  	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.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 */ diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 3ca6757b129..45d21fe317f 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 */ diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 516ff7f3e43..afa5423a0f9 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, @@ -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,17 +578,21 @@ 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 */  	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 */  	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/headsmp-sh73a0.S b/arch/arm/mach-shmobile/headsmp-sh73a0.S new file mode 100644 index 00000000000..bec4c0d9b71 --- /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 <linux/linkage.h> +#include <linux/init.h> +#include <asm/memory.h> + +	__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/headsmp.S b/arch/arm/mach-shmobile/headsmp.S index b202c127252..96001fd49b6 100644 --- a/arch/arm/mach-shmobile/headsmp.S +++ b/arch/arm/mach-shmobile/headsmp.S @@ -16,54 +16,6 @@  	__CPUINIT -/* Cache invalidation nicked from arch/arm/mach-imx/head-v7.S, thanks! - * - * 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<<WayShift)|(NumSets<<SetShift) -	mcr	p15, 0, r5, c7, c6, 2 -	bgt	2b -	cmp	r2, #0 -	bgt	1b -	dsb -	isb -	mov	pc, lr -ENDPROC(v7_invalidate_l1) -  ENTRY(shmobile_invalidate_start)  	bl	v7_invalidate_l1  	b	secondary_startup diff --git a/arch/arm/mach-shmobile/hotplug.c b/arch/arm/mach-shmobile/hotplug.c index b09a0bdbf81..a1524e3367b 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 a57439eec11..e48606d8a2b 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); @@ -32,12 +34,17 @@ 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); +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); +extern void sh73a0_secondary_vector(void);  extern struct clk sh73a0_extal1_clk;  extern struct clk sh73a0_extal2_clk;  extern struct clk sh73a0_extcki_clk; @@ -49,6 +56,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); @@ -76,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); diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index 978369973be..91faba666d4 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -23,6 +23,7 @@  #include <linux/irq.h>  #include <linux/io.h>  #include <linux/sh_intc.h> +#include <linux/irqchip.h>  #include <linux/irqchip/arm-gic.h>  #include <mach/intc.h>  #include <mach/irqs.h> @@ -315,11 +316,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 +335,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 @@ -464,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 diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index 21e5316d2d8..40b87aa1d44 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 <linux/console.h> +#include <linux/suspend.h>  #include <mach/pm-rmobile.h> +#include <mach/common.h>  #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(); +} diff --git a/arch/arm/mach-shmobile/pm-sh73a0.c b/arch/arm/mach-shmobile/pm-sh73a0.c new file mode 100644 index 00000000000..99086e98fbb --- /dev/null +++ b/arch/arm/mach-shmobile/pm-sh73a0.c @@ -0,0 +1,32 @@ +/* + * sh73a0 Power management support + * + *  Copyright (C) 2012 Bastian Hecht <hechtb+renesas@gmail.com> + * + * 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 <linux/suspend.h> +#include <mach/common.h> + +#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(); +} diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index b580979923e..30ac79c7c68 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -27,7 +27,6 @@  #include <linux/serial_sci.h>  #include <linux/sh_dma.h>  #include <linux/sh_timer.h> -#include <linux/dma-mapping.h>  #include <mach/dma-register.h>  #include <mach/r8a7740.h>  #include <mach/pm-rmobile.h> @@ -288,6 +287,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, @@ -299,6 +389,9 @@ static struct platform_device *r8a7740_early_devices[] __initdata = {  	&scif7_device,  	&scifb_device,  	&cmt10_device, +	&tmu00_device, +	&tmu01_device, +	&tmu02_device,  };  /* DMA */ diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index 344eb79658f..c54ff9b29fe 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -91,8 +91,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 = { @@ -109,8 +108,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 = { @@ -127,8 +125,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 = { @@ -145,8 +142,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 = { @@ -163,8 +159,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 = { @@ -181,8 +176,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 = { diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 48f7f583647..2ecd6681692 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -23,6 +23,7 @@  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/platform_device.h> +#include <linux/of_platform.h>  #include <linux/delay.h>  #include <linux/input.h>  #include <linux/io.h> @@ -779,7 +780,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, @@ -790,6 +791,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,  }; @@ -812,6 +816,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, @@ -830,9 +836,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 */ diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S index 1d564674451..a9df53b69ab 100644 --- a/arch/arm/mach-shmobile/sleep-sh7372.S +++ b/arch/arm/mach-shmobile/sleep-sh7372.S @@ -59,17 +59,19 @@ 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.  	 * This sequence switches back to ARM.  Note that .align may insert a diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 5c5bcb59535..acb46a94ccd 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -25,6 +25,7 @@  #include <linux/delay.h>  #include <linux/irqchip/arm-gic.h>  #include <mach/common.h> +#include <asm/cacheflush.h>  #include <asm/smp_plat.h>  #include <mach/sh73a0.h>  #include <asm/smp_scu.h> @@ -36,14 +37,13 @@  #define SBAR		IOMEM(0xe6180020)  #define APARMBAREA	IOMEM(0xe6f10020) +#define PSTR_SHUTDOWN_MODE	3 +  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 +52,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 +68,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 +78,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) @@ -114,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; +	u32 pstr; -	/* 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. +	/* +	 * 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); @@ -132,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, @@ -140,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_disable		= shmobile_cpu_disable, +	.cpu_die		= sh73a0_cpu_die, +	.cpu_disable		= shmobile_cpu_disable_any,  #endif  }; diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index fdbe54a1155..3d16d4dff01 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -20,6 +20,7 @@   */  #include <linux/platform_device.h>  #include <linux/delay.h> +#include <asm/arch_timer.h>  #include <asm/mach/time.h>  #include <asm/smp_twd.h> @@ -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();  } diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h index 9941caa9493..315edff610f 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 f09b1283ffc..9004bfb1756 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 4e9e69d9e7d..84c60fa8daa 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 27d68468a02..1042c023cf2 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, @@ -67,6 +68,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"); @@ -93,7 +99,6 @@ static void __init socfpga_cyclone5_init(void)  static const char *altera_dt_match[] = {  	"altr,socfpga", -	"altr,socfpga-cyclone5",  	NULL  }; diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 1ec7f80e2af..d1c4893894c 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -4,7 +4,7 @@ comment "NVIDIA Tegra options"  config ARCH_TEGRA_2x_SOC  	bool "Enable support for Tegra20 family" -	select ARCH_REQUIRE_GPIOLIB +	select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP  	select ARM_ERRATA_720789  	select ARM_ERRATA_742230 if SMP  	select ARM_ERRATA_751472 @@ -26,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 @@ -44,6 +43,18 @@ 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_ARCH_TIMER +	select ARM_GIC +	select ARM_L1_CACHE_SHIFT_6 +	select CPU_V7 +	select PINCTRL +	select PINCTRL_TEGRA114 +	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 f0520961baf..f6b46ae2b7f 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) @@ -34,6 +29,10 @@ 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/board-dt-tegra114.c b/arch/arm/mach-tegra/board-dt-tegra114.c new file mode 100644 index 00000000000..085d63637b6 --- /dev/null +++ b/arch/arm/mach-tegra/board-dt-tegra114.c @@ -0,0 +1,46 @@ +/* + * 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 <linux/of.h> +#include <linux/of_platform.h> +#include <linux/clocksource.h> + +#include <asm/mach/arch.h> + +#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	= tegra114_init_early, +	.init_irq	= tegra_dt_init_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/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index d320f7ad735..a0edf251028 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -40,7 +40,6 @@  #include <asm/setup.h>  #include "board.h" -#include "clock.h"  #include "common.h"  #include "iomap.h" @@ -69,70 +68,17 @@ 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", +	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), -	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),  	{}  }; -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 97e1f67fc31..bf68567e549 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -34,72 +34,12 @@  #include <asm/mach/arch.h>  #include "board.h" -#include "clock.h"  #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 __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); +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);  }  static const char *tegra30_dt_board_compat[] = { diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index da8f5a3c424..86851c81a35 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/clock.c b/arch/arm/mach-tegra/clock.c deleted file mode 100644 index 867bf8bf556..00000000000 --- a/arch/arm/mach-tegra/clock.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2012 NVIDIA CORPORATION.  All rights reserved. - * - * Author: - *	Colin Cross <ccross@google.com> - * - * 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 <linux/kernel.h> -#include <linux/clk.h> -#include <linux/clkdev.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/seq_file.h> -#include <linux/slab.h> - -#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; - -/* - * 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); -} - -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. */ -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 2aa37f5c44c..00000000000 --- 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 <ccross@google.com> - * - * 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 <linux/clk-provider.h> -#include <linux/clkdev.h> -#include <linux/list.h> - -#include <mach/clk.h> - -#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/common.c b/arch/arm/mach-tegra/common.c index 8f0ffe97ffe..5449a3f2977 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: @@ -22,13 +23,13 @@  #include <linux/clk.h>  #include <linux/delay.h>  #include <linux/irqchip.h> +#include <linux/clk/tegra.h>  #include <asm/hardware/cache-l2x0.h>  #include <mach/powergate.h>  #include "board.h" -#include "clock.h"  #include "common.h"  #include "fuse.h"  #include "iomap.h" @@ -59,6 +60,7 @@ u32 tegra_uart_config[4] = {  #ifdef CONFIG_OF  void __init tegra_dt_init_irq(void)  { +	tegra_clocks_init();  	tegra_init_irq();  	irqchip_init();  } @@ -74,43 +76,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 @@ -129,35 +94,39 @@ static void __init tegra_init_cache(void)  } -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -void __init tegra20_init_early(void) +static void __init tegra_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(); +} + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +void __init tegra20_init_early(void) +{ +	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(); -	tegra30_init_clocks(); -	tegra_clk_init_from_table(tegra30_clk_init_table); -	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(); diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index ece29ab15b5..e3d6e15ff18 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -265,7 +265,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/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c new file mode 100644 index 00000000000..0f4e8c483b3 --- /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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/cpuidle.h> + +#include <asm/cpuidle.h> + +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-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index d32e8b0dbd4..825ced4f7a4 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -22,21 +22,199 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/cpuidle.h> +#include <linux/cpu_pm.h> +#include <linux/clockchips.h> +#include <linux/clk/tegra.h>  #include <asm/cpuidle.h> +#include <asm/proc-fns.h> +#include <asm/suspend.h> +#include <asm/smp_plat.h> + +#include "pm.h" +#include "sleep.h" +#include "iomap.h" +#include "irq.h" +#include "flowctrl.h" + +#ifdef CONFIG_PM_SLEEP +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_coupled, +		.exit_latency		= 5000, +		.target_residency	= 10000, +		.power_usage		= 0, +		.flags			= CPUIDLE_FLAG_TIME_VALID | +					  CPUIDLE_FLAG_COUPLED, +		.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 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, +					 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_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) +		entered_lp2 = tegra20_cpu_cluster_power_down(dev, drv, index); +	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 +222,14 @@ 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])); +  	ret = cpuidle_register_driver(&tegra_idle_driver);  	if (ret) {  		pr_err("CPUidle driver registration failed\n"); @@ -53,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/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 82530bd9b8c..8b50cf4ddd6 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -24,6 +24,7 @@  #include <linux/cpuidle.h>  #include <linux/cpu_pm.h>  #include <linux/clockchips.h> +#include <linux/clk/tegra.h>  #include <asm/cpuidle.h>  #include <asm/proc-fns.h> @@ -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/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c index d0651397aec..4b744c4661e 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 496204d34e5..d733f75d020 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 diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c index 5393eb2cae2..b477ef310dc 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 0798dec1832..67eab56699b 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) diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 8121742711f..f7db0782a6b 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -20,6 +20,7 @@  #include <linux/kernel.h>  #include <linux/io.h>  #include <linux/export.h> +#include <linux/tegra-soc.h>  #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/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index ff1383dd61a..da78434678c 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; diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index b2834810b02..fd473f2b4c3 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S @@ -5,49 +5,6 @@          .section ".text.head", "ax" -/* - * Tegra specific entry point for secondary CPUs. - *   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. - */ -ENTRY(v7_invalidate_l1) -        mov     r0, #0 -        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<<WayShift)|(NumSets<<SetShift) -        mcr     p15, 0, r5, c7, c6, 2 -        bgt     2b -        cmp     r2, #0 -        bgt     1b -        dsb -        isb -        mov     pc, lr -ENDPROC(v7_invalidate_l1) -  ENTRY(tegra_secondary_startup)          bl      v7_invalidate_l1  	/* Enable coresight */ diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index 6a27de4001e..a599f6e36de 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -10,12 +10,12 @@   */  #include <linux/kernel.h>  #include <linux/smp.h> +#include <linux/clk/tegra.h>  #include <asm/cacheflush.h>  #include <asm/smp_plat.h>  #include "sleep.h" -#include "tegra_cpu_car.h"  static void (*tegra_hotplug_shutdown)(void); 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 95f3a547c77..00000000000 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * arch/arm/mach-tegra/include/mach/clk.h - * - * Copyright (C) 2010 Google, Inc. - * - * Author: - *	Erik Gilling <konkers@google.com> - * - * 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, -}; - -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 - -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/iomap.h b/arch/arm/mach-tegra/iomap.h index db8be51cad8..399fbca2710 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 diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 2ff2128cb9d..1952e82797c 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -44,6 +44,8 @@  #define FIRST_LEGACY_IRQ 32 +#define SGI_MASK 0xFFFF +  static int num_ictlrs;  static void __iomem *ictlr_reg_base[] = { @@ -54,6 +56,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 00000000000..5142649bba0 --- /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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __TEGRA_IRQ_H +#define __TEGRA_IRQ_H + +bool tegra_pending_sgi(void); + +#endif diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c index bffcd643d7a..b60165f1ca0 100644 --- a/arch/arm/mach-tegra/pcie.c +++ b/arch/arm/mach-tegra/pcie.c @@ -33,11 +33,11 @@  #include <linux/clk.h>  #include <linux/delay.h>  #include <linux/export.h> +#include <linux/clk/tegra.h>  #include <asm/sizes.h>  #include <asm/mach/pci.h> -#include <mach/clk.h>  #include <mach/powergate.h>  #include "board.h" diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 3c4a43c892a..2c6b3d55213 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -19,6 +19,7 @@  #include <linux/smp.h>  #include <linux/io.h>  #include <linux/irqchip/arm-gic.h> +#include <linux/clk/tegra.h>  #include <asm/cacheflush.h>  #include <asm/mach-types.h> @@ -30,7 +31,6 @@  #include "fuse.h"  #include "flowctrl.h"  #include "reset.h" -#include "tegra_cpu_car.h"  #include "common.h"  #include "iomap.h" @@ -38,7 +38,6 @@  extern void tegra_secondary_startup(void);  static cpumask_t tegra_cpu_init_mask; -static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);  #define EVP_CPU_RESET_VECTOR \  	(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) @@ -177,34 +176,16 @@ 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); -} -  static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)  {  	/* Always mark the boot CPU (CPU0) as initialized. */  	cpumask_set_cpu(0, &tegra_cpu_init_mask); -	scu_enable(scu_base); +	if (scu_a9_has_base()) +		scu_enable(IO_ADDRESS(scu_a9_get_base()));  }  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, diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 498d70b3377..523604de666 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -24,6 +24,7 @@  #include <linux/cpu_pm.h>  #include <linux/clk.h>  #include <linux/err.h> +#include <linux/clk/tegra.h>  #include <asm/smp_plat.h>  #include <asm/cacheflush.h> @@ -35,8 +36,8 @@  #include "iomap.h"  #include "reset.h"  #include "flowctrl.h" +#include "fuse.h"  #include "sleep.h" -#include "tegra_cpu_car.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/powergate.c b/arch/arm/mach-tegra/powergate.c index 2cc1185d902..c6bc8f85759 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -26,8 +26,8 @@  #include <linux/io.h>  #include <linux/seq_file.h>  #include <linux/spinlock.h> +#include <linux/clk/tegra.h> -#include <mach/clk.h>  #include <mach/powergate.h>  #include "fuse.h" diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S index ad2ca07d057..9f6bfafdd51 100644 --- a/arch/arm/mach-tegra/sleep-tegra20.S +++ b/arch/arm/mach-tegra/sleep-tegra20.S @@ -21,6 +21,8 @@  #include <linux/linkage.h>  #include <asm/assembler.h> +#include <asm/proc-fns.h> +#include <asm/cp15.h>  #include "sleep.h"  #include "flowctrl.h" @@ -55,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 @@ -75,3 +80,198 @@ 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_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) + * + * 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) + +/* + * 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 addae357da3..364d84523fb 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 56505c381ea..4ffae541726 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,17 @@ 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); +#else +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); diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c deleted file mode 100644 index 4eb6bc81a87..00000000000 --- 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 <ccross@google.com> - * - * 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 <linux/kernel.h> -#include <linux/module.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/clkdev.h> -#include <linux/clk.h> - -#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 -#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<<PLL_MISC_CPCON_SHIFT) -#define PLL_MISC_LFCON_SHIFT		4 -#define PLL_MISC_LFCON_MASK		(0xF<<PLL_MISC_LFCON_SHIFT) -#define PLL_MISC_VCOCON_SHIFT		0 -#define PLL_MISC_VCOCON_MASK		(0xF<<PLL_MISC_VCOCON_SHIFT) - -#define PLLU_BASE_POST_DIV		(1<<20) - -#define PLLD_MISC_CLKENABLE		(1<<30) -#define PLLD_MISC_DIV_RST		(1<<23) -#define PLLD_MISC_DCCON_SHIFT		12 - -#define PLLE_MISC_READY			(1 << 15) - -#define PERIPH_CLK_TO_ENB_REG(c)	((c->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 8bfd31bcc49..00000000000 --- 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 <http://www.gnu.org/licenses/>. - */ - -#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 a23a0734e35..00000000000 --- 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 <ccross@google.com> - * - * 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 <linux/clk-private.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/clk.h> - -#include "clock.h" -#include "fuse.h" -#include "tegra2_emc.h" -#include "tegra20_clocks.h" -#include "tegra_cpu_car.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 d7147779f8e..00000000000 --- 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 <linux/kernel.h> -#include <linux/module.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/cpufreq.h> -#include <linux/syscore_ops.h> - -#include <asm/clkdev.h> - -#include <mach/powergate.h> - -#include "clock.h" -#include "fuse.h" -#include "iomap.h" -#include "tegra_cpu_car.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<<PERIPH_CLK_VI_SEL_EX_SHIFT) -#define PERIPH_CLK_NAND_DIV_EX_ENB	(1<<8) -#define PERIPH_CLK_DTV_POLARITY_INV	(1<<25) - -#define AUDIO_SYNC_SOURCE_MASK		0x0F -#define AUDIO_SYNC_DISABLE_BIT		0x10 -#define AUDIO_SYNC_TAP_NIBBLE_SHIFT(c)	((c->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<<PLL_MISC_CPCON_SHIFT) -#define PLL_MISC_LFCON_SHIFT		4 -#define PLL_MISC_LFCON_MASK		(0xF<<PLL_MISC_LFCON_SHIFT) -#define PLL_MISC_VCOCON_SHIFT		0 -#define PLL_MISC_VCOCON_MASK		(0xF<<PLL_MISC_VCOCON_SHIFT) -#define PLLD_MISC_CLKENABLE		(1<<30) - -#define PLLU_BASE_POST_DIV		(1<<20) - -#define PLLD_BASE_DSIB_MUX_SHIFT	25 -#define PLLD_BASE_DSIB_MUX_MASK		(1<<PLLD_BASE_DSIB_MUX_SHIFT) -#define PLLD_BASE_CSI_CLKENABLE		(1<<26) -#define PLLD_MISC_DSI_CLKENABLE		(1<<30) -#define PLLD_MISC_DIV_RST		(1<<23) -#define PLLD_MISC_DCCON_SHIFT		12 - -#define PLLDU_LFCON_SET_DIVN		600 - -/* FIXME: OUT_OF_TABLE_CPCON per pll */ -#define OUT_OF_TABLE_CPCON		0x8 - -#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_LP_DIV2_BYPASS		(0x1 << 16) -#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 SUPER_CLOCK_DIV_U71_SHIFT	16 -#define SUPER_CLOCK_DIV_U71_MASK	(0xff << SUPER_CLOCK_DIV_U71_SHIFT) -/* guarantees safe cpu backup */ -#define SUPER_CLOCK_DIV_U71_MIN		0x2 - -#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 - -#define PMC_PLLP_WB0_OVERRIDE				0xf8 -#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE		(1 << 12) - -#define UTMIP_PLL_CFG2					0x488 -#define UTMIP_PLL_CFG2_STABLE_COUNT(x)			(((x) & 0xfff) << 6) -#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x)		(((x) & 0x3f) << 18) -#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN	(1 << 0) -#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN	(1 << 2) -#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN	(1 << 4) - -#define UTMIP_PLL_CFG1					0x484 -#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x)		(((x) & 0x1f) << 27) -#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x)		(((x) & 0xfff) << 0) -#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN	(1 << 14) -#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN	(1 << 12) -#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN		(1 << 16) - -#define PLLE_BASE_CML_ENABLE		(1<<31) -#define PLLE_BASE_ENABLE		(1<<30) -#define PLLE_BASE_DIVCML_SHIFT		24 -#define PLLE_BASE_DIVCML_MASK		(0xf<<PLLE_BASE_DIVCML_SHIFT) -#define PLLE_BASE_DIVP_SHIFT		16 -#define PLLE_BASE_DIVP_MASK		(0x3f<<PLLE_BASE_DIVP_SHIFT) -#define PLLE_BASE_DIVN_SHIFT		8 -#define PLLE_BASE_DIVN_MASK		(0xFF<<PLLE_BASE_DIVN_SHIFT) -#define PLLE_BASE_DIVM_SHIFT		0 -#define PLLE_BASE_DIVM_MASK		(0xFF<<PLLE_BASE_DIVM_SHIFT) -#define PLLE_BASE_DIV_MASK		\ -	(PLLE_BASE_DIVCML_MASK | PLLE_BASE_DIVP_MASK | \ -	 PLLE_BASE_DIVN_MASK | PLLE_BASE_DIVM_MASK) -#define PLLE_BASE_DIV(m, n, p, cml)		\ -	 (((cml)<<PLLE_BASE_DIVCML_SHIFT) | ((p)<<PLLE_BASE_DIVP_SHIFT) | \ -	  ((n)<<PLLE_BASE_DIVN_SHIFT) | ((m)<<PLLE_BASE_DIVM_SHIFT)) - -#define PLLE_MISC_SETUP_BASE_SHIFT	16 -#define PLLE_MISC_SETUP_BASE_MASK	(0xFFFF<<PLLE_MISC_SETUP_BASE_SHIFT) -#define PLLE_MISC_READY			(1<<15) -#define PLLE_MISC_LOCK			(1<<11) -#define PLLE_MISC_LOCK_ENABLE		(1<<9) -#define PLLE_MISC_SETUP_EX_SHIFT	2 -#define PLLE_MISC_SETUP_EX_MASK		(0x3<<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		\ -	  ((0x7<<PLLE_MISC_SETUP_BASE_SHIFT) | (0x0<<PLLE_MISC_SETUP_EX_SHIFT)) - -#define PLLE_SS_CTRL			0x68 -#define	PLLE_SS_INCINTRV_SHIFT		24 -#define	PLLE_SS_INCINTRV_MASK		(0x3f<<PLLE_SS_INCINTRV_SHIFT) -#define	PLLE_SS_INC_SHIFT		16 -#define	PLLE_SS_INC_MASK		(0xff<<PLLE_SS_INC_SHIFT) -#define	PLLE_SS_MAX_SHIFT		0 -#define	PLLE_SS_MAX_MASK		(0x1ff<<PLLE_SS_MAX_SHIFT) -#define PLLE_SS_COEFFICIENTS_MASK	\ -	(PLLE_SS_INCINTRV_MASK | PLLE_SS_INC_MASK | PLLE_SS_MAX_MASK) -#define PLLE_SS_COEFFICIENTS_12MHZ	\ -	((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \ -	 (0x24<<PLLE_SS_MAX_SHIFT)) -#define PLLE_SS_DISABLE			((1<<12) | (1<<11) | (1<<10)) - -#define PLLE_AUX			0x48c -#define PLLE_AUX_PLLP_SEL		(1<<2) -#define PLLE_AUX_CML_SATA_ENABLE	(1<<1) -#define PLLE_AUX_CML_PCIE_ENABLE	(1<<0) - -#define	PMC_SATA_PWRGT			0x1ac -#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE	(1<<5) -#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL	(1<<4) - -#define ROUND_DIVIDER_UP	0 -#define ROUND_DIVIDER_DOWN	1 - -/* FIXME: recommended safety delay after lock is detected */ -#define PLL_POST_LOCK_DELAY		100 - -/* 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 - -/** -* 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 = 13000000, -		.enable_delay_count = 0x02, -		.stable_count = 0x33, -		.active_delay_count = 0x05, -		.xtal_freq_count = 0x7F -	}, -	{ -		.osc_frequency = 19200000, -		.enable_delay_count = 0x03, -		.stable_count = 0x4B, -		.active_delay_count = 0x06, -		.xtal_freq_count = 0xBB}, -	{ -		.osc_frequency = 12000000, -		.enable_delay_count = 0x02, -		.stable_count = 0x2F, -		.active_delay_count = 0x04, -		.xtal_freq_count = 0x76 -	}, -	{ -		.osc_frequency = 26000000, -		.enable_delay_count = 0x04, -		.stable_count = 0x66, -		.active_delay_count = 0x09, -		.xtal_freq_count = 0xFE -	}, -	{ -		.osc_frequency = 16800000, -		.enable_delay_count = 0x03, -		.stable_count = 0x41, -		.active_delay_count = 0x0A, -		.xtal_freq_count = 0xA4 -	}, -}; - -static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); -static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); -static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE); - -#define MISC_GP_HIDREV                  0x804 - -/* - * Some peripheral clocks share an enable bit, so refcount the enable bits - * in registers CLK_ENABLE_L, ... CLK_ENABLE_W - */ -static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 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)) -#define chipid_readl() \ -	__raw_readl(misc_gp_hidrev_base + MISC_GP_HIDREV) - -#define clk_writel_delay(value, reg)					\ -	do {								\ -		__raw_writel((value), reg_clk_base + (reg));	\ -		udelay(2);						\ -	} while (0) - -static inline int clk_set_div(struct clk_tegra *c, u32 n) -{ -	struct clk *clk = c->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 7a34adb2f72..00000000000 --- 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 <http://www.gnu.org/licenses/>. - */ - -#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 741d264d5ec..00000000000 --- 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 <linux/clk-private.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/cpufreq.h> - -#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)		\ -	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/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig index 7a602069bab..e3e94b2fa14 100644 --- a/arch/arm/mach-vt8500/Kconfig +++ b/arch/arm/mach-vt8500/Kconfig @@ -16,3 +16,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 fe99b709f11..49e80053d82 100644 --- a/arch/arm/mach-vt8500/vt8500.c +++ b/arch/arm/mach-vt8500/vt8500.c @@ -180,6 +180,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)") diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index 7539ec27506..15451ee4acc 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -19,6 +19,52 @@  #include "proc-macros.S"  /* + * 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 function is cloned from arch/arm/mach-tegra/headsmp.S, and needs + * to be called for both secondary cores startup and primary core resume + * procedures. + */ +ENTRY(v7_invalidate_l1) +       mov     r0, #0 +       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<<WayShift)|(NumSets<<SetShift) +       mcr     p15, 0, r5, c7, c6, 2 +       bgt     2b +       cmp     r2, #0 +       bgt     1b +       dsb +       isb +       mov     pc, lr +ENDPROC(v7_invalidate_l1) + +/*   *	v7_flush_icache_all()   *   *	Flush the whole I-cache. diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 14fde73ea6f..300d4775d92 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -26,6 +26,8 @@ obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o  obj-$(CONFIG_ARCH_U8500)	+= ux500/  obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o  obj-$(CONFIG_ARCH_ZYNQ)		+= clk-zynq.o +obj-$(CONFIG_ARCH_TEGRA)	+= tegra/ +  obj-$(CONFIG_X86)		+= x86/  # Chip specific diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c index e69991aab43..792bc57a9db 100644 --- a/drivers/clk/clk-bcm2835.c +++ b/drivers/clk/clk-bcm2835.c @@ -20,6 +20,13 @@  #include <linux/clk-provider.h>  #include <linux/clkdev.h>  #include <linux/clk/bcm2835.h> +#include <linux/clk-provider.h> +#include <linux/of.h> + +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);  } diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index 126370a62ce..76ce6c6d111 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++) diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile new file mode 100644 index 00000000000..2b41b0f4f73 --- /dev/null +++ b/drivers/clk/tegra/Makefile @@ -0,0 +1,11 @@ +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 + +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-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c new file mode 100644 index 00000000000..c0f7843e80e --- /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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> + +#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 00000000000..4d75b1f37e3 --- /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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/clk-provider.h> +#include <linux/clk.h> + +#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 00000000000..6dd533251e7 --- /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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/tegra-soc.h> + +#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 00000000000..788486e6331 --- /dev/null +++ b/drivers/clk/tegra/clk-periph.c @@ -0,0 +1,218 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> + +#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); +} + +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, +	.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 00000000000..3598987a451 --- /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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/clk-provider.h> +#include <linux/clk.h> + +#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 00000000000..165f24734c1 --- /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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk-provider.h> +#include <linux/clk.h> + +#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 00000000000..7ad48a83233 --- /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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/clk-provider.h> +#include <linux/clk.h> + +#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-tegra20.c b/drivers/clk/tegra/clk-tegra20.c new file mode 100644 index 00000000000..5d41569883a --- /dev/null +++ b/drivers/clk/tegra/clk-tegra20.c @@ -0,0 +1,1349 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/tegra.h> +#include <linux/delay.h> + +#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 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 +#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)) + +#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; +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); +} + +#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[] = { +	{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(usbd,   "utmip-pad",    NULL), +	TEGRA_CLK_DUPLICATE(usbd,   "tegra-ehci.0", NULL), +	TEGRA_CLK_DUPLICATE(usbd,   "tegra-otg",    NULL), +	TEGRA_CLK_DUPLICATE(cclk,   NULL,           "cpu"), +	TEGRA_CLK_DUPLICATE(twd,    "smp_twd",      NULL), +	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-tegra30.c b/drivers/clk/tegra/clk-tegra30.c new file mode 100644 index 00000000000..a1638129eba --- /dev/null +++ b/drivers/clk/tegra/clk-tegra30.c @@ -0,0 +1,1987 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/tegra.h> + +#include <mach/powergate.h> + +#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; + +	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(usbd, "utmip-pad", NULL), +	TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), +	TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), +	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(twd, "smp_twd", NULL), +	TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"), +	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.c b/drivers/clk/tegra/clk.c new file mode 100644 index 00000000000..a603b9af0ad --- /dev/null +++ b/drivers/clk/tegra/clk.c @@ -0,0 +1,85 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/clk/tegra.h> + +#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) +{ +	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); +			} +	} +} + +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/clk/tegra/clk.h b/drivers/clk/tegra/clk.h new file mode 100644 index 00000000000..0744731c622 --- /dev/null +++ b/drivers/clk/tegra/clk.h @@ -0,0 +1,502 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __TEGRA_CLK_H +#define __TEGRA_CLK_H + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> + +/** + * 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); + +#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 */ + +#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 */ diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index c4cc27e5c8a..071e2c3eec4 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 03ee87482c7..24c6e7d945e 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 index f7304670f2f..670aa1e55cd 100644 --- a/arch/arm/mach-kirkwood/cpuidle.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -14,6 +14,7 @@   */  #include <linux/kernel.h> +#include <linux/module.h>  #include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/cpuidle.h> @@ -21,16 +22,17 @@  #include <linux/export.h>  #include <asm/proc-fns.h>  #include <asm/cpuidle.h> -#include <mach/kirkwood.h>  #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 <andrew@lunn.ch>"); +MODULE_DESCRIPTION("Kirkwood cpu idle driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kirkwood-cpuidle"); diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 58c1896271e..f6c018f1b45 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -32,8 +32,8 @@  #include <linux/platform_device.h>  #include <linux/pm_runtime.h>  #include <linux/slab.h> +#include <linux/clk/tegra.h> -#include <mach/clk.h>  #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 d365c6dff0f..b6679b36700 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -12,8 +12,7 @@  #include <linux/module.h>  #include <linux/of.h>  #include <linux/platform_device.h> - -#include <mach/clk.h> +#include <linux/clk/tegra.h>  #include "drm.h"  #include "dc.h" diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 3a503c9e468..d980dc75788 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -11,7 +11,6 @@  #include <linux/of_address.h>  #include <linux/of_platform.h> -#include <mach/clk.h>  #include <linux/dma-mapping.h>  #include <asm/dma-iommu.h> diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 266af787924..d4f3fb9f0c2 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -14,8 +14,7 @@  #include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/regulator/consumer.h> - -#include <mach/clk.h> +#include <linux/clk/tegra.h>  #include "hdmi.h"  #include "drm.h" diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 1fb30099dac..f0d9923323e 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -29,11 +29,10 @@  #include <linux/of_i2c.h>  #include <linux/of_device.h>  #include <linux/module.h> +#include <linux/clk/tegra.h>  #include <asm/unaligned.h> -#include <mach/clk.h> -  #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 d89e7d392d1..0e138ebcc76 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -30,7 +30,7 @@  #include <linux/clk.h>  #include <linux/slab.h>  #include <linux/input/matrix_keypad.h> -#include <mach/clk.h> +#include <linux/clk/tegra.h>  #define KBC_MAX_GPIO	24  #define KBC_MAX_KPENT	8 diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index aa64d5d3fb2..476d06452af 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1033,7 +1033,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 diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 8a61b27a9f2..3d6a12b2af0 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -34,7 +34,7 @@  #include <linux/of_device.h>  #include <linux/spi/spi.h>  #include <linux/spi/spi-tegra.h> -#include <mach/clk.h> +#include <linux/clk/tegra.h>  #define SPI_COMMAND				0x000  #define SPI_GO					BIT(30) @@ -531,7 +531,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 8458c4bf717..b8698b389ef 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -35,7 +35,7 @@  #include <linux/of_device.h>  #include <linux/spi/spi.h>  #include <linux/spi/spi-tegra.h> -#include <mach/clk.h> +#include <linux/clk/tegra.h>  #define SLINK_COMMAND			0x000  #define SLINK_BIT_LENGTH(x)		(((x) & 0x1f) << 0) @@ -1186,7 +1186,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); diff --git a/drivers/staging/nvec/TODO b/drivers/staging/nvec/TODO index f950ab890e2..e5ae42a0b44 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 6a0b6eccf1e..cf159365b0e 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -37,8 +37,7 @@  #include <linux/slab.h>  #include <linux/spinlock.h>  #include <linux/workqueue.h> - -#include <mach/clk.h> +#include <linux/clk/tegra.h>  #include "nvec.h" @@ -816,7 +815,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; diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index acf17556bd8..568aecc7075 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,23 +26,28 @@  #include <linux/of.h>  #include <linux/of_gpio.h>  #include <linux/pm_runtime.h> - +#include <linux/usb/ehci_def.h>  #include <linux/usb/tegra_usb_phy.h>  #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 {  	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; +	bool needs_double_reset;  	enum tegra_usb_phy_port_speed port_speed;  }; @@ -50,9 +55,8 @@ 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); +	usb_phy_set_suspend(hcd->phy, 0);  	tegra->host_resumed = 1;  } @@ -61,9 +65,8 @@ 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); -	clk_disable_unprepare(tegra->emc_clk);  }  static int tegra_ehci_internal_port_reset( @@ -156,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);  		}  	} @@ -184,7 +187,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); @@ -209,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); @@ -473,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); @@ -540,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;  } @@ -604,6 +607,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) @@ -615,6 +649,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) { @@ -656,15 +691,8 @@ 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");  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res) { @@ -712,9 +740,19 @@ 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); -	err = usb_phy_set_suspend(&tegra->phy->u_phy, 0); +	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(hcd->phy, 0);  	if (err) {  		dev_err(&pdev->dev, "Failed to power on the phy\n");  		goto fail; @@ -760,10 +798,8 @@ 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->emc_clk); -fail_emc_clk:  	clk_disable_unprepare(tegra->clk);  fail_clk:  	usb_put_hcd(hcd); @@ -784,15 +820,12 @@ 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); -	clk_disable_unprepare(tegra->emc_clk); -  	return 0;  } diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 9d13c81754e..5487d38481a 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -24,6 +24,7 @@  #include <linux/platform_device.h>  #include <linux/io.h>  #include <linux/gpio.h> +#include <linux/of.h>  #include <linux/of_gpio.h>  #include <linux/usb/otg.h>  #include <linux/usb/ulpi.h> @@ -35,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) @@ -208,11 +196,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); @@ -221,7 +204,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 +219,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 +288,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,13 +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); -	} - -	if (phy->instance == 2) { -		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__); @@ -332,7 +310,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,13 +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); -	} - -	if (phy->instance == 2) { -		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)) @@ -365,7 +338,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 +413,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 +430,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,11 +443,8 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)  	utmi_phy_clk_enable(phy); -	if (phy->instance == 2) { -		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;  } @@ -621,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); @@ -639,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);  } @@ -660,7 +615,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)) { @@ -698,7 +653,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); @@ -709,7 +664,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); @@ -717,7 +672,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); @@ -739,8 +694,9 @@ 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 = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); +	phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);  	if (!phy)  		return ERR_PTR(-ENOMEM); @@ -749,9 +705,16 @@ 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"); +	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,45 +759,40 @@ 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)  { -	if (!phy_is_ulpi(phy)) +	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)  { -	if (!phy_is_ulpi(phy)) +	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)  { -	if (!phy_is_ulpi(phy)) +	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)  { -	if (!phy_is_ulpi(phy)) +	struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + +	if (!phy->is_ulpi_phy)  		utmi_phy_restore_end(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/arch/arm/mach-tegra/tegra_cpu_car.h b/include/linux/clk/tegra.h index 9764d31032b..404d6f94087 100644 --- a/arch/arm/mach-tegra/tegra_cpu_car.h +++ b/include/linux/clk/tegra.h @@ -14,8 +14,10 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ -#ifndef __MACH_TEGRA_CPU_CAR_H -#define __MACH_TEGRA_CPU_CAR_H +#ifndef __LINUX_CLK_TEGRA_H_ +#define __LINUX_CLK_TEGRA_H_ + +#include <linux/clk.h>  /*   * Tegra CPU clock and reset control ops @@ -118,7 +120,8 @@ 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); -#endif /* __MACH_TEGRA_CPU_CAR_H */ +#endif /* __LINUX_CLK_TEGRA_H_ */ diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h index ef65b67c56c..e697c85ad3b 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;  };  /*-------------------------------------------------------------------------*/ diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h new file mode 100644 index 00000000000..95f611d78f3 --- /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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __LINUX_TEGRA_SOC_H_ +#define __LINUX_TEGRA_SOC_H_ + +u32 tegra_read_chipid(void); + +#endif /* __LINUX_TEGRA_SOC_H_ */ diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 176b1ca06ae..9ebebe90692 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -59,22 +59,24 @@ struct tegra_usb_phy {  	struct usb_phy *ulpi;  	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,  	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_preresume(struct usb_phy *phy); -void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy); +void tegra_usb_phy_postresume(struct usb_phy *phy); -void tegra_usb_phy_preresume(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_usb_phy_postresume(struct tegra_usb_phy *phy); +void tegra_ehci_phy_restore_end(struct usb_phy *phy); -void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, -				 enum tegra_usb_phy_port_speed port_speed); +void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val); -void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy); +void tegra_ehci_set_phcd(struct usb_phy *x, bool enable);  #endif /* __TEGRA_USB_PHY_H */ diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index dd146f10fef..e5cfb4ac41b 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -25,7 +25,7 @@  #include <linux/pm_runtime.h>  #include <linux/regmap.h>  #include <linux/slab.h> -#include <mach/clk.h> +#include <linux/clk/tegra.h>  #include <sound/soc.h>  #include "tegra30_ahub.h" @@ -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;  |