diff options
654 files changed, 22906 insertions, 10467 deletions
diff --git a/Documentation/arm/sunxi/clocks.txt b/Documentation/arm/sunxi/clocks.txt new file mode 100644 index 000000000000..e09a88aa3136 --- /dev/null +++ b/Documentation/arm/sunxi/clocks.txt @@ -0,0 +1,56 @@ +Frequently asked questions about the sunxi clock system +======================================================= + +This document contains useful bits of information that people tend to ask +about the sunxi clock system, as well as accompanying ASCII art when adequate. + +Q: Why is the main 24MHz oscillator gatable? Wouldn't that break the + system? + +A: The 24MHz oscillator allows gating to save power. Indeed, if gated + carelessly the system would stop functioning, but with the right + steps, one can gate it and keep the system running. Consider this + simplified suspend example: + + While the system is operational, you would see something like + + 24MHz 32kHz + | + PLL1 + \ + \_ CPU Mux + | + [CPU] + + When you are about to suspend, you switch the CPU Mux to the 32kHz + oscillator: + + 24Mhz 32kHz + | | + PLL1 | + / + CPU Mux _/ + | + [CPU] + + Finally you can gate the main oscillator + + 32kHz + | + | + / + CPU Mux _/ + | + [CPU] + +Q: Were can I learn more about the sunxi clocks? + +A: The linux-sunxi wiki contains a page documenting the clock registers, + you can find it at + + http://linux-sunxi.org/A10/CCM + + The authoritative source for information at this time is the ccmu driver + released by Allwinner, you can find it at + + https://github.com/linux-sunxi/linux-sunxi/tree/sunxi-3.0/arch/arm/mach-sun4i/clock/ccmu diff --git a/Documentation/clk.txt b/Documentation/clk.txt index 1943fae014fd..4274a546eb57 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -174,9 +174,9 @@ int clk_foo_enable(struct clk_hw *hw) }; Below is a matrix detailing which clk_ops are mandatory based upon the -hardware capbilities of that clock. A cell marked as "y" means +hardware capabilities of that clock. A cell marked as "y" means mandatory, a cell marked as "n" implies that either including that -callback is invalid or otherwise uneccesary. Empty cells are either +callback is invalid or otherwise unnecessary. Empty cells are either optional or must be evaluated on a case-by-case basis. clock hardware characteristics diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt index b5846e21cc2e..1608a54e90e1 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt @@ -1,19 +1,84 @@ NVIDIA Tegra Power Management Controller (PMC) -Properties: +The PMC block interacts with an external Power Management Unit. The PMC +mostly controls the entry and exit of the system from different sleep +modes. It provides power-gating controllers for SoC and CPU power-islands. + +Required properties: - name : Should be pmc - compatible : Should contain "nvidia,tegra<chip>-pmc". - reg : Offset and length of the register set for the device +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Must include the following entries: + "pclk" (The Tegra clock of that name), + "clk32k_in" (The 32KHz clock input to Tegra). + +Optional properties: - nvidia,invert-interrupt : If present, inverts the PMU interrupt signal. The PMU is an external Power Management Unit, whose interrupt output signal is fed into the PMC. This signal is optionally inverted, and then fed into the ARM GIC. The PMC is not involved in the detection or handling of this interrupt signal, merely its inversion. +- nvidia,suspend-mode : The suspend mode that the platform should use. + Valid values are 0, 1 and 2: + 0 (LP0): CPU + Core voltage off and DRAM in self-refresh + 1 (LP1): CPU voltage off and DRAM in self-refresh + 2 (LP2): CPU voltage off +- nvidia,core-power-req-active-high : Boolean, core power request active-high +- nvidia,sys-clock-req-active-high : Boolean, system clock request active-high +- nvidia,combined-power-req : Boolean, combined power request for CPU & Core +- nvidia,cpu-pwr-good-en : Boolean, CPU power good signal (from PMIC to PMC) + is enabled. + +Required properties when nvidia,suspend-mode is specified: +- nvidia,cpu-pwr-good-time : CPU power good time in uS. +- nvidia,cpu-pwr-off-time : CPU power off time in uS. +- nvidia,core-pwr-good-time : <Oscillator-stable-time Power-stable-time> + Core power good time in uS. +- nvidia,core-pwr-off-time : Core power off time in uS. + +Required properties when nvidia,suspend-mode=<0>: +- nvidia,lp0-vec : <start length> Starting address and length of LP0 vector + The LP0 vector contains the warm boot code that is executed by AVP when + resuming from the LP0 state. The AVP (Audio-Video Processor) is an ARM7 + processor and always being the first boot processor when chip is power on + or resume from deep sleep mode. When the system is resumed from the deep + sleep mode, the warm boot code will restore some PLLs, clocks and then + bring up CPU0 for resuming the system. Example: +/ SoC dts including file pmc@7000f400 { compatible = "nvidia,tegra20-pmc"; reg = <0x7000e400 0x400>; + clocks = <&tegra_car 110>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; nvidia,invert-interrupt; + nvidia,suspend-mode = <1>; + nvidia,cpu-pwr-good-time = <2000>; + nvidia,cpu-pwr-off-time = <100>; + nvidia,core-pwr-good-time = <3845 3845>; + nvidia,core-pwr-off-time = <458>; + nvidia,core-power-req-active-high; + nvidia,sys-clock-req-active-high; + nvidia,lp0-vec = <0xbdffd000 0x2000>; +}; + +/ Tegra board dts file +{ + ... + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + ... }; diff --git a/Documentation/devicetree/bindings/bus/ti-gpmc.txt b/Documentation/devicetree/bindings/bus/ti-gpmc.txt index 5ddb2e9efaaa..4b87ea1194e3 100644 --- a/Documentation/devicetree/bindings/bus/ti-gpmc.txt +++ b/Documentation/devicetree/bindings/bus/ti-gpmc.txt @@ -35,36 +35,83 @@ Required properties: Timing properties for child nodes. All are optional and default to 0. - - gpmc,sync-clk: Minimum clock period for synchronous mode, in picoseconds - - Chip-select signal timings corresponding to GPMC_CONFIG2: - - gpmc,cs-on: Assertion time - - gpmc,cs-rd-off: Read deassertion time - - gpmc,cs-wr-off: Write deassertion time - - ADV signal timings corresponding to GPMC_CONFIG3: - - gpmc,adv-on: Assertion time - - gpmc,adv-rd-off: Read deassertion time - - gpmc,adv-wr-off: Write deassertion time - - WE signals timings corresponding to GPMC_CONFIG4: - - gpmc,we-on: Assertion time - - gpmc,we-off: Deassertion time - - OE signals timings corresponding to GPMC_CONFIG4: - - gpmc,oe-on: Assertion time - - gpmc,oe-off: Deassertion time - - Access time and cycle time timings corresponding to GPMC_CONFIG5: - - gpmc,page-burst-access: Multiple access word delay - - gpmc,access: Start-cycle to first data valid delay - - gpmc,rd-cycle: Total read cycle time - - gpmc,wr-cycle: Total write cycle time + - gpmc,sync-clk-ps: Minimum clock period for synchronous mode, in picoseconds + + Chip-select signal timings (in nanoseconds) corresponding to GPMC_CONFIG2: + - gpmc,cs-on-ns: Assertion time + - gpmc,cs-rd-off-ns: Read deassertion time + - gpmc,cs-wr-off-ns: Write deassertion time + + ADV signal timings (in nanoseconds) corresponding to GPMC_CONFIG3: + - gpmc,adv-on-ns: Assertion time + - gpmc,adv-rd-off-ns: Read deassertion time + - gpmc,adv-wr-off-ns: Write deassertion time + + WE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4: + - gpmc,we-on-ns Assertion time + - gpmc,we-off-ns: Deassertion time + + OE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4: + - gpmc,oe-on-ns: Assertion time + - gpmc,oe-off-ns: Deassertion time + + Access time and cycle time timings (in nanoseconds) corresponding to + GPMC_CONFIG5: + - gpmc,page-burst-access-ns: Multiple access word delay + - gpmc,access-ns: Start-cycle to first data valid delay + - gpmc,rd-cycle-ns: Total read cycle time + - gpmc,wr-cycle-ns: Total write cycle time + - gpmc,bus-turnaround-ns: Turn-around time between successive accesses + - gpmc,cycle2cycle-delay-ns: Delay between chip-select pulses + - gpmc,clk-activation-ns: GPMC clock activation time + - gpmc,wait-monitoring-ns: Start of wait monitoring with regard to valid + data + +Boolean timing parameters. If property is present parameter enabled and +disabled if omitted: + - gpmc,adv-extra-delay: ADV signal is delayed by half GPMC clock + - gpmc,cs-extra-delay: CS signal is delayed by half GPMC clock + - gpmc,cycle2cycle-diffcsen: Add "cycle2cycle-delay" between successive + accesses to a different CS + - gpmc,cycle2cycle-samecsen: Add "cycle2cycle-delay" between successive + accesses to the same CS + - gpmc,oe-extra-delay: OE signal is delayed by half GPMC clock + - gpmc,we-extra-delay: WE signal is delayed by half GPMC clock + - gpmc,time-para-granularity: Multiply all access times by 2 The following are only applicable to OMAP3+ and AM335x: - - gpmc,wr-access - - gpmc,wr-data-mux-bus - + - gpmc,wr-access-ns: In synchronous write mode, for single or + burst accesses, defines the number of + GPMC_FCLK cycles from start access time + to the GPMC_CLK rising edge used by the + memory device for the first data capture. + - gpmc,wr-data-mux-bus-ns: In address-data multiplex mode, specifies + the time when the first data is driven on + the address-data bus. + +GPMC chip-select settings properties for child nodes. All are optional. + +- gpmc,burst-length Page/burst length. Must be 4, 8 or 16. +- gpmc,burst-wrap Enables wrap bursting +- gpmc,burst-read Enables read page/burst mode +- gpmc,burst-write Enables write page/burst mode +- gpmc,device-nand Device is NAND +- gpmc,device-width Total width of device(s) connected to a GPMC + chip-select in bytes. The GPMC supports 8-bit + and 16-bit devices and so this property must be + 1 or 2. +- gpmc,mux-add-data Address and data multiplexing configuration. + Valid values are 1 for address-address-data + multiplexing mode and 2 for address-data + multiplexing mode. +- gpmc,sync-read Enables synchronous read. Defaults to asynchronous + is this is not set. +- gpmc,sync-write Enables synchronous writes. Defaults to asynchronous + is this is not set. +- gpmc,wait-pin Wait-pin used by client. Must be less than + "gpmc,num-waitpins". +- gpmc,wait-on-read Enables wait monitoring on reads. +- gpmc,wait-on-write Enables wait monitoring on writes. Example for an AM33xx board: diff --git a/Documentation/devicetree/bindings/clock/axi-clkgen.txt b/Documentation/devicetree/bindings/clock/axi-clkgen.txt new file mode 100644 index 000000000000..028b493e97ff --- /dev/null +++ b/Documentation/devicetree/bindings/clock/axi-clkgen.txt @@ -0,0 +1,22 @@ +Binding for the axi-clkgen clock generator + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "adi,axi-clkgen". +- #clock-cells : from common clock binding; Should always be set to 0. +- reg : Address and length of the axi-clkgen register set. +- clocks : Phandle and clock specifier for the parent clock. + +Optional properties: +- clock-output-names : From common clock binding. + +Example: + clock@0xff000000 { + compatible = "adi,axi-clkgen"; + #clock-cells = <0>; + reg = <0xff000000 0x1000>; + clocks = <&osc 1>; + }; diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt new file mode 100644 index 000000000000..ea5e26f16aec --- /dev/null +++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt @@ -0,0 +1,288 @@ +* Samsung Exynos4 Clock Controller + +The Exynos4 clock controller generates and supplies clock to various controllers +within the Exynos4 SoC. The clock binding described here is applicable to all +SoC's in the Exynos4 family. + +Required Properties: + +- comptible: should be one of the following. + - "samsung,exynos4210-clock" - controller compatible with Exynos4210 SoC. + - "samsung,exynos4412-clock" - controller compatible with Exynos4412 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +The following is the list of clocks generated by the controller. Each clock is +assigned an identifier and client nodes use this identifier to specify the +clock which they consume. Some of the clocks are available only on a particular +Exynos4 SoC and this is specified where applicable. + + + [Core Clocks] + + Clock ID SoC (if specific) + ----------------------------------------------- + + xxti 1 + xusbxti 2 + fin_pll 3 + fout_apll 4 + fout_mpll 5 + fout_epll 6 + fout_vpll 7 + sclk_apll 8 + sclk_mpll 9 + sclk_epll 10 + sclk_vpll 11 + arm_clk 12 + aclk200 13 + aclk100 14 + aclk160 15 + aclk133 16 + mout_mpll_user_t 17 Exynos4x12 + mout_mpll_user_c 18 Exynos4x12 + mout_core 19 + mout_apll 20 + + + [Clock Gate for Special Clocks] + + Clock ID SoC (if specific) + ----------------------------------------------- + + sclk_fimc0 128 + sclk_fimc1 129 + sclk_fimc2 130 + sclk_fimc3 131 + sclk_cam0 132 + sclk_cam1 133 + sclk_csis0 134 + sclk_csis1 135 + sclk_hdmi 136 + sclk_mixer 137 + sclk_dac 138 + sclk_pixel 139 + sclk_fimd0 140 + sclk_mdnie0 141 Exynos4412 + sclk_mdnie_pwm0 12 142 Exynos4412 + sclk_mipi0 143 + sclk_audio0 144 + sclk_mmc0 145 + sclk_mmc1 146 + sclk_mmc2 147 + sclk_mmc3 148 + sclk_mmc4 149 + sclk_sata 150 Exynos4210 + sclk_uart0 151 + sclk_uart1 152 + sclk_uart2 153 + sclk_uart3 154 + sclk_uart4 155 + sclk_audio1 156 + sclk_audio2 157 + sclk_spdif 158 + sclk_spi0 159 + sclk_spi1 160 + sclk_spi2 161 + sclk_slimbus 162 + sclk_fimd1 163 Exynos4210 + sclk_mipi1 164 Exynos4210 + sclk_pcm1 165 + sclk_pcm2 166 + sclk_i2s1 167 + sclk_i2s2 168 + sclk_mipihsi 169 Exynos4412 + sclk_mfc 170 + sclk_pcm0 171 + sclk_g3d 172 + sclk_pwm_isp 173 Exynos4x12 + sclk_spi0_isp 174 Exynos4x12 + sclk_spi1_isp 175 Exynos4x12 + sclk_uart_isp 176 Exynos4x12 + + [Peripheral Clock Gates] + + Clock ID SoC (if specific) + ----------------------------------------------- + + fimc0 256 + fimc1 257 + fimc2 258 + fimc3 259 + csis0 260 + csis1 261 + jpeg 262 + smmu_fimc0 263 + smmu_fimc1 264 + smmu_fimc2 265 + smmu_fimc3 266 + smmu_jpeg 267 + vp 268 + mixer 269 + tvenc 270 Exynos4210 + hdmi 271 + smmu_tv 272 + mfc 273 + smmu_mfcl 274 + smmu_mfcr 275 + g3d 276 + g2d 277 Exynos4210 + rotator 278 Exynos4210 + mdma 279 Exynos4210 + smmu_g2d 280 Exynos4210 + smmu_rotator 281 Exynos4210 + smmu_mdma 282 Exynos4210 + fimd0 283 + mie0 284 + mdnie0 285 Exynos4412 + dsim0 286 + smmu_fimd0 287 + fimd1 288 Exynos4210 + mie1 289 Exynos4210 + dsim1 290 Exynos4210 + smmu_fimd1 291 Exynos4210 + pdma0 292 + pdma1 293 + pcie_phy 294 + sata_phy 295 Exynos4210 + tsi 296 + sdmmc0 297 + sdmmc1 298 + sdmmc2 299 + sdmmc3 300 + sdmmc4 301 + sata 302 Exynos4210 + sromc 303 + usb_host 304 + usb_device 305 + pcie 306 + onenand 307 + nfcon 308 + smmu_pcie 309 + gps 310 + smmu_gps 311 + uart0 312 + uart1 313 + uart2 314 + uart3 315 + uart4 316 + i2c0 317 + i2c1 318 + i2c2 319 + i2c3 320 + i2c4 321 + i2c5 322 + i2c6 323 + i2c7 324 + i2c_hdmi 325 + tsadc 326 + spi0 327 + spi1 328 + spi2 329 + i2s1 330 + i2s2 331 + pcm0 332 + i2s0 333 + pcm1 334 + pcm2 335 + pwm 336 + slimbus 337 + spdif 338 + ac97 339 + modemif 340 + chipid 341 + sysreg 342 + hdmi_cec 343 + mct 344 + wdt 345 + rtc 346 + keyif 347 + audss 348 + mipi_hsi 349 Exynos4210 + mdma2 350 Exynos4210 + pixelasyncm0 351 + pixelasyncm1 352 + fimc_lite0 353 Exynos4x12 + fimc_lite1 354 Exynos4x12 + ppmuispx 355 Exynos4x12 + ppmuispmx 356 Exynos4x12 + fimc_isp 357 Exynos4x12 + fimc_drc 358 Exynos4x12 + fimc_fd 359 Exynos4x12 + mcuisp 360 Exynos4x12 + gicisp 361 Exynos4x12 + smmu_isp 362 Exynos4x12 + smmu_drc 363 Exynos4x12 + smmu_fd 364 Exynos4x12 + smmu_lite0 365 Exynos4x12 + smmu_lite1 366 Exynos4x12 + mcuctl_isp 367 Exynos4x12 + mpwm_isp 368 Exynos4x12 + i2c0_isp 369 Exynos4x12 + i2c1_isp 370 Exynos4x12 + mtcadc_isp 371 Exynos4x12 + pwm_isp 372 Exynos4x12 + wdt_isp 373 Exynos4x12 + uart_isp 374 Exynos4x12 + asyncaxim 375 Exynos4x12 + smmu_ispcx 376 Exynos4x12 + spi0_isp 377 Exynos4x12 + spi1_isp 378 Exynos4x12 + pwm_isp_sclk 379 Exynos4x12 + spi0_isp_sclk 380 Exynos4x12 + spi1_isp_sclk 381 Exynos4x12 + uart_isp_sclk 382 Exynos4x12 + + [Mux Clocks] + + Clock ID SoC (if specific) + ----------------------------------------------- + + mout_fimc0 384 + mout_fimc1 385 + mout_fimc2 386 + mout_fimc3 387 + mout_cam0 388 + mout_cam1 389 + mout_csis0 390 + mout_csis1 391 + mout_g3d0 392 + mout_g3d1 393 + mout_g3d 394 + aclk400_mcuisp 395 Exynos4x12 + + [Div Clocks] + + Clock ID SoC (if specific) + ----------------------------------------------- + + div_isp0 450 Exynos4x12 + div_isp1 451 Exynos4x12 + div_mcuisp0 452 Exynos4x12 + div_mcuisp1 453 Exynos4x12 + div_aclk200 454 Exynos4x12 + div_aclk400_mcuisp 455 Exynos4x12 + + +Example 1: An example of a clock controller node is listed below. + + clock: clock-controller@0x10030000 { + compatible = "samsung,exynos4210-clock"; + reg = <0x10030000 0x20000>; + #clock-cells = <1>; + }; + +Example 2: UART controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + + serial@13820000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13820000 0x100>; + interrupts = <0 54 0>; + clocks = <&clock 314>, <&clock 153>; + clock-names = "uart", "clk_uart_baud0"; + }; diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt new file mode 100644 index 000000000000..781a6276adf7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt @@ -0,0 +1,177 @@ +* Samsung Exynos5250 Clock Controller + +The Exynos5250 clock controller generates and supplies clock to various +controllers within the Exynos5250 SoC. + +Required Properties: + +- comptible: should be one of the following. + - "samsung,exynos5250-clock" - controller compatible with Exynos5250 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +The following is the list of clocks generated by the controller. Each clock is +assigned an identifier and client nodes use this identifier to specify the +clock which they consume. + + + [Core Clocks] + + Clock ID + ---------------------------- + + fin_pll 1 + + [Clock Gate for Special Clocks] + + Clock ID + ---------------------------- + + sclk_cam_bayer 128 + sclk_cam0 129 + sclk_cam1 130 + sclk_gscl_wa 131 + sclk_gscl_wb 132 + sclk_fimd1 133 + sclk_mipi1 134 + sclk_dp 135 + sclk_hdmi 136 + sclk_pixel 137 + sclk_audio0 138 + sclk_mmc0 139 + sclk_mmc1 140 + sclk_mmc2 141 + sclk_mmc3 142 + sclk_sata 143 + sclk_usb3 144 + sclk_jpeg 145 + sclk_uart0 146 + sclk_uart1 147 + sclk_uart2 148 + sclk_uart3 149 + sclk_pwm 150 + sclk_audio1 151 + sclk_audio2 152 + sclk_spdif 153 + sclk_spi0 154 + sclk_spi1 155 + sclk_spi2 156 + + + [Peripheral Clock Gates] + + Clock ID + ---------------------------- + + gscl0 256 + gscl1 257 + gscl2 258 + gscl3 259 + gscl_wa 260 + gscl_wb 261 + smmu_gscl0 262 + smmu_gscl1 263 + smmu_gscl2 264 + smmu_gscl3 265 + mfc 266 + smmu_mfcl 267 + smmu_mfcr 268 + rotator 269 + jpeg 270 + mdma1 271 + smmu_rotator 272 + smmu_jpeg 273 + smmu_mdma1 274 + pdma0 275 + pdma1 276 + sata 277 + usbotg 278 + mipi_hsi 279 + sdmmc0 280 + sdmmc1 281 + sdmmc2 282 + sdmmc3 283 + sromc 284 + usb2 285 + usb3 286 + sata_phyctrl 287 + sata_phyi2c 288 + uart0 289 + uart1 290 + uart2 291 + uart3 292 + uart4 293 + i2c0 294 + i2c1 295 + i2c2 296 + i2c3 297 + i2c4 298 + i2c5 299 + i2c6 300 + i2c7 301 + i2c_hdmi 302 + adc 303 + spi0 304 + spi1 305 + spi2 306 + i2s1 307 + i2s2 308 + pcm1 309 + pcm2 310 + pwm 311 + spdif 312 + ac97 313 + hsi2c0 314 + hsi2c1 315 + hs12c2 316 + hs12c3 317 + chipid 318 + sysreg 319 + pmu 320 + cmu_top 321 + cmu_core 322 + cmu_mem 323 + tzpc0 324 + tzpc1 325 + tzpc2 326 + tzpc3 327 + tzpc4 328 + tzpc5 329 + tzpc6 330 + tzpc7 331 + tzpc8 332 + tzpc9 333 + hdmi_cec 334 + mct 335 + wdt 336 + rtc 337 + tmu 338 + fimd1 339 + mie1 340 + dsim0 341 + dp 342 + mixer 343 + hdmi 345 + +Example 1: An example of a clock controller node is listed below. + + clock: clock-controller@0x10010000 { + compatible = "samsung,exynos5250-clock"; + reg = <0x10010000 0x30000>; + #clock-cells = <1>; + }; + +Example 2: UART controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + + serial@13820000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13820000 0x100>; + interrupts = <0 54 0>; + clocks = <&clock 314>, <&clock 153>; + clock-names = "uart", "clk_uart_baud0"; + }; diff --git a/Documentation/devicetree/bindings/clock/exynos5440-clock.txt b/Documentation/devicetree/bindings/clock/exynos5440-clock.txt new file mode 100644 index 000000000000..4499e9966bc9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/exynos5440-clock.txt @@ -0,0 +1,61 @@ +* Samsung Exynos5440 Clock Controller + +The Exynos5440 clock controller generates and supplies clock to various +controllers within the Exynos5440 SoC. + +Required Properties: + +- comptible: should be "samsung,exynos5440-clock". + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +The following is the list of clocks generated by the controller. Each clock is +assigned an identifier and client nodes use this identifier to specify the +clock which they consume. + + + [Core Clocks] + + Clock ID + ---------------------------- + + xtal 1 + arm_clk 2 + + [Peripheral Clock Gates] + + Clock ID + ---------------------------- + + spi_baud 16 + pb0_250 17 + pr0_250 18 + pr1_250 19 + b_250 20 + b_125 21 + b_200 22 + sata 23 + usb 24 + gmac0 25 + cs250 26 + pb0_250_o 27 + pr0_250_o 28 + pr1_250_o 29 + b_250_o 30 + b_125_o 31 + b_200_o 32 + sata_o 33 + usb_o 34 + gmac0_o 35 + cs250_o 36 + +Example: An example of a clock controller node is listed below. + + clock: clock-controller@0x10010000 { + compatible = "samsung,exynos5440-clock"; + reg = <0x160000 0x10000>; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt new file mode 100644 index 000000000000..d6cb083b90a2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt @@ -0,0 +1,303 @@ +NVIDIA Tegra114 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,tegra114-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 160 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 unassigned + 1 unassigned + 2 unassigned + 3 unassigned + 4 rtc + 5 timer + 6 uarta + 7 unassigned (register bit affects uartb and vfir) + 8 unassigned + 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 unassigned + + 32 unassigned + 33 unassigned + 34 apbdma + 35 unassigned + 36 kbc + 37 unassigned + 38 unassigned + 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 + 50 mipi + 51 hdmi + 52 csi + 53 unassigned + 54 i2c2 + 55 uartc + 56 mipi-cal + 57 emc + 58 usb2 + 59 usb3 + 60 msenc + 61 vde + 62 bsea + 63 bsev + + 64 unassigned + 65 uartd + 66 unassigned + 67 i2c3 + 68 sbc4 + 69 sdmmc3 + 70 unassigned + 71 owr + 72 afi + 73 csite + 74 unassigned + 75 unassigned + 76 la + 77 trace + 78 soc_therm + 79 dtv + 80 ndspeed + 81 i2cslow + 82 dsib + 83 tsec + 84 unassigned + 85 unassigned + 86 unassigned + 87 unassigned + 88 unassigned + 89 xusb_host + 90 unassigned + 91 msenc + 92 csus + 93 unassigned + 94 unassigned + 95 unassigned (bit affects xusb_dev and xusb_dev_src) + + 96 unassigned + 97 unassigned + 98 unassigned + 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 unassigned + 113 audio0_2x + 114 audio1_2x + 115 audio2_2x + 116 audio3_2x + 117 audio4_2x + 118 spdif_2x + 119 actmon + 120 extern1 + 121 extern2 + 122 extern3 + 123 unassigned + 124 unassigned + 125 hda + 126 unassigned + 127 se + + 128 hda2hdmi + 129 unassigned + 130 unassigned + 131 unassigned + 132 unassigned + 133 unassigned + 134 unassigned + 135 unassigned + 136 unassigned + 137 unassigned + 138 unassigned + 139 unassigned + 140 unassigned + 141 unassigned + 142 unassigned + 143 unassigned (bit affects xusb_falcon_src, xusb_fs_src, + xusb_host_src and xusb_ss_src) + 144 cilab + 145 cilcd + 146 cile + 147 dsialp + 148 dsiblp + 149 unassigned + 150 dds + 151 unassigned + 152 dp2 + 153 amx + 154 adx + 155 unassigned (bit affects dfll_ref and dfll_soc) + 156 xusb_ss + + 192 uartb + 193 vfir + 194 spdif_in + 195 spdif_out + 196 vi + 197 vi_sensor + 198 fuse + 199 fuse_burn + 200 clk_32k + 201 clk_m + 202 clk_m_div2 + 203 clk_m_div4 + 204 pll_ref + 205 pll_c + 206 pll_c_out1 + 207 pll_c2 + 208 pll_c3 + 209 pll_m + 210 pll_m_out1 + 211 pll_p + 212 pll_p_out1 + 213 pll_p_out2 + 214 pll_p_out3 + 215 pll_p_out4 + 216 pll_a + 217 pll_a_out0 + 218 pll_d + 219 pll_d_out0 + 220 pll_d2 + 221 pll_d2_out0 + 222 pll_u + 223 pll_u_480M + 224 pll_u_60M + 225 pll_u_48M + 226 pll_u_12M + 227 pll_x + 228 pll_x_out0 + 229 pll_re_vco + 230 pll_re_out + 231 pll_e_out0 + 232 spdif_in_sync + 233 i2s0_sync + 234 i2s1_sync + 235 i2s2_sync + 236 i2s3_sync + 237 i2s4_sync + 238 vimclk_sync + 239 audio0 + 240 audio1 + 241 audio2 + 242 audio3 + 243 audio4 + 244 spdif + 245 clk_out_1 + 246 clk_out_2 + 247 clk_out_3 + 248 blink + 252 xusb_host_src + 253 xusb_falcon_src + 254 xusb_fs_src + 255 xusb_ss_src + 256 xusb_dev_src + 257 xusb_dev + 258 xusb_hs_src + 259 sclk + 260 hclk + 261 pclk + 262 cclk_g + 263 cclk_lp + 264 dfll_ref + 265 dfll_soc + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra114-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,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt index 0921fac73528..e885680f6b45 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt @@ -120,8 +120,8 @@ Required properties : 90 clk_d 91 unassigned 92 sus - 93 cdev1 - 94 cdev2 + 93 cdev2 + 94 cdev1 95 unassigned 96 uart2 diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt new file mode 100644 index 000000000000..20b8479c2760 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -0,0 +1,44 @@ +Device Tree Clock bindings for arch-sunxi + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "allwinner,sun4i-osc-clk" - for a gatable oscillator + "allwinner,sun4i-pll1-clk" - for the main PLL clock + "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock + "allwinner,sun4i-axi-clk" - for the AXI clock + "allwinner,sun4i-ahb-clk" - for the AHB clock + "allwinner,sun4i-apb0-clk" - for the APB0 clock + "allwinner,sun4i-apb1-clk" - for the APB1 clock + "allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing + +Required properties for all clocks: +- reg : shall be the control register address for the clock. +- clocks : shall be the input parent clock(s) phandle for the clock +- #clock-cells : from common clock binding; shall be set to 0. + +For example: + +osc24M: osc24M@01c20050 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-osc-clk"; + reg = <0x01c20050 0x4>; + clocks = <&osc24M_fixed>; +}; + +pll1: pll1@01c20000 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-pll1-clk"; + reg = <0x01c20000 0x4>; + clocks = <&osc24M>; +}; + +cpu: cpu@01c20054 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-cpu-clk"; + reg = <0x01c20054 0x4>; + clocks = <&osc32k>, <&osc24M>, <&pll1>; +}; diff --git a/Documentation/devicetree/bindings/gpio/gpio-vt8500.txt b/Documentation/devicetree/bindings/gpio/gpio-vt8500.txt deleted file mode 100644 index f4dc5233167e..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio-vt8500.txt +++ /dev/null @@ -1,24 +0,0 @@ -VIA/Wondermedia VT8500 GPIO Controller ------------------------------------------------------ - -Required properties: -- compatible : "via,vt8500-gpio", "wm,wm8505-gpio" - or "wm,wm8650-gpio" depending on your SoC -- reg : Should contain 1 register range (address and length) -- #gpio-cells : should be <3>. - 1) bank - 2) pin number - 3) flags - should be 0 - -Example: - - gpio: gpio-controller@d8110000 { - compatible = "via,vt8500-gpio"; - gpio-controller; - reg = <0xd8110000 0x10000>; - #gpio-cells = <3>; - }; - - vibrate { - gpios = <&gpio 0 1 0>; /* Bank 0, Pin 1, No flags */ - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt new file mode 100644 index 000000000000..c54c5a9a2a90 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt @@ -0,0 +1,53 @@ +Samsung S3C24XX Interrupt Controllers + +The S3C24XX SoCs contain a custom set of interrupt controllers providing a +varying number of interrupt sources. The set consists of a main- and sub- +controller and on newer SoCs even a second main controller. + +Required properties: +- compatible: Compatible property value should be "samsung,s3c2410-irq" + for machines before s3c2416 and "samsung,s3c2416-irq" for s3c2416 and later. + +- reg: Physical base address of the controller and length of memory mapped + region. + +- interrupt-controller : Identifies the node as an interrupt controller + +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 4 and interrupt descriptor shall + have the following format: + <ctrl_num parent_irq ctrl_irq type> + + ctrl_num contains the controller to use: + - 0 ... main controller + - 1 ... sub controller + - 2 ... second main controller on s3c2416 and s3c2450 + parent_irq contains the parent bit in the main controller and will be + ignored in main controllers + ctrl_irq contains the interrupt bit of the controller + type contains the trigger type to use + +Example: + + interrupt-controller@4a000000 { + compatible = "samsung,s3c2410-irq"; + reg = <0x4a000000 0x100>; + interrupt-controller; + #interrupt-cells=<4>; + }; + + [...] + + serial@50000000 { + compatible = "samsung,s3c2410-uart"; + reg = <0x50000000 0x4000>; + interrupt-parent = <&subintc>; + interrupts = <1 28 0 4>, <1 28 1 4>; + }; + + rtc@57000000 { + compatible = "samsung,s3c2410-rtc"; + reg = <0x57000000 0x100>; + interrupt-parent = <&intc>; + interrupts = <0 30 0 3>, <0 8 0 3>; + }; diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 67ec3d4ccc7f..bf0182d8da25 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -21,3 +21,24 @@ Required properties: - samsung,mfc-l : Base address of the second memory bank used by MFC for DMA contiguous memory allocation and its size. + +Optional properties: + - samsung,power-domain : power-domain property defined with a phandle + to respective power domain. + +Example: +SoC specific DT entry: + +mfc: codec@13400000 { + compatible = "samsung,mfc-v5"; + reg = <0x13400000 0x10000>; + interrupts = <0 94 0>; + samsung,power-domain = <&pd_mfc>; +}; + +Board specific DT entry: + +codec@13400000 { + samsung,mfc-r = <0x43000000 0x800000>; + samsung,mfc-l = <0x51000000 0x800000>; +}; diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nor.txt b/Documentation/devicetree/bindings/mtd/gpmc-nor.txt new file mode 100644 index 000000000000..420b3ab18890 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/gpmc-nor.txt @@ -0,0 +1,98 @@ +Device tree bindings for NOR flash connect to TI GPMC + +NOR flash connected to the TI GPMC (found on OMAP boards) are represented as +child nodes of the GPMC controller with a name of "nor". + +All timing relevant properties as well as generic GPMC child properties are +explained in a separate documents. Please refer to +Documentation/devicetree/bindings/bus/ti-gpmc.txt + +Required properties: +- bank-width: Width of NOR flash in bytes. GPMC supports 8-bit and + 16-bit devices and so must be either 1 or 2 bytes. +- compatible: Documentation/devicetree/bindings/mtd/mtd-physmap.txt +- gpmc,cs-on-ns: Chip-select assertion time +- gpmc,cs-rd-off-ns: Chip-select de-assertion time for reads +- gpmc,cs-wr-off-ns: Chip-select de-assertion time for writes +- gpmc,oe-on-ns: Output-enable assertion time +- gpmc,oe-off-ns: Output-enable de-assertion time +- gpmc,we-on-ns Write-enable assertion time +- gpmc,we-off-ns: Write-enable de-assertion time +- gpmc,access-ns: Start cycle to first data capture (read access) +- gpmc,rd-cycle-ns: Total read cycle time +- gpmc,wr-cycle-ns: Total write cycle time +- linux,mtd-name: Documentation/devicetree/bindings/mtd/mtd-physmap.txt +- reg: Chip-select, base address (relative to chip-select) + and size of NOR flash. Note that base address will be + typically 0 as this is the start of the chip-select. + +Optional properties: +- gpmc,XXX Additional GPMC timings and settings parameters. See + Documentation/devicetree/bindings/bus/ti-gpmc.txt + +Optional properties for partiton table parsing: +- #address-cells: should be set to 1 +- #size-cells: should be set to 1 + +Example: + +gpmc: gpmc@6e000000 { + compatible = "ti,omap3430-gpmc", "simple-bus"; + ti,hwmods = "gpmc"; + reg = <0x6e000000 0x1000>; + interrupts = <20>; + gpmc,num-cs = <8>; + gpmc,num-waitpins = <4>; + #address-cells = <2>; + #size-cells = <1>; + + ranges = <0 0 0x10000000 0x08000000>; + + nor@0,0 { + compatible = "cfi-flash"; + linux,mtd-name= "intel,pf48f6000m0y1be"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0 0 0x08000000>; + bank-width = <2>; + + gpmc,mux-add-data; + gpmc,cs-on-ns = <0>; + gpmc,cs-rd-off-ns = <186>; + gpmc,cs-wr-off-ns = <186>; + gpmc,adv-on-ns = <12>; + gpmc,adv-rd-off-ns = <48>; + gpmc,adv-wr-off-ns = <48>; + gpmc,oe-on-ns = <54>; + gpmc,oe-off-ns = <168>; + gpmc,we-on-ns = <54>; + gpmc,we-off-ns = <168>; + gpmc,rd-cycle-ns = <186>; + gpmc,wr-cycle-ns = <186>; + gpmc,access-ns = <114>; + gpmc,page-burst-access-ns = <6>; + gpmc,bus-turnaround-ns = <12>; + gpmc,cycle2cycle-delay-ns = <18>; + gpmc,wr-data-mux-bus-ns = <90>; + gpmc,wr-access-ns = <186>; + gpmc,cycle2cycle-samecsen; + gpmc,cycle2cycle-diffcsen; + + partition@0 { + label = "bootloader-nor"; + reg = <0 0x40000>; + }; + partition@0x40000 { + label = "params-nor"; + reg = <0x40000 0x40000>; + }; + partition@0x80000 { + label = "kernel-nor"; + reg = <0x80000 0x200000>; + }; + partition@0x280000 { + label = "filesystem-nor"; + reg = <0x240000 0x7d80000>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt index deec9da224a2..b7529424ac88 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt @@ -10,6 +10,8 @@ Documentation/devicetree/bindings/bus/ti-gpmc.txt Required properties: - reg: The CS line the peripheral is connected to + - gpmc,device-width Width of the ONENAND device connected to the GPMC + in bytes. Must be 1 or 2. Optional properties: @@ -34,6 +36,7 @@ Example for an OMAP3430 board: onenand@0 { reg = <0 0 0>; /* CS0, offset 0 */ + gpmc,device-width = <2>; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/net/gpmc-eth.txt b/Documentation/devicetree/bindings/net/gpmc-eth.txt new file mode 100644 index 000000000000..24cb4e46f675 --- /dev/null +++ b/Documentation/devicetree/bindings/net/gpmc-eth.txt @@ -0,0 +1,97 @@ +Device tree bindings for Ethernet chip connected to TI GPMC + +Besides being used to interface with external memory devices, the +General-Purpose Memory Controller can be used to connect Pseudo-SRAM devices +such as ethernet controllers to processors using the TI GPMC as a data bus. + +Ethernet controllers connected to TI GPMC are represented as child nodes of +the GPMC controller with an "ethernet" name. + +All timing relevant properties as well as generic GPMC child properties are +explained in a separate documents. Please refer to +Documentation/devicetree/bindings/bus/ti-gpmc.txt + +For the properties relevant to the ethernet controller connected to the GPMC +refer to the binding documentation of the device. For example, the documentation +for the SMSC 911x is Documentation/devicetree/bindings/net/smsc911x.txt + +Child nodes need to specify the GPMC bus address width using the "bank-width" +property but is possible that an ethernet controller also has a property to +specify the I/O registers address width. Even when the GPMC has a maximum 16-bit +address width, it supports devices with 32-bit word registers. +For example with an SMSC LAN911x/912x controller connected to the TI GPMC on an +OMAP2+ board, "bank-width = <2>;" and "reg-io-width = <4>;". + +Required properties: +- bank-width: Address width of the device in bytes. GPMC supports 8-bit + and 16-bit devices and so must be either 1 or 2 bytes. +- compatible: Compatible string property for the ethernet child device. +- gpmc,cs-on: Chip-select assertion time +- gpmc,cs-rd-off: Chip-select de-assertion time for reads +- gpmc,cs-wr-off: Chip-select de-assertion time for writes +- gpmc,oe-on: Output-enable assertion time +- gpmc,oe-off Output-enable de-assertion time +- gpmc,we-on: Write-enable assertion time +- gpmc,we-off: Write-enable de-assertion time +- gpmc,access: Start cycle to first data capture (read access) +- gpmc,rd-cycle: Total read cycle time +- gpmc,wr-cycle: Total write cycle time +- reg: Chip-select, base address (relative to chip-select) + and size of the memory mapped for the device. + Note that base address will be typically 0 as this + is the start of the chip-select. + +Optional properties: +- gpmc,XXX Additional GPMC timings and settings parameters. See + Documentation/devicetree/bindings/bus/ti-gpmc.txt + +Example: + +gpmc: gpmc@6e000000 { + compatible = "ti,omap3430-gpmc"; + ti,hwmods = "gpmc"; + reg = <0x6e000000 0x1000>; + interrupts = <20>; + gpmc,num-cs = <8>; + gpmc,num-waitpins = <4>; + #address-cells = <2>; + #size-cells = <1>; + + ranges = <5 0 0x2c000000 0x1000000>; + + ethernet@5,0 { + compatible = "smsc,lan9221", "smsc,lan9115"; + reg = <5 0 0xff>; + bank-width = <2>; + + gpmc,mux-add-data; + gpmc,cs-on = <0>; + gpmc,cs-rd-off = <186>; + gpmc,cs-wr-off = <186>; + gpmc,adv-on = <12>; + gpmc,adv-rd-off = <48>; + gpmc,adv-wr-off = <48>; + gpmc,oe-on = <54>; + gpmc,oe-off = <168>; + gpmc,we-on = <54>; + gpmc,we-off = <168>; + gpmc,rd-cycle = <186>; + gpmc,wr-cycle = <186>; + gpmc,access = <114>; + gpmc,page-burst-access = <6>; + gpmc,bus-turnaround = <12>; + gpmc,cycle2cycle-delay = <18>; + gpmc,wr-data-mux-bus = <90>; + gpmc,wr-access = <186>; + gpmc,cycle2cycle-samecsen; + gpmc,cycle2cycle-diffcsen; + + interrupt-parent = <&gpio6>; + interrupts = <16>; + vmmc-supply = <&vddvario>; + vmmc_aux-supply = <&vdd33a>; + reg-io-width = <4>; + + smsc,save-mac-address; + }; +}; diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-vt8500.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-vt8500.txt new file mode 100644 index 000000000000..b3aa90f0ce44 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-vt8500.txt @@ -0,0 +1,57 @@ +VIA VT8500 and Wondermedia WM8xxx-series pinmux/gpio controller + +These SoCs contain a combined Pinmux/GPIO module. Each pin may operate as +either a GPIO in, GPIO out or as an alternate function (I2C, SPI etc). + +Required properties: +- compatible: "via,vt8500-pinctrl", "wm,wm8505-pinctrl", "wm,wm8650-pinctrl", + "wm8750-pinctrl" or "wm,wm8850-pinctrl" +- reg: Should contain the physical address of the module's registers. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters. + bit 0 - active low + +Please refer to ../gpio/gpio.txt for a general description of GPIO bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Each pin configuration node lists the pin(s) to which it applies, and one or +more of the mux functions to select on those pin(s), and pull-up/down +configuration. Each subnode only affects those parameters that are explicitly +listed. In other words, a subnode that lists only a mux function implies no +information about any pull configuration. Similarly, a subnode that lists only +a pull parameter implies no information about the mux function. + +Required subnode-properties: +- wm,pins: An array of cells. Each cell contains the ID of a pin. + +Optional subnode-properties: +- wm,function: Integer, containing the function to mux to the pin(s): + 0: GPIO in + 1: GPIO out + 2: alternate + +- wm,pull: Integer, representing the pull-down/up to apply to the pin(s): + 0: none + 1: down + 2: up + +Each of wm,function and wm,pull may contain either a single value which +will be applied to all pins in wm,pins, or one value for each entry in +wm,pins. + +Example: + + pinctrl: pinctrl { + compatible = "wm,wm8505-pinctrl"; + reg = <0xD8110000 0x10000>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt b/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt new file mode 100644 index 000000000000..993695c659e1 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt @@ -0,0 +1,17 @@ +Cadence TTC - Triple Timer Counter + +Required properties: +- compatible : Should be "cdns,ttc". +- reg : Specifies base physical address and size of the registers. +- interrupts : A list of 3 interrupts; one per timer channel. +- clocks: phandle to the source clock + +Example: + +ttc0: ttc0@f8001000 { + interrupt-parent = <&intc>; + interrupts = < 0 10 4 0 11 4 0 12 4 >; + compatible = "cdns,ttc"; + reg = <0xF8001000 0x1000>; + clocks = <&cpu_clk 3>; +}; diff --git a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt new file mode 100644 index 000000000000..cb47bfbcaeea --- /dev/null +++ b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt @@ -0,0 +1,68 @@ +Samsung's Multi Core Timer (MCT) + +The Samsung's Multi Core Timer (MCT) module includes two main blocks, the +global timer and CPU local timers. The global timer is a 64-bit free running +up-counter and can generate 4 interrupts when the counter reaches one of the +four preset counter values. The CPU local timers are 32-bit free running +down-counters and generate an interrupt when the counter expires. There is +one CPU local timer instantiated in MCT for every CPU in the system. + +Required properties: + +- compatible: should be "samsung,exynos4210-mct". + (a) "samsung,exynos4210-mct", for mct compatible with Exynos4210 mct. + (b) "samsung,exynos4412-mct", for mct compatible with Exynos4412 mct. + +- reg: base address of the mct controller and length of the address space + it occupies. + +- interrupts: the list of interrupts generated by the controller. The following + should be the order of the interrupts specified. The local timer interrupts + should be specified after the four global timer interrupts have been + specified. + + 0: Global Timer Interrupt 0 + 1: Global Timer Interrupt 1 + 2: Global Timer Interrupt 2 + 3: Global Timer Interrupt 3 + 4: Local Timer Interrupt 0 + 5: Local Timer Interrupt 1 + 6: .. + 7: .. + i: Local Timer Interrupt n + +Example 1: In this example, the system uses only the first global timer + interrupt generated by MCT and the remaining three global timer + interrupts are unused. Two local timer interrupts have been + specified. + + mct@10050000 { + compatible = "samsung,exynos4210-mct"; + reg = <0x10050000 0x800>; + interrupts = <0 57 0>, <0 0 0>, <0 0 0>, <0 0 0>, + <0 42 0>, <0 48 0>; + }; + +Example 2: In this example, the MCT global and local timer interrupts are + connected to two seperate interrupt controllers. Hence, an + interrupt-map is created to map the interrupts to the respective + interrupt controllers. + + mct@101C0000 { + compatible = "samsung,exynos4210-mct"; + reg = <0x101C0000 0x800>; + interrupt-controller; + #interrups-cells = <2>; + interrupt-parent = <&mct_map>; + interrupts = <0 0>, <1 0>, <2 0>, <3 0>, + <4 0>, <5 0>; + + mct_map: mct-map { + #interrupt-cells = <2>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = <0x0 0 &combiner 23 3>, + <0x4 0 &gic 0 120 0>, + <0x5 0 &gic 0 121 0>; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt new file mode 100644 index 000000000000..f66fcddba46f --- /dev/null +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt @@ -0,0 +1,40 @@ +Samsung Exynos SoC USB controller + +The USB devices interface with USB controllers on Exynos SOCs. +The device node has following properties. + +EHCI +Required properties: + - compatible: should be "samsung,exynos4210-ehci" for USB 2.0 + EHCI controller in host mode. + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + +Optional properties: + - samsung,vbus-gpio: if present, specifies the GPIO that + needs to be pulled up for the bus to be powered. + +Example: + + usb@12110000 { + compatible = "samsung,exynos4210-ehci"; + reg = <0x12110000 0x100>; + interrupts = <0 71 0>; + samsung,vbus-gpio = <&gpx2 6 1 3 3>; + }; + +OHCI +Required properties: + - compatible: should be "samsung,exynos4210-ohci" for USB 2.0 + OHCI companion controller in host mode. + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + +Example: + usb@12120000 { + compatible = "samsung,exynos4210-ohci"; + reg = <0x12120000 0x100>; + interrupts = <0 71 0>; + }; diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt index f2a2488f1bf3..9573d0c48c6e 100644 --- a/Documentation/networking/ipvs-sysctl.txt +++ b/Documentation/networking/ipvs-sysctl.txt @@ -15,6 +15,13 @@ amemthresh - INTEGER enabled and the variable is automatically set to 2, otherwise the strategy is disabled and the variable is set to 1. +backup_only - BOOLEAN + 0 - disabled (default) + not 0 - enabled + + If set, disable the director function while the server is + in backup mode to avoid packet loops for DR/TUN methods. + conntrack - BOOLEAN 0 - disabled (default) not 0 - enabled diff --git a/MAINTAINERS b/MAINTAINERS index 4cf5fd334a06..74e58a4d035b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3242,6 +3242,12 @@ F: Documentation/firmware_class/ F: drivers/base/firmware*.c F: include/linux/firmware.h +FLASHSYSTEM DRIVER (IBM FlashSystem 70/80 PCI SSD Flash Card) +M: Joshua Morris <josh.h.morris@us.ibm.com> +M: Philip Kelleher <pjk1939@linux.vnet.ibm.com> +S: Maintained +F: drivers/block/rsxx/ + FLOPPY DRIVER M: Jiri Kosina <jkosina@suse.cz> T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy.git @@ -5683,7 +5689,7 @@ S: Maintained F: arch/arm/*omap*/*clock* OMAP POWER MANAGEMENT SUPPORT -M: Kevin Hilman <khilman@ti.com> +M: Kevin Hilman <khilman@deeprootsystems.com> L: linux-omap@vger.kernel.org S: Maintained F: arch/arm/*omap*/*pm* @@ -5777,7 +5783,7 @@ F: arch/arm/*omap*/usb* OMAP GPIO DRIVER M: Santosh Shilimkar <santosh.shilimkar@ti.com> -M: Kevin Hilman <khilman@ti.com> +M: Kevin Hilman <khilman@deeprootsystems.com> L: linux-omap@vger.kernel.org S: Maintained F: drivers/gpio/gpio-omap.c @@ -6209,7 +6215,7 @@ F: include/linux/power_supply.h F: drivers/power/ PNP SUPPORT -M: Adam Belay <abelay@mit.edu> +M: Rafael J. Wysocki <rafael.j.wysocki@intel.com> M: Bjorn Helgaas <bhelgaas@google.com> S: Maintained F: drivers/pnp/ @@ -6551,12 +6557,6 @@ S: Maintained F: Documentation/blockdev/ramdisk.txt F: drivers/block/brd.c -RAMSAM DRIVER (IBM RamSan 70/80 PCI SSD Flash Card) -M: Joshua Morris <josh.h.morris@us.ibm.com> -M: Philip Kelleher <pjk1939@linux.vnet.ibm.com> -S: Maintained -F: drivers/block/rsxx/ - RANDOM NUMBER DRIVER M: Theodore Ts'o" <tytso@mit.edu> S: Maintained @@ -7173,7 +7173,7 @@ F: arch/arm/mach-s3c2410/bast-irq.c TI DAVINCI MACHINE SUPPORT M: Sekhar Nori <nsekhar@ti.com> -M: Kevin Hilman <khilman@ti.com> +M: Kevin Hilman <khilman@deeprootsystems.com> L: davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers) T: git git://gitorious.org/linux-davinci/linux-davinci.git Q: http://patchwork.kernel.org/project/linux-davinci/list/ @@ -7706,9 +7706,10 @@ F: include/linux/swiotlb.h SYNOPSYS ARC ARCHITECTURE M: Vineet Gupta <vgupta@synopsys.com> -L: linux-snps-arc@vger.kernel.org S: Supported F: arch/arc/ +F: Documentation/devicetree/bindings/arc/ +F: drivers/tty/serial/arc-uart.c SYSV FILESYSTEM M: Christoph Hellwig <hch@infradead.org> @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 9 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Unicycling Gorilla # *DOCUMENTATION* diff --git a/arch/arc/include/asm/dma-mapping.h b/arch/arc/include/asm/dma-mapping.h index 31f77aec0823..45b8e0cea176 100644 --- a/arch/arc/include/asm/dma-mapping.h +++ b/arch/arc/include/asm/dma-mapping.h @@ -126,7 +126,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int i; for_each_sg(sg, s, nents, i) - sg->dma_address = dma_map_page(dev, sg_page(s), s->offset, + s->dma_address = dma_map_page(dev, sg_page(s), s->offset, s->length, dir); return nents; diff --git a/arch/arc/include/asm/elf.h b/arch/arc/include/asm/elf.h index f4c8d36ebecb..a26282857683 100644 --- a/arch/arc/include/asm/elf.h +++ b/arch/arc/include/asm/elf.h @@ -72,7 +72,4 @@ extern int elf_check_arch(const struct elf32_hdr *); */ #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) \ - set_personality(PER_LINUX | (current->personality & (~PER_MASK))) - #endif diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h index 23daa326fc9b..eb2ae53187d9 100644 --- a/arch/arc/include/asm/entry.h +++ b/arch/arc/include/asm/entry.h @@ -415,7 +415,7 @@ *-------------------------------------------------------------*/ .macro SAVE_ALL_EXCEPTION marker - st \marker, [sp, 8] + st \marker, [sp, 8] /* orig_r8 */ st r0, [sp, 4] /* orig_r0, needed only for sys calls */ /* Restore r9 used to code the early prologue */ diff --git a/arch/arc/include/asm/kgdb.h b/arch/arc/include/asm/kgdb.h index f3c4934f0ca9..4930957ca3d3 100644 --- a/arch/arc/include/asm/kgdb.h +++ b/arch/arc/include/asm/kgdb.h @@ -13,7 +13,7 @@ #ifdef CONFIG_KGDB -#include <asm/user.h> +#include <asm/ptrace.h> /* to ensure compatibility with Linux 2.6.35, we don't implement the get/set * register API yet */ @@ -53,9 +53,7 @@ enum arc700_linux_regnums { }; #else -static inline void kgdb_trap(struct pt_regs *regs, int param) -{ -} +#define kgdb_trap(regs, param) #endif #endif /* __ARC_KGDB_H__ */ diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 8ae783d20a81..6179de7e07c2 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -123,7 +123,7 @@ static inline long regs_return_value(struct pt_regs *regs) #define orig_r8_IS_SCALL 0x0001 #define orig_r8_IS_SCALL_RESTARTED 0x0002 #define orig_r8_IS_BRKPT 0x0004 -#define orig_r8_IS_EXCPN 0x0004 +#define orig_r8_IS_EXCPN 0x0008 #define orig_r8_IS_IRQ1 0x0010 #define orig_r8_IS_IRQ2 0x0020 diff --git a/arch/arc/include/asm/syscalls.h b/arch/arc/include/asm/syscalls.h index e53a5340ba4f..dd785befe7fd 100644 --- a/arch/arc/include/asm/syscalls.h +++ b/arch/arc/include/asm/syscalls.h @@ -16,8 +16,6 @@ #include <linux/types.h> int sys_clone_wrapper(int, int, int, int, int); -int sys_fork_wrapper(void); -int sys_vfork_wrapper(void); int sys_cacheflush(uint32_t, uint32_t uint32_t); int sys_arc_settls(void *); int sys_arc_gettls(void); diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h index 6afa4f702075..30333cec0fef 100644 --- a/arch/arc/include/uapi/asm/ptrace.h +++ b/arch/arc/include/uapi/asm/ptrace.h @@ -28,14 +28,14 @@ */ struct user_regs_struct { - struct scratch { + struct { long pad; long bta, lp_start, lp_end, lp_count; long status32, ret, blink, fp, gp; long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0; long sp; } scratch; - struct callee { + struct { long pad; long r25, r24, r23, r22, r21, r20; long r19, r18, r17, r16, r15, r14, r13; diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S index ef6800ba2f03..91eeab81f52d 100644 --- a/arch/arc/kernel/entry.S +++ b/arch/arc/kernel/entry.S @@ -452,7 +452,7 @@ tracesys: ; using ERET won't work since next-PC has already committed lr r12, [efa] GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11 - st r12, [r11, THREAD_FAULT_ADDR] + st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address ; PRE Sys Call Ptrace hook mov r0, sp ; pt_regs needed @@ -792,31 +792,6 @@ ARC_EXIT ret_from_fork ;################### Special Sys Call Wrappers ########################## -; TBD: call do_fork directly from here -ARC_ENTRY sys_fork_wrapper - SAVE_CALLEE_SAVED_USER - bl @sys_fork - DISCARD_CALLEE_SAVED_USER - - GET_CURR_THR_INFO_FLAGS r10 - btst r10, TIF_SYSCALL_TRACE - bnz tracesys_exit - - b ret_from_system_call -ARC_EXIT sys_fork_wrapper - -ARC_ENTRY sys_vfork_wrapper - SAVE_CALLEE_SAVED_USER - bl @sys_vfork - DISCARD_CALLEE_SAVED_USER - - GET_CURR_THR_INFO_FLAGS r10 - btst r10, TIF_SYSCALL_TRACE - bnz tracesys_exit - - b ret_from_system_call -ARC_EXIT sys_vfork_wrapper - ARC_ENTRY sys_clone_wrapper SAVE_CALLEE_SAVED_USER bl @sys_clone diff --git a/arch/arc/kernel/kgdb.c b/arch/arc/kernel/kgdb.c index 2888ba5be47e..52bdc83c1495 100644 --- a/arch/arc/kernel/kgdb.c +++ b/arch/arc/kernel/kgdb.c @@ -9,6 +9,7 @@ */ #include <linux/kgdb.h> +#include <linux/sched.h> #include <asm/disasm.h> #include <asm/cacheflush.h> diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index dc0f968dae0a..2d95ac07df7b 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -232,10 +232,8 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len) n += scnprintf(buf + n, len - n, "\n"); -#ifdef _ASM_GENERIC_UNISTD_H n += scnprintf(buf + n, len - n, - "OS ABI [v2]\t: asm-generic/{unistd,stat,fcntl}\n"); -#endif + "OS ABI [v3]\t: no-legacy-syscalls\n"); return buf; } diff --git a/arch/arc/kernel/sys.c b/arch/arc/kernel/sys.c index f6bdd07583f3..9d6c1ca26af6 100644 --- a/arch/arc/kernel/sys.c +++ b/arch/arc/kernel/sys.c @@ -6,8 +6,6 @@ #include <asm/syscalls.h> #define sys_clone sys_clone_wrapper -#define sys_fork sys_fork_wrapper -#define sys_vfork sys_vfork_wrapper #undef __SYSCALL #define __SYSCALL(nr, call) [nr] = (call), diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 13b739469c51..ccb6c0c71521 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -673,6 +673,7 @@ config ARCH_TEGRA select HAVE_CLK select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 + select SOC_BUS select SPARSE_IRQ select USE_OF help @@ -769,12 +770,15 @@ config ARCH_SA1100 config ARCH_S3C24XX bool "Samsung S3C24XX SoCs" select ARCH_HAS_CPUFREQ - select ARCH_USES_GETTIMEOFFSET + select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP + select CLKSRC_MMIO + select GENERIC_CLOCKEVENTS select HAVE_CLK select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_WATCHDOG if WATCHDOG select HAVE_S3C_RTC if RTC_CLASS + select MULTI_IRQ_HANDLER select NEED_MACH_GPIO_H select NEED_MACH_IO_H help @@ -787,10 +791,11 @@ config ARCH_S3C64XX bool "Samsung S3C64XX" select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB - select ARCH_USES_GETTIMEOFFSET select ARM_VIC select CLKDEV_LOOKUP + select CLKSRC_MMIO select CPU_V6 + select GENERIC_CLOCKEVENTS select HAVE_CLK select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_WATCHDOG if WATCHDOG @@ -824,9 +829,11 @@ config ARCH_S5P64X0 config ARCH_S5PC100 bool "Samsung S5PC100" - select ARCH_USES_GETTIMEOFFSET + select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP + select CLKSRC_MMIO select CPU_V7 + select GENERIC_CLOCKEVENTS select HAVE_CLK select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_WATCHDOG if WATCHDOG @@ -859,6 +866,7 @@ config ARCH_EXYNOS select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_SPARSEMEM_ENABLE select CLKDEV_LOOKUP + select COMMON_CLK select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_CLK @@ -1593,6 +1601,7 @@ config HAVE_ARM_ARCH_TIMER config HAVE_ARM_TWD bool depends on SMP + select CLKSRC_OF if OF help This options enables support for the ARM timer and watchdog unit @@ -1646,7 +1655,7 @@ config LOCAL_TIMERS bool "Use local timer interrupts" depends on SMP default y - select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT) + select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !CLKSRC_EXYNOS_MCT) help Enable support for local timers on SMP platforms, rather then the legacy IPI broadcast method. Local timers allows the system @@ -1661,7 +1670,8 @@ config ARCH_NR_GPIO default 1024 if ARCH_SHMOBILE || ARCH_TEGRA default 512 if SOC_OMAP5 default 355 if ARCH_U8500 - default 288 if ARCH_VT8500 || ARCH_SUNXI + default 352 if ARCH_VT8500 + default 288 if ARCH_SUNXI default 264 if MACH_H4700 default 0 help diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index ecfcdba2d17c..9b31f4311ea2 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -495,6 +495,7 @@ config DEBUG_IMX_UART_PORT DEBUG_IMX53_UART || \ DEBUG_IMX6Q_UART default 1 + depends on ARCH_MXC help Choose UART port on which kernel low-level debug messages should be output. diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 9c6255884cbb..d3cd880d70b3 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -42,7 +42,10 @@ dtb-$(CONFIG_ARCH_DOVE) += dove-cm-a510.dtb \ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \ exynos4210-smdkv310.dtb \ exynos4210-trats.dtb \ + exynos4412-odroidx.dtb \ exynos4412-smdk4412.dtb \ + exynos4412-origen.dtb \ + exynos5250-arndale.dtb \ exynos5250-smdk5250.dtb \ exynos5250-snow.dtb \ exynos5440-ssdk5440.dtb diff --git a/arch/arm/boot/dts/cros5250-common.dtsi b/arch/arm/boot/dts/cros5250-common.dtsi index 46c098017036..62eceb4f0d3f 100644 --- a/arch/arm/boot/dts/cros5250-common.dtsi +++ b/arch/arm/boot/dts/cros5250-common.dtsi @@ -24,6 +24,144 @@ samsung,i2c-max-bus-freq = <378000>; gpios = <&gpb3 0 2 3 0>, <&gpb3 1 2 3 0>; + + max77686@09 { + compatible = "maxim,max77686"; + reg = <0x09>; + + voltage-regulators { + ldo1_reg: LDO1 { + regulator-name = "P1.0V_LDO_OUT1"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + ldo2_reg: LDO2 { + regulator-name = "P1.8V_LDO_OUT2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo3_reg: LDO3 { + regulator-name = "P1.8V_LDO_OUT3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo7_reg: LDO7 { + regulator-name = "P1.1V_LDO_OUT7"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + ldo8_reg: LDO8 { + regulator-name = "P1.0V_LDO_OUT8"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + ldo10_reg: LDO10 { + regulator-name = "P1.8V_LDO_OUT10"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo12_reg: LDO12 { + regulator-name = "P3.0V_LDO_OUT12"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + ldo14_reg: LDO14 { + regulator-name = "P1.8V_LDO_OUT14"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo15_reg: LDO15 { + regulator-name = "P1.0V_LDO_OUT15"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + ldo16_reg: LDO16 { + regulator-name = "P1.8V_LDO_OUT16"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + buck3_reg: BUCK3 { + regulator-name = "vdd_int"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + buck4_reg: BUCK4 { + regulator-name = "vdd_g3d"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + }; + + buck5_reg: BUCK5 { + regulator-name = "P1.8V_BUCK_OUT5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + buck6_reg: BUCK6 { + regulator-name = "P1.35V_BUCK_OUT6"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + buck7_reg: BUCK7 { + regulator-name = "P2.0V_BUCK_OUT7"; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-always-on; + }; + + buck8_reg: BUCK8 { + regulator-name = "P2.85V_BUCK_OUT8"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-always-on; + }; + }; + }; }; i2c@12C70000 { diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 1a62bcf18aa3..9ac47d51c407 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -86,6 +86,8 @@ compatible = "samsung,s3c2410-wdt"; reg = <0x10060000 0x100>; interrupts = <0 43 0>; + clocks = <&clock 345>; + clock-names = "watchdog"; status = "disabled"; }; @@ -93,6 +95,8 @@ compatible = "samsung,s3c6410-rtc"; reg = <0x10070000 0x100>; interrupts = <0 44 0>, <0 45 0>; + clocks = <&clock 346>; + clock-names = "rtc"; status = "disabled"; }; @@ -100,6 +104,8 @@ compatible = "samsung,s5pv210-keypad"; reg = <0x100A0000 0x100>; interrupts = <0 109 0>; + clocks = <&clock 347>; + clock-names = "keypad"; status = "disabled"; }; @@ -107,6 +113,8 @@ compatible = "samsung,exynos4210-sdhci"; reg = <0x12510000 0x100>; interrupts = <0 73 0>; + clocks = <&clock 297>, <&clock 145>; + clock-names = "hsmmc", "mmc_busclk.2"; status = "disabled"; }; @@ -114,6 +122,8 @@ compatible = "samsung,exynos4210-sdhci"; reg = <0x12520000 0x100>; interrupts = <0 74 0>; + clocks = <&clock 298>, <&clock 146>; + clock-names = "hsmmc", "mmc_busclk.2"; status = "disabled"; }; @@ -121,6 +131,8 @@ compatible = "samsung,exynos4210-sdhci"; reg = <0x12530000 0x100>; interrupts = <0 75 0>; + clocks = <&clock 299>, <&clock 147>; + clock-names = "hsmmc", "mmc_busclk.2"; status = "disabled"; }; @@ -128,6 +140,16 @@ compatible = "samsung,exynos4210-sdhci"; reg = <0x12540000 0x100>; interrupts = <0 76 0>; + clocks = <&clock 300>, <&clock 148>; + clock-names = "hsmmc", "mmc_busclk.2"; + status = "disabled"; + }; + + mfc: codec@13400000 { + compatible = "samsung,mfc-v5"; + reg = <0x13400000 0x10000>; + interrupts = <0 94 0>; + samsung,power-domain = <&pd_mfc>; status = "disabled"; }; @@ -135,6 +157,8 @@ compatible = "samsung,exynos4210-uart"; reg = <0x13800000 0x100>; interrupts = <0 52 0>; + clocks = <&clock 312>, <&clock 151>; + clock-names = "uart", "clk_uart_baud0"; status = "disabled"; }; @@ -142,6 +166,8 @@ compatible = "samsung,exynos4210-uart"; reg = <0x13810000 0x100>; interrupts = <0 53 0>; + clocks = <&clock 313>, <&clock 152>; + clock-names = "uart", "clk_uart_baud0"; status = "disabled"; }; @@ -149,6 +175,8 @@ compatible = "samsung,exynos4210-uart"; reg = <0x13820000 0x100>; interrupts = <0 54 0>; + clocks = <&clock 314>, <&clock 153>; + clock-names = "uart", "clk_uart_baud0"; status = "disabled"; }; @@ -156,6 +184,8 @@ compatible = "samsung,exynos4210-uart"; reg = <0x13830000 0x100>; interrupts = <0 55 0>; + clocks = <&clock 315>, <&clock 154>; + clock-names = "uart", "clk_uart_baud0"; status = "disabled"; }; @@ -165,6 +195,8 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x13860000 0x100>; interrupts = <0 58 0>; + clocks = <&clock 317>; + clock-names = "i2c"; status = "disabled"; }; @@ -174,6 +206,8 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x13870000 0x100>; interrupts = <0 59 0>; + clocks = <&clock 318>; + clock-names = "i2c"; status = "disabled"; }; @@ -183,6 +217,8 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x13880000 0x100>; interrupts = <0 60 0>; + clocks = <&clock 319>; + clock-names = "i2c"; status = "disabled"; }; @@ -192,6 +228,8 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x13890000 0x100>; interrupts = <0 61 0>; + clocks = <&clock 320>; + clock-names = "i2c"; status = "disabled"; }; @@ -201,6 +239,8 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x138A0000 0x100>; interrupts = <0 62 0>; + clocks = <&clock 321>; + clock-names = "i2c"; status = "disabled"; }; @@ -210,6 +250,8 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x138B0000 0x100>; interrupts = <0 63 0>; + clocks = <&clock 322>; + clock-names = "i2c"; status = "disabled"; }; @@ -219,6 +261,8 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x138C0000 0x100>; interrupts = <0 64 0>; + clocks = <&clock 323>; + clock-names = "i2c"; status = "disabled"; }; @@ -228,6 +272,8 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x138D0000 0x100>; interrupts = <0 65 0>; + clocks = <&clock 324>; + clock-names = "i2c"; status = "disabled"; }; @@ -239,6 +285,8 @@ rx-dma-channel = <&pdma0 6>; /* preliminary */ #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 327>, <&clock 159>; + clock-names = "spi", "spi_busclk0"; status = "disabled"; }; @@ -250,6 +298,8 @@ rx-dma-channel = <&pdma1 6>; /* preliminary */ #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 328>, <&clock 160>; + clock-names = "spi", "spi_busclk0"; status = "disabled"; }; @@ -261,6 +311,8 @@ rx-dma-channel = <&pdma0 8>; /* preliminary */ #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 329>, <&clock 161>; + clock-names = "spi", "spi_busclk0"; status = "disabled"; }; @@ -275,6 +327,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x12680000 0x1000>; interrupts = <0 35 0>; + clocks = <&clock 292>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <32>; @@ -284,6 +338,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x12690000 0x1000>; interrupts = <0 36 0>; + clocks = <&clock 293>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <32>; @@ -293,6 +349,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x12850000 0x1000>; interrupts = <0 34 0>; + clocks = <&clock 279>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <1>; diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts index f2710018e84e..1b30bc8e2654 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts +++ b/arch/arm/boot/dts/exynos4210-origen.dts @@ -57,6 +57,12 @@ status = "okay"; }; + codec@13400000 { + samsung,mfc-r = <0x43000000 0x800000>; + samsung,mfc-l = <0x51000000 0x800000>; + status = "okay"; + }; + serial@13800000 { status = "okay"; }; @@ -121,4 +127,16 @@ linux,default-trigger = "heartbeat"; }; }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <0>; + }; + + xusbxti { + compatible = "samsung,clock-xusbxti"; + clock-frequency = <24000000>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts index f63490707f3a..f52c86e2d424 100644 --- a/arch/arm/boot/dts/exynos4210-smdkv310.dts +++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts @@ -43,6 +43,12 @@ status = "okay"; }; + codec@13400000 { + samsung,mfc-r = <0x43000000 0x800000>; + samsung,mfc-l = <0x51000000 0x800000>; + status = "okay"; + }; + serial@13800000 { status = "okay"; }; @@ -189,4 +195,16 @@ }; }; }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <12000000>; + }; + + xusbxti { + compatible = "samsung,clock-xusbxti"; + clock-frequency = <24000000>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts index c346b64dff55..9a14484c7bb1 100644 --- a/arch/arm/boot/dts/exynos4210-trats.dts +++ b/arch/arm/boot/dts/exynos4210-trats.dts @@ -289,4 +289,16 @@ }; }; }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <0>; + }; + + xusbxti { + compatible = "samsung,clock-xusbxti"; + clock-frequency = <24000000>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index 2feffc70814c..15143bdbafb8 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -47,6 +47,42 @@ <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>; }; + mct@10050000 { + compatible = "samsung,exynos4210-mct"; + reg = <0x10050000 0x800>; + interrupt-controller; + #interrups-cells = <2>; + interrupt-parent = <&mct_map>; + interrupts = <0 0>, <1 0>, <2 0>, <3 0>, + <4 0>, <5 0>; + clocks = <&clock 3>, <&clock 344>; + clock-names = "fin_pll", "mct"; + + mct_map: mct-map { + #interrupt-cells = <2>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = <0x0 0 &gic 0 57 0>, + <0x1 0 &gic 0 69 0>, + <0x2 0 &combiner 12 6>, + <0x3 0 &combiner 12 7>, + <0x4 0 &gic 0 42 0>, + <0x5 0 &gic 0 48 0>; + }; + }; + + clock: clock-controller@0x10030000 { + compatible = "samsung,exynos4210-clock"; + reg = <0x10030000 0x20000>; + #clock-cells = <1>; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&combiner>; + interrupts = <2 2>, <3 2>; + }; + pinctrl_0: pinctrl@11400000 { compatible = "samsung,exynos4210-pinctrl"; reg = <0x11400000 0x1000>; diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi index c6ae2005961f..36d4299789ef 100644 --- a/arch/arm/boot/dts/exynos4212.dtsi +++ b/arch/arm/boot/dts/exynos4212.dtsi @@ -25,4 +25,26 @@ gic:interrupt-controller@10490000 { cpu-offset = <0x8000>; }; + + mct@10050000 { + compatible = "samsung,exynos4412-mct"; + reg = <0x10050000 0x800>; + interrupt-controller; + #interrups-cells = <2>; + interrupt-parent = <&mct_map>; + interrupts = <0 0>, <1 0>, <2 0>, <3 0>, + <4 0>, <5 0>; + + mct_map: mct-map { + #interrupt-cells = <2>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = <0x0 0 &gic 0 57 0>, + <0x1 0 &combiner 12 5>, + <0x2 0 &combiner 12 6>, + <0x3 0 &combiner 12 7>, + <0x4 0 &gic 1 12 0>, + <0x5 0 &gic 1 12 0>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts new file mode 100644 index 000000000000..53bc8bf77984 --- /dev/null +++ b/arch/arm/boot/dts/exynos4412-odroidx.dts @@ -0,0 +1,111 @@ +/* + * Hardkernel's Exynos4412 based ODROID-X board device tree source + * + * Copyright (c) 2012 Dongjin Kim <tobetter@gmail.com> + * + * Device tree source file for Hardkernel's ODROID-X board which is based on + * Samsung's Exynos4412 SoC. + * + * 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. +*/ + +/dts-v1/; +/include/ "exynos4412.dtsi" + +/ { + model = "Hardkernel ODROID-X board based on Exynos4412"; + compatible = "hardkernel,odroid-x", "samsung,exynos4412"; + + memory { + reg = <0x40000000 0x40000000>; + }; + + leds { + compatible = "gpio-leds"; + led1 { + label = "led1:heart"; + gpios = <&gpc1 0 1>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + led2 { + label = "led2:mmc0"; + gpios = <&gpc1 2 1>; + default-state = "on"; + linux,default-trigger = "mmc0"; + }; + }; + + mshc@12550000 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>; + pinctrl-names = "default"; + status = "okay"; + + num-slots = <1>; + supports-highspeed; + broken-cd; + fifo-depth = <0x80>; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + + slot@0 { + reg = <0>; + bus-width = <8>; + }; + }; + + regulator_p3v3 { + compatible = "regulator-fixed"; + regulator-name = "p3v3_en"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpa1 1 1>; + enable-active-high; + regulator-boot-on; + }; + + rtc@10070000 { + status = "okay"; + }; + + sdhci@12530000 { + bus-width = <4>; + pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>; + pinctrl-names = "default"; + status = "okay"; + }; + + serial@13800000 { + status = "okay"; + }; + + serial@13810000 { + status = "okay"; + }; + + serial@13820000 { + status = "okay"; + }; + + serial@13830000 { + status = "okay"; + }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <0>; + }; + + xusbxti { + compatible = "samsung,clock-xusbxti"; + clock-frequency = <24000000>; + }; + }; +}; diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts new file mode 100644 index 000000000000..1fecf7666dc0 --- /dev/null +++ b/arch/arm/boot/dts/exynos4412-origen.dts @@ -0,0 +1,432 @@ +/* + * Insignal's Exynos4412 based Origen board device tree source + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Device tree source file for Insignal's Origen board which is based on + * Samsung's Exynos4412 SoC. + * + * 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. +*/ + +/dts-v1/; +/include/ "exynos4412.dtsi" + +/ { + model = "Insignal Origen evaluation board based on Exynos4412"; + compatible = "insignal,origen4412", "samsung,exynos4412"; + + memory { + reg = <0x40000000 0x40000000>; + }; + + chosen { + bootargs ="console=ttySAC2,115200"; + }; + + mmc_reg: voltage-regulator { + compatible = "regulator-fixed"; + regulator-name = "VMEM_VDD_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + gpio = <&gpx1 1 0>; + enable-active-high; + }; + + sdhci@12530000 { + bus-width = <4>; + pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd2_cd>; + pinctrl-names = "default"; + vmmc-supply = <&mmc_reg>; + status = "okay"; + }; + + mshc@12550000 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>; + pinctrl-names = "default"; + status = "okay"; + + num-slots = <1>; + supports-highspeed; + broken-cd; + fifo-depth = <0x80>; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + + slot@0 { + reg = <0>; + bus-width = <8>; + }; + }; + + codec@13400000 { + samsung,mfc-r = <0x43000000 0x800000>; + samsung,mfc-l = <0x51000000 0x800000>; + status = "okay"; + }; + + serial@13800000 { + status = "okay"; + }; + + serial@13810000 { + status = "okay"; + }; + + serial@13820000 { + status = "okay"; + }; + + serial@13830000 { + status = "okay"; + }; + + i2c@13860000 { + #address-cells = <1>; + #size-cells = <0>; + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <20000>; + pinctrl-0 = <&i2c0_bus>; + pinctrl-names = "default"; + status = "okay"; + + s5m8767_pmic@66 { + compatible = "samsung,s5m8767-pmic"; + reg = <0x66>; + + s5m8767,pmic-buck-default-dvs-idx = <3>; + + s5m8767,pmic-buck-dvs-gpios = <&gpx2 3 0>, + <&gpx2 4 0>, + <&gpx2 5 0>; + + s5m8767,pmic-buck-ds-gpios = <&gpm3 5 0>, + <&gpm3 6 0>, + <&gpm3 7 0>; + + s5m8767,pmic-buck2-dvs-voltage = <1250000>, <1200000>, + <1200000>, <1200000>, + <1200000>, <1200000>, + <1200000>, <1200000>; + + s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>, + <1100000>, <1100000>, + <1100000>, <1100000>, + <1100000>, <1100000>; + + s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>, + <1200000>, <1200000>, + <1200000>, <1200000>, + <1200000>, <1200000>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ALIVE"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo2_reg: LDO2 { + regulator-name = "VDDQ_M12"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo3_reg: LDO3 { + regulator-name = "VDDIOAP_18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo4_reg: LDO4 { + regulator-name = "VDDQ_PRE"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo5_reg: LDO5 { + regulator-name = "VDD18_2M"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo6_reg: LDO6 { + regulator-name = "VDD10_MPLL"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo7_reg: LDO7 { + regulator-name = "VDD10_XPLL"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo8_reg: LDO8 { + regulator-name = "VDD10_MIPI"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo9_reg: LDO9 { + regulator-name = "VDD33_LCD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo10_reg: LDO10 { + regulator-name = "VDD18_MIPI"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo11_reg: LDO11 { + regulator-name = "VDD18_ABB1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo12_reg: LDO12 { + regulator-name = "VDD33_UOTG"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo13_reg: LDO13 { + regulator-name = "VDDIOPERI_18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo14_reg: LDO14 { + regulator-name = "VDD18_ABB02"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo15_reg: LDO15 { + regulator-name = "VDD10_USH"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo16_reg: LDO16 { + regulator-name = "VDD18_HSIC"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo17_reg: LDO17 { + regulator-name = "VDDIOAP_MMC012_28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo18_reg: LDO18 { + regulator-name = "VDDIOPERI_28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo19_reg: LDO19 { + regulator-name = "DVDD25"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo20_reg: LDO20 { + regulator-name = "VDD28_CAM"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo21_reg: LDO21 { + regulator-name = "VDD28_AF"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo22_reg: LDO22 { + regulator-name = "VDDA28_2M"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo23_reg: LDO23 { + regulator-name = "VDD28_TF"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo24_reg: LDO24 { + regulator-name = "VDD33_A31"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo25_reg: LDO25 { + regulator-name = "VDD18_CAM"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo26_reg: LDO26 { + regulator-name = "VDD18_A31"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo27_reg: LDO27 { + regulator-name = "GPS_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo28_reg: LDO28 { + regulator-name = "DVDD12"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck3_reg: BUCK3 { + regulator-name = "vdd_int"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck4_reg: BUCK4 { + regulator-name = "vdd_g3d"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck5_reg: BUCK5 { + regulator-name = "vdd_m12"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck6_reg: BUCK6 { + regulator-name = "vdd12_5m"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck9_reg: BUCK9 { + regulator-name = "vddf28_emmc"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + }; + }; + }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <0>; + }; + + xusbxti { + compatible = "samsung,clock-xusbxti"; + clock-frequency = <24000000>; + }; + }; +}; diff --git a/arch/arm/boot/dts/exynos4412-smdk4412.dts b/arch/arm/boot/dts/exynos4412-smdk4412.dts index f05bf575cc45..874beeaef99d 100644 --- a/arch/arm/boot/dts/exynos4412-smdk4412.dts +++ b/arch/arm/boot/dts/exynos4412-smdk4412.dts @@ -27,6 +27,19 @@ bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc"; }; + sdhci@12530000 { + bus-width = <4>; + pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd2_cd>; + pinctrl-names = "default"; + status = "okay"; + }; + + codec@13400000 { + samsung,mfc-r = <0x43000000 0x800000>; + samsung,mfc-l = <0x51000000 0x800000>; + status = "okay"; + }; + serial@13800000 { status = "okay"; }; @@ -42,4 +55,16 @@ serial@13830000 { status = "okay"; }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <0>; + }; + + xusbxti { + compatible = "samsung,clock-xusbxti"; + clock-frequency = <24000000>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index d7dfe312772a..d75c047e80a9 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi @@ -25,4 +25,30 @@ gic:interrupt-controller@10490000 { cpu-offset = <0x4000>; }; + + mct@10050000 { + compatible = "samsung,exynos4412-mct"; + reg = <0x10050000 0x800>; + interrupt-controller; + #interrups-cells = <2>; + interrupt-parent = <&mct_map>; + interrupts = <0 0>, <1 0>, <2 0>, <3 0>, + <4 0>, <5 0>, <6 0>, <7 0>; + clocks = <&clock 3>, <&clock 344>; + clock-names = "fin_pll", "mct"; + + mct_map: mct-map { + #interrupt-cells = <2>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = <0x0 0 &gic 0 57 0>, + <0x1 0 &combiner 12 5>, + <0x2 0 &combiner 12 6>, + <0x3 0 &combiner 12 7>, + <0x4 0 &gic 1 12 0>, + <0x5 0 &gic 1 12 0>, + <0x6 0 &gic 1 12 0>, + <0x7 0 &gic 1 12 0>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi index 9a8780694909..7496b8d633ea 100644 --- a/arch/arm/boot/dts/exynos4x12.dtsi +++ b/arch/arm/boot/dts/exynos4x12.dtsi @@ -36,6 +36,12 @@ <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>; }; + clock: clock-controller@0x10030000 { + compatible = "samsung,exynos4412-clock"; + reg = <0x10030000 0x20000>; + #clock-cells = <1>; + }; + pinctrl_0: pinctrl@11400000 { compatible = "samsung,exynos4x12-pinctrl"; reg = <0x11400000 0x1000>; diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts new file mode 100644 index 000000000000..5de019cb0e58 --- /dev/null +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -0,0 +1,129 @@ +/* + * Samsung's Exynos5250 based Arndale board device tree source + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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. +*/ + +/dts-v1/; +/include/ "exynos5250.dtsi" + +/ { + model = "Insignal Arndale evaluation board based on EXYNOS5250"; + compatible = "insignal,arndale", "samsung,exynos5250"; + + memory { + reg = <0x40000000 0x80000000>; + }; + + chosen { + bootargs = "console=ttySAC2,115200"; + }; + + i2c@12C60000 { + status = "disabled"; + }; + + i2c@12C70000 { + status = "disabled"; + }; + + i2c@12C80000 { + status = "disabled"; + }; + + i2c@12C90000 { + status = "disabled"; + }; + + i2c@12CA0000 { + status = "disabled"; + }; + + i2c@12CB0000 { + status = "disabled"; + }; + + i2c@12CC0000 { + status = "disabled"; + }; + + i2c@12CD0000 { + status = "disabled"; + }; + + i2c@121D0000 { + status = "disabled"; + }; + + dwmmc_0: dwmmc0@12200000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + fifo-depth = <0x80>; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + + slot@0 { + reg = <0>; + bus-width = <8>; + gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>, + <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>, + <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>, + <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>, + <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>; + }; + }; + + dwmmc_1: dwmmc1@12210000 { + status = "disabled"; + }; + + dwmmc_2: dwmmc2@12220000 { + num-slots = <1>; + supports-highspeed; + fifo-depth = <0x80>; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + + slot@0 { + reg = <0>; + bus-width = <4>; + samsung,cd-pinmux-gpio = <&gpc3 2 2 3 3>; + gpios = <&gpc3 0 2 0 3>, <&gpc3 1 2 0 3>, + <&gpc3 3 2 3 3>, <&gpc3 4 2 3 3>, + <&gpc3 5 2 3 3>, <&gpc3 6 2 3 3>; + }; + }; + + dwmmc_3: dwmmc3@12230000 { + status = "disabled"; + }; + + spi_0: spi@12d20000 { + status = "disabled"; + }; + + spi_1: spi@12d30000 { + status = "disabled"; + }; + + spi_2: spi@12d40000 { + status = "disabled"; + }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <24000000>; + }; + }; +}; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 1b8d4106d338..872ae1f93c75 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -231,4 +231,24 @@ samsung,i2s-controller = <&i2s0>; samsung,audio-codec = <&wm8994>; }; + + usb@12110000 { + samsung,vbus-gpio = <&gpx2 6 1 3 3>; + }; + + dp-controller { + samsung,color-space = <0>; + samsung,dynamic-range = <0>; + samsung,ycbcr-coeff = <0>; + samsung,color-depth = <1>; + samsung,link-rate = <0x0a>; + samsung,lane-count = <4>; + }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <24000000>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index 17dd951c1cd2..babd9f9b1bf9 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -40,4 +40,15 @@ <&gpc4 5 2 3 0>, <&gpc4 6 2 3 0>; }; }; + + usb@12110000 { + samsung,vbus-gpio = <&gpx1 1 1 3 3>; + }; + + fixed-rate-clocks { + xxti { + compatible = "samsung,clock-xxti"; + clock-frequency = <24000000>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index b1ac73e21c80..24c52e681b58 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -46,6 +46,22 @@ i2c8 = &i2c_8; }; + pd_gsc: gsc-power-domain@0x10044000 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10044000 0x20>; + }; + + pd_mfc: mfc-power-domain@0x10044040 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10044040 0x20>; + }; + + clock: clock-controller@0x10010000 { + compatible = "samsung,exynos5250-clock"; + reg = <0x10010000 0x30000>; + #clock-cells = <1>; + }; + gic:interrupt-controller@10481000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; @@ -69,58 +85,105 @@ <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>; }; + mct@101C0000 { + compatible = "samsung,exynos4210-mct"; + reg = <0x101C0000 0x800>; + interrupt-controller; + #interrups-cells = <2>; + interrupt-parent = <&mct_map>; + interrupts = <0 0>, <1 0>, <2 0>, <3 0>, + <4 0>, <5 0>; + clocks = <&clock 1>, <&clock 335>; + clock-names = "fin_pll", "mct"; + + mct_map: mct-map { + #interrupt-cells = <2>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = <0x0 0 &combiner 23 3>, + <0x1 0 &combiner 23 4>, + <0x2 0 &combiner 25 2>, + <0x3 0 &combiner 25 3>, + <0x4 0 &gic 0 120 0>, + <0x5 0 &gic 0 121 0>; + }; + }; + + pmu { + compatible = "arm,cortex-a15-pmu"; + interrupt-parent = <&combiner>; + interrupts = <1 2>, <22 4>; + }; + watchdog { compatible = "samsung,s3c2410-wdt"; reg = <0x101D0000 0x100>; interrupts = <0 42 0>; + clocks = <&clock 336>; + clock-names = "watchdog"; }; codec@11000000 { compatible = "samsung,mfc-v6"; reg = <0x11000000 0x10000>; interrupts = <0 96 0>; + samsung,power-domain = <&pd_mfc>; }; rtc { compatible = "samsung,s3c6410-rtc"; reg = <0x101E0000 0x100>; interrupts = <0 43 0>, <0 44 0>; + clocks = <&clock 337>; + clock-names = "rtc"; }; tmu@10060000 { compatible = "samsung,exynos5250-tmu"; reg = <0x10060000 0x100>; interrupts = <0 65 0>; + clocks = <&clock 338>; + clock-names = "tmu_apbif"; }; serial@12C00000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C00000 0x100>; interrupts = <0 51 0>; + clocks = <&clock 289>, <&clock 146>; + clock-names = "uart", "clk_uart_baud0"; }; serial@12C10000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C10000 0x100>; interrupts = <0 52 0>; + clocks = <&clock 290>, <&clock 147>; + clock-names = "uart", "clk_uart_baud0"; }; serial@12C20000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C20000 0x100>; interrupts = <0 53 0>; + clocks = <&clock 291>, <&clock 148>; + clock-names = "uart", "clk_uart_baud0"; }; serial@12C30000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C30000 0x100>; interrupts = <0 54 0>; + clocks = <&clock 292>, <&clock 149>; + clock-names = "uart", "clk_uart_baud0"; }; sata@122F0000 { compatible = "samsung,exynos5-sata-ahci"; reg = <0x122F0000 0x1ff>; interrupts = <0 115 0>; + clocks = <&clock 277>, <&clock 143>; + clock-names = "sata", "sclk_sata"; }; sata-phy@12170000 { @@ -134,6 +197,8 @@ interrupts = <0 56 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 294>; + clock-names = "i2c"; }; i2c_1: i2c@12C70000 { @@ -142,6 +207,8 @@ interrupts = <0 57 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 295>; + clock-names = "i2c"; }; i2c_2: i2c@12C80000 { @@ -150,6 +217,8 @@ interrupts = <0 58 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 296>; + clock-names = "i2c"; }; i2c_3: i2c@12C90000 { @@ -158,6 +227,8 @@ interrupts = <0 59 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 297>; + clock-names = "i2c"; }; i2c_4: i2c@12CA0000 { @@ -166,6 +237,8 @@ interrupts = <0 60 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 298>; + clock-names = "i2c"; }; i2c_5: i2c@12CB0000 { @@ -174,6 +247,8 @@ interrupts = <0 61 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 299>; + clock-names = "i2c"; }; i2c_6: i2c@12CC0000 { @@ -182,6 +257,8 @@ interrupts = <0 62 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 300>; + clock-names = "i2c"; }; i2c_7: i2c@12CD0000 { @@ -190,6 +267,8 @@ interrupts = <0 63 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 301>; + clock-names = "i2c"; }; i2c_8: i2c@12CE0000 { @@ -198,6 +277,8 @@ interrupts = <0 64 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 302>; + clock-names = "i2c"; }; i2c@121D0000 { @@ -205,6 +286,8 @@ reg = <0x121D0000 0x100>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 288>; + clock-names = "i2c"; }; spi_0: spi@12d20000 { @@ -216,6 +299,8 @@ dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 304>, <&clock 154>; + clock-names = "spi", "spi_busclk0"; }; spi_1: spi@12d30000 { @@ -227,6 +312,8 @@ dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 305>, <&clock 155>; + clock-names = "spi", "spi_busclk0"; }; spi_2: spi@12d40000 { @@ -238,6 +325,8 @@ dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 306>, <&clock 156>; + clock-names = "spi", "spi_busclk0"; }; dwmmc_0: dwmmc0@12200000 { @@ -246,6 +335,8 @@ interrupts = <0 75 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 280>, <&clock 139>; + clock-names = "biu", "ciu"; }; dwmmc_1: dwmmc1@12210000 { @@ -254,6 +345,8 @@ interrupts = <0 76 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 281>, <&clock 140>; + clock-names = "biu", "ciu"; }; dwmmc_2: dwmmc2@12220000 { @@ -262,6 +355,8 @@ interrupts = <0 77 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 282>, <&clock 141>; + clock-names = "biu", "ciu"; }; dwmmc_3: dwmmc3@12230000 { @@ -270,6 +365,8 @@ interrupts = <0 78 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 283>, <&clock 142>; + clock-names = "biu", "ciu"; }; i2s0: i2s@03830000 { @@ -301,6 +398,18 @@ dma-names = "tx", "rx"; }; + usb@12110000 { + compatible = "samsung,exynos4210-ehci"; + reg = <0x12110000 0x100>; + interrupts = <0 71 0>; + }; + + usb@12120000 { + compatible = "samsung,exynos4210-ohci"; + reg = <0x12120000 0x100>; + interrupts = <0 71 0>; + }; + amba { #address-cells = <1>; #size-cells = <1>; @@ -312,6 +421,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x121A0000 0x1000>; interrupts = <0 34 0>; + clocks = <&clock 275>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <32>; @@ -321,6 +432,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x121B0000 0x1000>; interrupts = <0 35 0>; + clocks = <&clock 276>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <32>; @@ -330,6 +443,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x10800000 0x1000>; interrupts = <0 33 0>; + clocks = <&clock 271>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <1>; @@ -339,6 +454,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x11C10000 0x1000>; interrupts = <0 124 0>; + clocks = <&clock 271>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <1>; @@ -592,34 +709,51 @@ }; }; + gsc_0: gsc@0x13e00000 { compatible = "samsung,exynos5-gsc"; reg = <0x13e00000 0x1000>; interrupts = <0 85 0>; + samsung,power-domain = <&pd_gsc>; + clocks = <&clock 256>; + clock-names = "gscl"; }; gsc_1: gsc@0x13e10000 { compatible = "samsung,exynos5-gsc"; reg = <0x13e10000 0x1000>; interrupts = <0 86 0>; + samsung,power-domain = <&pd_gsc>; + clocks = <&clock 257>; + clock-names = "gscl"; }; gsc_2: gsc@0x13e20000 { compatible = "samsung,exynos5-gsc"; reg = <0x13e20000 0x1000>; interrupts = <0 87 0>; + samsung,power-domain = <&pd_gsc>; + clocks = <&clock 258>; + clock-names = "gscl"; }; gsc_3: gsc@0x13e30000 { compatible = "samsung,exynos5-gsc"; reg = <0x13e30000 0x1000>; interrupts = <0 88 0>; + samsung,power-domain = <&pd_gsc>; + clocks = <&clock 259>; + clock-names = "gscl"; }; hdmi { compatible = "samsung,exynos5-hdmi"; reg = <0x14530000 0x70000>; interrupts = <0 95 0>; + clocks = <&clock 333>, <&clock 136>, <&clock 137>, + <&clock 333>, <&clock 333>; + clock-names = "hdmi", "sclk_hdmi", "sclk_pixel", + "sclk_hdmiphy", "hdmiphy"; }; mixer { @@ -627,4 +761,18 @@ reg = <0x14450000 0x10000>; interrupts = <0 94 0>; }; + + dp-controller { + compatible = "samsung,exynos5-dp"; + reg = <0x145b0000 0x1000>; + interrupts = <10 3>; + interrupt-parent = <&combiner>; + #address-cells = <1>; + #size-cells = <0>; + + dptx-phy { + reg = <0x10040720>; + samsung,enable-mask = <1>; + }; + }; }; diff --git a/arch/arm/boot/dts/exynos5440-ssdk5440.dts b/arch/arm/boot/dts/exynos5440-ssdk5440.dts index 81e2c964a900..a21eb4cbe893 100644 --- a/arch/arm/boot/dts/exynos5440-ssdk5440.dts +++ b/arch/arm/boot/dts/exynos5440-ssdk5440.dts @@ -28,19 +28,10 @@ status = "disabled"; }; - i2c@F0000 { - status = "disabled"; - }; - - i2c@100000 { - status = "disabled"; - }; - - watchdog { - status = "disabled"; - }; - - rtc { - status = "disabled"; + fixed-rate-clocks { + xtal { + compatible = "samsung,clock-xtal"; + clock-frequency = <50000000>; + }; }; }; diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi index 9a99755920c0..c374a31e9c3d 100644 --- a/arch/arm/boot/dts/exynos5440.dtsi +++ b/arch/arm/boot/dts/exynos5440.dtsi @@ -16,6 +16,12 @@ interrupt-parent = <&gic>; + clock: clock-controller@0x160000 { + compatible = "samsung,exynos5440-clock"; + reg = <0x160000 0x1000>; + #clock-cells = <1>; + }; + gic:interrupt-controller@2E0000 { compatible = "arm,cortex-a15-gic"; #interrupt-cells = <3>; @@ -24,55 +30,51 @@ }; cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { compatible = "arm,cortex-a15"; - timer { - compatible = "arm,armv7-timer"; - interrupts = <1 13 0xf08>; - clock-frequency = <1000000>; - }; + reg = <0>; }; cpu@1 { compatible = "arm,cortex-a15"; - timer { - compatible = "arm,armv7-timer"; - interrupts = <1 14 0xf08>; - clock-frequency = <1000000>; - }; + reg = <1>; }; cpu@2 { compatible = "arm,cortex-a15"; - timer { - compatible = "arm,armv7-timer"; - interrupts = <1 14 0xf08>; - clock-frequency = <1000000>; - }; + reg = <2>; }; cpu@3 { compatible = "arm,cortex-a15"; - timer { - compatible = "arm,armv7-timer"; - interrupts = <1 14 0xf08>; - clock-frequency = <1000000>; - }; + reg = <3>; }; }; - common { - compatible = "samsung,exynos5440"; - + timer { + compatible = "arm,cortex-a15-timer", + "arm,armv7-timer"; + interrupts = <1 13 0xf08>, + <1 14 0xf08>, + <1 11 0xf08>, + <1 10 0xf08>; + clock-frequency = <50000000>; }; serial@B0000 { compatible = "samsung,exynos4210-uart"; reg = <0xB0000 0x1000>; interrupts = <0 2 0>; + clocks = <&clock 21>, <&clock 21>; + clock-names = "uart", "clk_uart_baud0"; }; serial@C0000 { compatible = "samsung,exynos4210-uart"; reg = <0xC0000 0x1000>; interrupts = <0 3 0>; + clocks = <&clock 21>, <&clock 21>; + clock-names = "uart", "clk_uart_baud0"; }; spi { @@ -83,6 +85,8 @@ rx-dma-channel = <&pdma0 4>; /* preliminary */ #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 21>, <&clock 16>; + clock-names = "spi", "spi_busclk0"; }; pinctrl { @@ -110,25 +114,31 @@ }; i2c@F0000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos5440-i2c"; reg = <0xF0000 0x1000>; interrupts = <0 5 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 21>; + clock-names = "i2c"; }; i2c@100000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos5440-i2c"; reg = <0x100000 0x1000>; interrupts = <0 6 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clock 21>; + clock-names = "i2c"; }; watchdog { compatible = "samsung,s3c2410-wdt"; reg = <0x110000 0x1000>; interrupts = <0 1 0>; + clocks = <&clock 21>; + clock-names = "watchdog"; }; amba { @@ -142,6 +152,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x120000 0x1000>; interrupts = <0 34 0>; + clocks = <&clock 21>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <32>; @@ -151,6 +163,8 @@ compatible = "arm,pl330", "arm,primecell"; reg = <0x121000 0x1000>; interrupts = <0 35 0>; + clocks = <&clock 21>; + clock-names = "apb_pclk"; #dma-cells = <1>; #dma-channels = <8>; #dma-requests = <32>; @@ -161,5 +175,7 @@ compatible = "samsung,s3c6410-rtc"; reg = <0x130000 0x1000>; interrupts = <0 17 0>, <0 16 0>; + clocks = <&clock 21>; + clock-names = "rtc"; }; }; diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index f624dc85d441..02d23f15fd86 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -38,6 +38,57 @@ }; }; + /* HS USB Port 2 RESET */ + hsusb2_reset: hsusb2_reset_reg { + compatible = "regulator-fixed"; + regulator-name = "hsusb2_reset"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio5 19 0>; /* gpio_147 */ + startup-delay-us = <70000>; + enable-active-high; + }; + + /* HS USB Port 2 Power */ + hsusb2_power: hsusb2_power_reg { + compatible = "regulator-fixed"; + regulator-name = "hsusb2_vbus"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&twl_gpio 18 0>; /* GPIO LEDA */ + startup-delay-us = <70000>; + }; + + /* HS USB Host PHY on PORT 2 */ + hsusb2_phy: hsusb2_phy { + compatible = "usb-nop-xceiv"; + reset-supply = <&hsusb2_reset>; + vcc-supply = <&hsusb2_power>; + }; +}; + +&omap3_pmx_core { + pinctrl-names = "default"; + pinctrl-0 = < + &hsusbb2_pins + >; + + hsusbb2_pins: pinmux_hsusbb2_pins { + pinctrl-single,pins = < + 0x5c0 0x3 /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_clk OUTPUT */ + 0x5c2 0x3 /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_stp OUTPUT */ + 0x5c4 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dir INPUT | PULLDOWN */ + 0x5c6 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_nxt INPUT | PULLDOWN */ + 0x5c8 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat0 INPUT | PULLDOWN */ + 0x5cA 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat1 INPUT | PULLDOWN */ + 0x1a4 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat2 INPUT | PULLDOWN */ + 0x1a6 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat3 INPUT | PULLDOWN */ + 0x1a8 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat4 INPUT | PULLDOWN */ + 0x1aa 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat5 INPUT | PULLDOWN */ + 0x1ac 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat6 INPUT | PULLDOWN */ + 0x1ae 0x10b /* USBB2_ULPITLL_CLK_MUXMODE.usbb1_ulpiphy_dat7 INPUT | PULLDOWN */ + >; + }; }; &i2c1 { @@ -65,3 +116,23 @@ &mmc3 { status = "disabled"; }; + +&usbhshost { + port2-mode = "ehci-phy"; +}; + +&usbhsehci { + phys = <0 &hsusb2_phy>; +}; + +&twl_gpio { + ti,use-leds; + /* pullups: BIT(1) */ + ti,pullups = <0x000002>; + /* + * pulldowns: + * BIT(2), BIT(6), BIT(7), BIT(8), BIT(13) + * BIT(15), BIT(16), BIT(17) + */ + ti,pulldowns = <0x03a1c4>; +}; diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index 1acc26148ffc..a14f74bbce7c 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -397,5 +397,36 @@ ti,timer-alwon; ti,timer-secure; }; + + usbhstll: usbhstll@48062000 { + compatible = "ti,usbhs-tll"; + reg = <0x48062000 0x1000>; + interrupts = <78>; + ti,hwmods = "usb_tll_hs"; + }; + + usbhshost: usbhshost@48064000 { + compatible = "ti,usbhs-host"; + reg = <0x48064000 0x400>; + ti,hwmods = "usb_host_hs"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + usbhsohci: ohci@48064400 { + compatible = "ti,ohci-omap3", "usb-ohci"; + reg = <0x48064400 0x400>; + interrupt-parent = <&intc>; + interrupts = <76>; + }; + + usbhsehci: ehci@48064800 { + compatible = "ti,ehci-omap", "usb-ehci"; + reg = <0x48064800 0x400>; + interrupt-parent = <&intc>; + interrupts = <77>; + }; + }; + }; }; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 739bb79e410e..b7db1a2b6ca7 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -529,5 +529,35 @@ ti,hwmods = "timer11"; ti,timer-pwm; }; + + usbhstll: usbhstll@4a062000 { + compatible = "ti,usbhs-tll"; + reg = <0x4a062000 0x1000>; + interrupts = <0 78 0x4>; + ti,hwmods = "usb_tll_hs"; + }; + + usbhshost: usbhshost@4a064000 { + compatible = "ti,usbhs-host"; + reg = <0x4a064000 0x800>; + ti,hwmods = "usb_host_hs"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + usbhsohci: ohci@4a064800 { + compatible = "ti,ohci-omap3", "usb-ohci"; + reg = <0x4a064800 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 76 0x4>; + }; + + usbhsehci: ehci@4a064c00 { + compatible = "ti,ehci-omap", "usb-ehci"; + reg = <0x4a064c00 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 77 0x4>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi new file mode 100644 index 000000000000..fe5c6f213271 --- /dev/null +++ b/arch/arm/boot/dts/r8a7779.dtsi @@ -0,0 +1,98 @@ +/* + * Device Tree Source for Renesas r8a7779 + * + * Copyright (C) 2013 Renesas Solutions Corp. + * Copyright (C) 2013 Simon Horman + * + * 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,r8a7779"; + + 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>; + }; + }; + + gic: interrupt-controller@f0001000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0xf0001000 0x1000>, + <0xf0000100 0x100>; + }; + + i2c0: i2c@0xffc70000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xffc70000 0x1000>; + interrupt-parent = <&gic>; + interrupts = <0 79 0x4>; + }; + + i2c1: i2c@0xffc71000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xffc71000 0x1000>; + interrupt-parent = <&gic>; + interrupts = <0 82 0x4>; + }; + + i2c2: i2c@0xffc72000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xffc72000 0x1000>; + interrupt-parent = <&gic>; + interrupts = <0 80 0x4>; + }; + + i2c3: i2c@0xffc73000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0xffc73000 0x1000>; + interrupt-parent = <&gic>; + interrupts = <0 81 0x4>; + }; + + thermal@ffc48000 { + compatible = "renesas,rcar-thermal"; + reg = <0xffc48000 0x38>; + }; + + sata: sata@fc600000 { + compatible = "renesas,rcar-sata"; + reg = <0xfc600000 0x2000>; + interrupt-parent = <&gic>; + interrupts = <0 100 0x4>; + }; +}; diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts index a30aca62658a..616990dc92db 100644 --- a/arch/arm/boot/dts/tegra114-dalmore.dts +++ b/arch/arm/boot/dts/tegra114-dalmore.dts @@ -12,10 +12,22 @@ serial@70006300 { status = "okay"; - clock-frequency = <408000000>; }; pmc { nvidia,invert-interrupt; }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; }; diff --git a/arch/arm/boot/dts/tegra114-pluto.dts b/arch/arm/boot/dts/tegra114-pluto.dts index 9bea8f57aa47..6bbc8efae9c0 100644 --- a/arch/arm/boot/dts/tegra114-pluto.dts +++ b/arch/arm/boot/dts/tegra114-pluto.dts @@ -12,10 +12,22 @@ serial@70006300 { status = "okay"; - clock-frequency = <408000000>; }; pmc { nvidia,invert-interrupt; }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; }; diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 1dfaf2874c57..c1110a9b2a91 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -24,10 +24,11 @@ 0 42 0x04 0 121 0x04 0 122 0x04>; + clocks = <&tegra_car 5>; }; tegra_car: clock { - compatible = "nvidia,tegra114-car, nvidia,tegra30-car"; + compatible = "nvidia,tegra114-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; }; @@ -66,6 +67,7 @@ reg-shift = <2>; interrupts = <0 36 0x04>; status = "disabled"; + clocks = <&tegra_car 6>; }; serial@70006040 { @@ -74,6 +76,7 @@ reg-shift = <2>; interrupts = <0 37 0x04>; status = "disabled"; + clocks = <&tegra_car 192>; }; serial@70006200 { @@ -82,6 +85,7 @@ reg-shift = <2>; interrupts = <0 46 0x04>; status = "disabled"; + clocks = <&tegra_car 55>; }; serial@70006300 { @@ -90,17 +94,21 @@ reg-shift = <2>; interrupts = <0 90 0x04>; status = "disabled"; + clocks = <&tegra_car 65>; }; rtc { compatible = "nvidia,tegra114-rtc", "nvidia,tegra20-rtc"; reg = <0x7000e000 0x100>; interrupts = <0 2 0x04>; + clocks = <&tegra_car 4>; }; pmc { - compatible = "nvidia,tegra114-pmc", "nvidia,tegra30-pmc"; + compatible = "nvidia,tegra114-pmc"; reg = <0x7000e400 0x400>; + clocks = <&tegra_car 261>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; }; iommu { diff --git a/arch/arm/boot/dts/tegra20-colibri-512.dtsi b/arch/arm/boot/dts/tegra20-colibri-512.dtsi index 444162090042..4e3afdef28a8 100644 --- a/arch/arm/boot/dts/tegra20-colibri-512.dtsi +++ b/arch/arm/boot/dts/tegra20-colibri-512.dtsi @@ -444,7 +444,20 @@ }; sdhci@c8000600 { - cd-gpios = <&gpio 23 0>; /* gpio PC7 */ + cd-gpios = <&gpio 23 1>; /* gpio PC7 */ + }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; }; sound { diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index 61d027f03617..ae9d5a20834e 100644 --- a/arch/arm/boot/dts/tegra20-harmony.dts +++ b/arch/arm/boot/dts/tegra20-harmony.dts @@ -437,7 +437,7 @@ sdhci@c8000200 { status = "okay"; - cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + cd-gpios = <&gpio 69 1>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 155 0>; /* gpio PT3 */ bus-width = <4>; @@ -445,12 +445,25 @@ sdhci@c8000600 { status = "okay"; - cd-gpios = <&gpio 58 0>; /* gpio PH2 */ + cd-gpios = <&gpio 58 1>; /* gpio PH2 */ wp-gpios = <&gpio 59 0>; /* gpio PH3 */ power-gpios = <&gpio 70 0>; /* gpio PI6 */ bus-width = <8>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + kbc { status = "okay"; nvidia,debounce-delay-ms = <2>; diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 54d6fce00a59..fd60940e4063 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -436,7 +436,7 @@ sdhci@c8000000 { status = "okay"; - cd-gpios = <&gpio 173 0>; /* gpio PV5 */ + cd-gpios = <&gpio 173 1>; /* gpio PV5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 169 0>; /* gpio PV1 */ bus-width = <4>; @@ -447,6 +447,19 @@ bus-width = <8>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + gpio-keys { compatible = "gpio-keys"; diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index 37b3a57ec0f1..4ee700a33ca5 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts @@ -584,7 +584,7 @@ sdhci@c8000400 { status = "okay"; - cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + cd-gpios = <&gpio 69 1>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 70 0>; /* gpio PI6 */ bus-width = <4>; @@ -595,6 +595,19 @@ bus-width = <8>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + gpio-keys { compatible = "gpio-keys"; diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi index 4766abae7a72..c19025725918 100644 --- a/arch/arm/boot/dts/tegra20-tamonten.dtsi +++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi @@ -465,12 +465,25 @@ }; sdhci@c8000600 { - cd-gpios = <&gpio 58 0>; /* gpio PH2 */ + cd-gpios = <&gpio 58 1>; /* gpio PH2 */ wp-gpios = <&gpio 59 0>; /* gpio PH3 */ bus-width = <4>; status = "okay"; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + regulators { compatible = "simple-bus"; diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts index 5d79e4fc49a6..a9f3f06580f5 100644 --- a/arch/arm/boot/dts/tegra20-trimslice.dts +++ b/arch/arm/boot/dts/tegra20-trimslice.dts @@ -325,11 +325,24 @@ sdhci@c8000600 { status = "okay"; - cd-gpios = <&gpio 121 0>; /* gpio PP1 */ + cd-gpios = <&gpio 121 1>; /* gpio PP1 */ wp-gpios = <&gpio 122 0>; /* gpio PP2 */ bus-width = <4>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + poweroff { compatible = "gpio-poweroff"; gpios = <&gpio 191 1>; /* gpio PX7, active low */ diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts index 425c89000c20..f544806e9618 100644 --- a/arch/arm/boot/dts/tegra20-ventana.dts +++ b/arch/arm/boot/dts/tegra20-ventana.dts @@ -520,7 +520,7 @@ sdhci@c8000400 { status = "okay"; - cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + cd-gpios = <&gpio 69 1>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 70 0>; /* gpio PI6 */ bus-width = <4>; @@ -531,6 +531,19 @@ bus-width = <8>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + regulators { compatible = "simple-bus"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts index ea57c0f6dcce..258cf945f515 100644 --- a/arch/arm/boot/dts/tegra20-whistler.dts +++ b/arch/arm/boot/dts/tegra20-whistler.dts @@ -510,6 +510,7 @@ sdhci@c8000400 { status = "okay"; + cd-gpios = <&gpio 69 1>; /* gpio PI5 */ wp-gpios = <&gpio 173 0>; /* gpio PV5 */ bus-width = <8>; }; @@ -519,6 +520,19 @@ bus-width = <8>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + kbc { status = "okay"; nvidia,debounce-delay-ms = <20>; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 48d00a099ce3..fc7febc2b386 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -145,6 +145,7 @@ 0 1 0x04 0 41 0x04 0 42 0x04>; + clocks = <&tegra_car 5>; }; tegra_car: clock { @@ -304,6 +305,7 @@ compatible = "nvidia,tegra20-rtc"; reg = <0x7000e000 0x100>; interrupts = <0 2 0x04>; + clocks = <&tegra_car 4>; }; i2c@7000c000 { @@ -385,7 +387,7 @@ spi@7000d800 { compatible = "nvidia,tegra20-slink"; - reg = <0x7000d480 0x200>; + reg = <0x7000d800 0x200>; interrupts = <0 83 0x04>; nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; @@ -416,6 +418,8 @@ pmc { compatible = "nvidia,tegra20-pmc"; reg = <0x7000e400 0x400>; + clocks = <&tegra_car 110>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; }; memory-controller@7000f000 { diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts index 8ff2ff20e4a3..6248b2445b32 100644 --- a/arch/arm/boot/dts/tegra30-beaver.dts +++ b/arch/arm/boot/dts/tegra30-beaver.dts @@ -257,7 +257,7 @@ sdhci@78000000 { status = "okay"; - cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + cd-gpios = <&gpio 69 1>; /* gpio PI5 */ wp-gpios = <&gpio 155 0>; /* gpio PT3 */ power-gpios = <&gpio 31 0>; /* gpio PD7 */ bus-width = <4>; @@ -268,6 +268,19 @@ bus-width = <8>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + regulators { compatible = "simple-bus"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index 17499272a4ef..65bf2b63174e 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -311,7 +311,7 @@ sdhci@78000000 { status = "okay"; - cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + cd-gpios = <&gpio 69 1>; /* gpio PI5 */ wp-gpios = <&gpio 155 0>; /* gpio PT3 */ power-gpios = <&gpio 31 0>; /* gpio PD7 */ bus-width = <4>; @@ -322,6 +322,19 @@ bus-width = <8>; }; + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + regulators { compatible = "simple-bus"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 9d87a3ffe998..9fe7a92b4c85 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -148,6 +148,7 @@ 0 42 0x04 0 121 0x04 0 122 0x04>; + clocks = <&tegra_car 5>; }; tegra_car: clock { @@ -291,6 +292,7 @@ compatible = "nvidia,tegra30-rtc", "nvidia,tegra20-rtc"; reg = <0x7000e000 0x100>; interrupts = <0 2 0x04>; + clocks = <&tegra_car 4>; }; i2c@7000c000 { @@ -372,7 +374,7 @@ spi@7000d800 { compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; - reg = <0x7000d480 0x200>; + reg = <0x7000d800 0x200>; interrupts = <0 83 0x04>; nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; @@ -423,8 +425,10 @@ }; pmc { - compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc"; + compatible = "nvidia,tegra30-pmc"; reg = <0x7000e400 0x400>; + clocks = <&tegra_car 218>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; }; memory-controller { diff --git a/arch/arm/boot/dts/vt8500.dtsi b/arch/arm/boot/dts/vt8500.dtsi index cf31ced46602..e1c3926aca52 100644 --- a/arch/arm/boot/dts/vt8500.dtsi +++ b/arch/arm/boot/dts/vt8500.dtsi @@ -25,11 +25,13 @@ #interrupt-cells = <1>; }; - gpio: gpio-controller@d8110000 { - compatible = "via,vt8500-gpio"; - gpio-controller; + pinctrl: pinctrl@d8110000 { + compatible = "via,vt8500-pinctrl"; reg = <0xd8110000 0x10000>; - #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; }; pmc@d8130000 { diff --git a/arch/arm/boot/dts/wm8505.dtsi b/arch/arm/boot/dts/wm8505.dtsi index e74a1c0fb9a2..bb92ef8ce665 100644 --- a/arch/arm/boot/dts/wm8505.dtsi +++ b/arch/arm/boot/dts/wm8505.dtsi @@ -40,11 +40,13 @@ interrupts = <56 57 58 59 60 61 62 63>; }; - gpio: gpio-controller@d8110000 { - compatible = "wm,wm8505-gpio"; - gpio-controller; + pinctrl: pinctrl@d8110000 { + compatible = "wm,wm8505-pinctrl"; reg = <0xd8110000 0x10000>; - #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; }; pmc@d8130000 { diff --git a/arch/arm/boot/dts/wm8650.dtsi b/arch/arm/boot/dts/wm8650.dtsi index db3c0a12e052..bb4af580f40b 100644 --- a/arch/arm/boot/dts/wm8650.dtsi +++ b/arch/arm/boot/dts/wm8650.dtsi @@ -34,11 +34,13 @@ interrupts = <56 57 58 59 60 61 62 63>; }; - gpio: gpio-controller@d8110000 { - compatible = "wm,wm8650-gpio"; - gpio-controller; + pinctrl: pinctrl@d8110000 { + compatible = "wm,wm8650-pinctrl"; reg = <0xd8110000 0x10000>; - #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; }; pmc@d8130000 { diff --git a/arch/arm/boot/dts/wm8850.dtsi b/arch/arm/boot/dts/wm8850.dtsi index e8cbfdc87bba..11cd180c58d3 100644 --- a/arch/arm/boot/dts/wm8850.dtsi +++ b/arch/arm/boot/dts/wm8850.dtsi @@ -41,11 +41,13 @@ interrupts = <56 57 58 59 60 61 62 63>; }; - gpio: gpio-controller@d8110000 { - compatible = "wm,wm8650-gpio"; - gpio-controller; + pinctrl: pinctrl@d8110000 { + compatible = "wm,wm8850-pinctrl"; reg = <0xd8110000 0x10000>; - #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; }; pmc@d8130000 { diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 5914b5654591..51243db2e9e4 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -111,56 +111,23 @@ }; ttc0: ttc0@f8001000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "xlnx,ttc"; + interrupt-parent = <&intc>; + interrupts = < 0 10 4 0 11 4 0 12 4 >; + compatible = "cdns,ttc"; reg = <0xF8001000 0x1000>; clocks = <&cpu_clk 3>; clock-names = "cpu_1x"; clock-ranges; - - ttc0_0: ttc0.0 { - status = "disabled"; - reg = <0>; - interrupts = <0 10 4>; - }; - ttc0_1: ttc0.1 { - status = "disabled"; - reg = <1>; - interrupts = <0 11 4>; - }; - ttc0_2: ttc0.2 { - status = "disabled"; - reg = <2>; - interrupts = <0 12 4>; - }; }; ttc1: ttc1@f8002000 { - #interrupt-parent = <&intc>; - #address-cells = <1>; - #size-cells = <0>; - compatible = "xlnx,ttc"; + interrupt-parent = <&intc>; + interrupts = < 0 37 4 0 38 4 0 39 4 >; + compatible = "cdns,ttc"; reg = <0xF8002000 0x1000>; clocks = <&cpu_clk 3>; clock-names = "cpu_1x"; clock-ranges; - - ttc1_0: ttc1.0 { - status = "disabled"; - reg = <0>; - interrupts = <0 37 4>; - }; - ttc1_1: ttc1.1 { - status = "disabled"; - reg = <1>; - interrupts = <0 38 4>; - }; - ttc1_2: ttc1.2 { - status = "disabled"; - reg = <2>; - interrupts = <0 39 4>; - }; }; }; }; diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts index c772942a399a..86f44d5b0265 100644 --- a/arch/arm/boot/dts/zynq-zc702.dts +++ b/arch/arm/boot/dts/zynq-zc702.dts @@ -32,13 +32,3 @@ &ps_clk { clock-frequency = <33333330>; }; - -&ttc0_0 { - status = "ok"; - compatible = "xlnx,ttc-counter-clocksource"; -}; - -&ttc0_1 { - status = "ok"; - compatible = "xlnx,ttc-counter-clockevent"; -}; diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h index 0f01f4677bd2..7b2899c2f7fc 100644 --- a/arch/arm/include/asm/smp_twd.h +++ b/arch/arm/include/asm/smp_twd.h @@ -34,12 +34,4 @@ struct twd_local_timer name __initdata = { \ int twd_local_timer_register(struct twd_local_timer *); -#ifdef CONFIG_HAVE_ARM_TWD -void twd_local_timer_of_register(void); -#else -static inline void twd_local_timer_of_register(void) -{ -} -#endif - #endif diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 0f82098c9bfe..cd22d821bf74 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -562,21 +562,21 @@ ENDPROC(__und_usr) @ Fall-through from Thumb-2 __und_usr @ #ifdef CONFIG_NEON + get_thread_info r10 @ get current thread adr r6, .LCneon_thumb_opcodes b 2f #endif call_fpe: + get_thread_info r10 @ get current thread #ifdef CONFIG_NEON adr r6, .LCneon_arm_opcodes -2: - ldr r7, [r6], #4 @ mask value - cmp r7, #0 @ end mask? - beq 1f - and r8, r0, r7 +2: ldr r5, [r6], #4 @ mask value ldr r7, [r6], #4 @ opcode bits matching in mask + cmp r5, #0 @ end mask? + beq 1f + and r8, r0, r5 cmp r8, r7 @ NEON instruction? bne 2b - get_thread_info r10 mov r7, #1 strb r7, [r10, #TI_USED_CP + 10] @ mark CP#10 as used strb r7, [r10, #TI_USED_CP + 11] @ mark CP#11 as used @@ -586,7 +586,6 @@ call_fpe: tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 moveq pc, lr - get_thread_info r10 @ get current thread and r8, r0, #0x00000f00 @ mask out CP number THUMB( lsr r8, r8, #8 ) mov r7, #1 diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 047d3e40e470..cbd0f51937cc 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -459,15 +459,16 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) * atomic helpers and the signal restart code. Insert it into the * gate_vma so that it is visible through ptrace and /proc/<pid>/mem. */ -static struct vm_area_struct gate_vma; +static struct vm_area_struct gate_vma = { + .vm_start = 0xffff0000, + .vm_end = 0xffff0000 + PAGE_SIZE, + .vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC, + .vm_mm = &init_mm, +}; static int __init gate_vma_init(void) { - gate_vma.vm_start = 0xffff0000; - gate_vma.vm_end = 0xffff0000 + PAGE_SIZE; - gate_vma.vm_page_prot = PAGE_READONLY_EXEC; - gate_vma.vm_flags = VM_READ | VM_EXEC | - VM_MAYREAD | VM_MAYEXEC; + gate_vma.vm_page_prot = PAGE_READONLY_EXEC; return 0; } arch_initcall(gate_vma_init); diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 3f2565037480..90525d9d290b 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -362,25 +362,13 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt) } #ifdef CONFIG_OF -const static struct of_device_id twd_of_match[] __initconst = { - { .compatible = "arm,cortex-a9-twd-timer", }, - { .compatible = "arm,cortex-a5-twd-timer", }, - { .compatible = "arm,arm11mp-twd-timer", }, - { }, -}; - -void __init twd_local_timer_of_register(void) +static void __init twd_local_timer_of_register(struct device_node *np) { - struct device_node *np; int err; if (!is_smp() || !setup_max_cpus) return; - np = of_find_matching_node(NULL, twd_of_match); - if (!np) - return; - twd_ppi = irq_of_parse_and_map(np, 0); if (!twd_ppi) { err = -EINVAL; @@ -398,4 +386,7 @@ void __init twd_local_timer_of_register(void) out: WARN(err, "twd_local_timer_of_register failed (%d)\n", err); } +CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); #endif diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 2998a08afc2d..0204f4cc9ebf 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -169,6 +169,8 @@ static struct clk *periph_clocks[] __initdata = { }; static struct clk_lookup periph_clocks_lookups[] = { + CLKDEV_CON_DEV_ID("hclk", "at91sam9261-lcdfb.0", &hck1), + CLKDEV_CON_DEV_ID("hclk", "at91sam9g10-lcdfb.0", &hck1), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 92e0f861084a..629ea5fc95cf 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -488,7 +488,6 @@ static struct resource lcdc_resources[] = { }; static struct platform_device at91_lcdc_device = { - .name = "atmel_lcdfb", .id = 0, .dev = { .dma_mask = &lcdc_dmamask, @@ -505,6 +504,11 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) return; } + if (cpu_is_at91sam9g10()) + at91_lcdc_device.name = "at91sam9g10-lcdfb"; + else + at91_lcdc_device.name = "at91sam9261-lcdfb"; + #if defined(CONFIG_FB_ATMEL_STN) at91_set_A_periph(AT91_PIN_PB0, 0); /* LCDVSYNC */ at91_set_A_periph(AT91_PIN_PB1, 0); /* LCDHSYNC */ diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index b9fc60d1b33a..2282fd7ad3e3 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -190,6 +190,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID("pclk", "fff98000.ssc", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc1_clk), + CLKDEV_CON_DEV_ID("hclk", "at91sam9263-lcdfb.0", &lcdc_clk), CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk), CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index ed666f5cb01d..858c8aac2daf 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -848,7 +848,7 @@ static struct resource lcdc_resources[] = { }; static struct platform_device at91_lcdc_device = { - .name = "atmel_lcdfb", + .name = "at91sam9263-lcdfb", .id = 0, .dev = { .dma_mask = &lcdc_dmamask, diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index d3addee43d8d..c68960d82247 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -228,6 +228,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("hclk", &macb_clk), /* One additional fake clock for ohci */ CLKDEV_CON_ID("ohci_clk", &uhphs_clk), + CLKDEV_CON_DEV_ID("hclk", "at91sam9g45-lcdfb.0", &lcdc_clk), + CLKDEV_CON_DEV_ID("hclk", "at91sam9g45es-lcdfb.0", &lcdc_clk), CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci", &uhphs_clk), CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk), CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk), diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 827c9f2a70fb..fe626d431b69 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -981,7 +981,6 @@ static struct resource lcdc_resources[] = { }; static struct platform_device at91_lcdc_device = { - .name = "atmel_lcdfb", .id = 0, .dev = { .dma_mask = &lcdc_dmamask, @@ -997,6 +996,11 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) if (!data) return; + if (cpu_is_at91sam9g45es()) + at91_lcdc_device.name = "at91sam9g45es-lcdfb"; + else + at91_lcdc_device.name = "at91sam9g45-lcdfb"; + at91_set_A_periph(AT91_PIN_PE0, 0); /* LCDDPWR */ at91_set_A_periph(AT91_PIN_PE2, 0); /* LCDCC */ diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index eb98704db2d9..3de3e04d0f81 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -179,6 +179,7 @@ static struct clk *periph_clocks[] __initdata = { }; static struct clk_lookup periph_clocks_lookups[] = { + CLKDEV_CON_DEV_ID("hclk", "at91sam9rl-lcdfb.0", &lcdc_clk), CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk), CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk), CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index ddf223ff35c4..352468f265a9 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -514,7 +514,7 @@ static struct resource lcdc_resources[] = { }; static struct platform_device at91_lcdc_device = { - .name = "atmel_lcdfb", + .name = "at91sam9rl-lcdfb", .id = 0, .dev = { .dma_mask = &lcdc_dmamask, diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 70f94c87479d..ef3b69a6277c 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -61,6 +61,7 @@ config SOC_EXYNOS5250 bool "SAMSUNG EXYNOS5250" default y depends on ARCH_EXYNOS5 + select PM_GENERIC_DOMAINS if PM select S5P_PM if PM select S5P_SLEEP if PM select S5P_DEV_MFC @@ -79,12 +80,6 @@ config SOC_EXYNOS5440 help Enable EXYNOS5440 SoC support -config EXYNOS4_MCT - bool - default y - help - Use MCT (Multi Core Timer) as kernel timers - config EXYNOS_DEV_DMA bool help @@ -276,8 +271,8 @@ config MACH_UNIVERSAL_C210 select S5P_DEV_ONENAND select S5P_DEV_TV select S5P_GPIO_INT - select S5P_HRT select S5P_SETUP_MIPIPHY + select SAMSUNG_HRT help Machine support for Samsung Mobile Universal S5PC210 Reference Board. @@ -406,10 +401,12 @@ config MACH_EXYNOS4_DT bool "Samsung Exynos4 Machine using device tree" depends on ARCH_EXYNOS4 select ARM_AMBA + select CLKSRC_OF select CPU_EXYNOS4210 select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD select PINCTRL select PINCTRL_EXYNOS + select S5P_DEV_MFC select USE_OF help Machine support for Samsung Exynos4 machine with device tree enabled. @@ -422,6 +419,7 @@ config MACH_EXYNOS5_DT default y depends on ARCH_EXYNOS5 select ARM_AMBA + select CLKSRC_OF select USE_OF help Machine support for Samsung EXYNOS5 machine with device tree enabled. diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 435757e57bb4..d2f6b362b6dd 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -13,10 +13,6 @@ obj- := # Core obj-$(CONFIG_ARCH_EXYNOS) += common.o -obj-$(CONFIG_ARCH_EXYNOS4) += clock-exynos4.o -obj-$(CONFIG_CPU_EXYNOS4210) += clock-exynos4210.o -obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o -obj-$(CONFIG_SOC_EXYNOS5250) += clock-exynos5.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o @@ -26,8 +22,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += pmu.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o -obj-$(CONFIG_EXYNOS4_MCT) += mct.o - obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o # machine support diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c deleted file mode 100644 index 8a8468d83c8c..000000000000 --- a/arch/arm/mach-exynos/clock-exynos4.c +++ /dev/null @@ -1,1601 +0,0 @@ -/* - * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS4 - Clock support - * - * 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/kernel.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/syscore_ops.h> - -#include <plat/cpu-freq.h> -#include <plat/clock.h> -#include <plat/cpu.h> -#include <plat/pll.h> -#include <plat/s5p-clock.h> -#include <plat/clock-clksrc.h> -#include <plat/pm.h> - -#include <mach/map.h> -#include <mach/regs-clock.h> - -#include "common.h" -#include "clock-exynos4.h" - -#ifdef CONFIG_PM_SLEEP -static struct sleep_save exynos4_clock_save[] = { - SAVE_ITEM(EXYNOS4_CLKDIV_LEFTBUS), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_LEFTBUS), - SAVE_ITEM(EXYNOS4_CLKDIV_RIGHTBUS), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_RIGHTBUS), - SAVE_ITEM(EXYNOS4_CLKSRC_TOP0), - SAVE_ITEM(EXYNOS4_CLKSRC_TOP1), - SAVE_ITEM(EXYNOS4_CLKSRC_CAM), - SAVE_ITEM(EXYNOS4_CLKSRC_TV), - SAVE_ITEM(EXYNOS4_CLKSRC_MFC), - SAVE_ITEM(EXYNOS4_CLKSRC_G3D), - SAVE_ITEM(EXYNOS4_CLKSRC_LCD0), - SAVE_ITEM(EXYNOS4_CLKSRC_MAUDIO), - SAVE_ITEM(EXYNOS4_CLKSRC_FSYS), - SAVE_ITEM(EXYNOS4_CLKSRC_PERIL0), - SAVE_ITEM(EXYNOS4_CLKSRC_PERIL1), - SAVE_ITEM(EXYNOS4_CLKDIV_CAM), - SAVE_ITEM(EXYNOS4_CLKDIV_TV), - SAVE_ITEM(EXYNOS4_CLKDIV_MFC), - SAVE_ITEM(EXYNOS4_CLKDIV_G3D), - SAVE_ITEM(EXYNOS4_CLKDIV_LCD0), - SAVE_ITEM(EXYNOS4_CLKDIV_MAUDIO), - SAVE_ITEM(EXYNOS4_CLKDIV_FSYS0), - SAVE_ITEM(EXYNOS4_CLKDIV_FSYS1), - SAVE_ITEM(EXYNOS4_CLKDIV_FSYS2), - SAVE_ITEM(EXYNOS4_CLKDIV_FSYS3), - SAVE_ITEM(EXYNOS4_CLKDIV_PERIL0), - SAVE_ITEM(EXYNOS4_CLKDIV_PERIL1), - SAVE_ITEM(EXYNOS4_CLKDIV_PERIL2), - SAVE_ITEM(EXYNOS4_CLKDIV_PERIL3), - SAVE_ITEM(EXYNOS4_CLKDIV_PERIL4), - SAVE_ITEM(EXYNOS4_CLKDIV_PERIL5), - SAVE_ITEM(EXYNOS4_CLKDIV_TOP), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_TOP), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_CAM), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_TV), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_LCD0), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_MAUDIO), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_FSYS), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_PERIL0), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_PERIL1), - SAVE_ITEM(EXYNOS4_CLKDIV2_RATIO), - SAVE_ITEM(EXYNOS4_CLKGATE_SCLKCAM), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_CAM), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_TV), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_MFC), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_G3D), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_LCD0), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_FSYS), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_GPS), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_PERIL), - SAVE_ITEM(EXYNOS4_CLKGATE_BLOCK), - SAVE_ITEM(EXYNOS4_CLKSRC_MASK_DMC), - SAVE_ITEM(EXYNOS4_CLKSRC_DMC), - SAVE_ITEM(EXYNOS4_CLKDIV_DMC0), - SAVE_ITEM(EXYNOS4_CLKDIV_DMC1), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_DMC), - SAVE_ITEM(EXYNOS4_CLKSRC_CPU), - SAVE_ITEM(EXYNOS4_CLKDIV_CPU), - SAVE_ITEM(EXYNOS4_CLKDIV_CPU + 0x4), - SAVE_ITEM(EXYNOS4_CLKGATE_SCLKCPU), - SAVE_ITEM(EXYNOS4_CLKGATE_IP_CPU), -}; -#endif - -static struct clk exynos4_clk_sclk_hdmi27m = { - .name = "sclk_hdmi27m", - .rate = 27000000, -}; - -static struct clk exynos4_clk_sclk_hdmiphy = { - .name = "sclk_hdmiphy", -}; - -static struct clk exynos4_clk_sclk_usbphy0 = { - .name = "sclk_usbphy0", - .rate = 27000000, -}; - -static struct clk exynos4_clk_sclk_usbphy1 = { - .name = "sclk_usbphy1", -}; - -static struct clk dummy_apb_pclk = { - .name = "apb_pclk", - .id = -1, -}; - -static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_TOP, clk, enable); -} - -static int exynos4_clksrc_mask_cam_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_CAM, clk, enable); -} - -static int exynos4_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_LCD0, clk, enable); -} - -int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_FSYS, clk, enable); -} - -static int exynos4_clksrc_mask_peril0_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_PERIL0, clk, enable); -} - -static int exynos4_clksrc_mask_peril1_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_PERIL1, clk, enable); -} - -static int exynos4_clk_ip_mfc_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_MFC, clk, enable); -} - -static int exynos4_clksrc_mask_tv_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_TV, clk, enable); -} - -static int exynos4_clk_ip_cam_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_CAM, clk, enable); -} - -static int exynos4_clk_ip_tv_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_TV, clk, enable); -} - -int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_IMAGE, clk, enable); -} - -static int exynos4_clk_ip_lcd0_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_LCD0, clk, enable); -} - -int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4210_CLKGATE_IP_LCD1, clk, enable); -} - -int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_FSYS, clk, enable); -} - -static int exynos4_clk_ip_peril_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIL, clk, enable); -} - -static int exynos4_clk_ip_perir_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIR, clk, enable); -} - -int exynos4_clk_ip_dmc_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_DMC, clk, enable); -} - -static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable); -} - -static int exynos4_clk_dac_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(S5P_DAC_PHY_CONTROL, clk, enable); -} - -/* Core list of CMU_CPU side */ - -static struct clksrc_clk exynos4_clk_mout_apll = { - .clk = { - .name = "mout_apll", - }, - .sources = &clk_src_apll, - .reg_src = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 0, .size = 1 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_apll = { - .clk = { - .name = "sclk_apll", - .parent = &exynos4_clk_mout_apll.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 24, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_mout_epll = { - .clk = { - .name = "mout_epll", - }, - .sources = &clk_src_epll, - .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 4, .size = 1 }, -}; - -struct clksrc_clk exynos4_clk_mout_mpll = { - .clk = { - .name = "mout_mpll", - }, - .sources = &clk_src_mpll, - - /* reg_src will be added in each SoCs' clock */ -}; - -static struct clk *exynos4_clkset_moutcore_list[] = { - [0] = &exynos4_clk_mout_apll.clk, - [1] = &exynos4_clk_mout_mpll.clk, -}; - -static struct clksrc_sources exynos4_clkset_moutcore = { - .sources = exynos4_clkset_moutcore_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_moutcore_list), -}; - -static struct clksrc_clk exynos4_clk_moutcore = { - .clk = { - .name = "moutcore", - }, - .sources = &exynos4_clkset_moutcore, - .reg_src = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 16, .size = 1 }, -}; - -static struct clksrc_clk exynos4_clk_coreclk = { - .clk = { - .name = "core_clk", - .parent = &exynos4_clk_moutcore.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 0, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_armclk = { - .clk = { - .name = "armclk", - .parent = &exynos4_clk_coreclk.clk, - }, -}; - -static struct clksrc_clk exynos4_clk_aclk_corem0 = { - .clk = { - .name = "aclk_corem0", - .parent = &exynos4_clk_coreclk.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 4, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_aclk_cores = { - .clk = { - .name = "aclk_cores", - .parent = &exynos4_clk_coreclk.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 4, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_aclk_corem1 = { - .clk = { - .name = "aclk_corem1", - .parent = &exynos4_clk_coreclk.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 8, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_periphclk = { - .clk = { - .name = "periphclk", - .parent = &exynos4_clk_coreclk.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 12, .size = 3 }, -}; - -/* Core list of CMU_CORE side */ - -static struct clk *exynos4_clkset_corebus_list[] = { - [0] = &exynos4_clk_mout_mpll.clk, - [1] = &exynos4_clk_sclk_apll.clk, -}; - -struct clksrc_sources exynos4_clkset_mout_corebus = { - .sources = exynos4_clkset_corebus_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_corebus_list), -}; - -static struct clksrc_clk exynos4_clk_mout_corebus = { - .clk = { - .name = "mout_corebus", - }, - .sources = &exynos4_clkset_mout_corebus, - .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 4, .size = 1 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_dmc = { - .clk = { - .name = "sclk_dmc", - .parent = &exynos4_clk_mout_corebus.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 12, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_aclk_cored = { - .clk = { - .name = "aclk_cored", - .parent = &exynos4_clk_sclk_dmc.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 16, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_aclk_corep = { - .clk = { - .name = "aclk_corep", - .parent = &exynos4_clk_aclk_cored.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 20, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_aclk_acp = { - .clk = { - .name = "aclk_acp", - .parent = &exynos4_clk_mout_corebus.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 0, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_pclk_acp = { - .clk = { - .name = "pclk_acp", - .parent = &exynos4_clk_aclk_acp.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 4, .size = 3 }, -}; - -/* Core list of CMU_TOP side */ - -struct clk *exynos4_clkset_aclk_top_list[] = { - [0] = &exynos4_clk_mout_mpll.clk, - [1] = &exynos4_clk_sclk_apll.clk, -}; - -static struct clksrc_sources exynos4_clkset_aclk = { - .sources = exynos4_clkset_aclk_top_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_aclk_top_list), -}; - -static struct clksrc_clk exynos4_clk_aclk_200 = { - .clk = { - .name = "aclk_200", - }, - .sources = &exynos4_clkset_aclk, - .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 12, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 0, .size = 3 }, -}; - -static struct clksrc_clk exynos4_clk_aclk_100 = { - .clk = { - .name = "aclk_100", - }, - .sources = &exynos4_clkset_aclk, - .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 16, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 4, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_aclk_160 = { - .clk = { - .name = "aclk_160", - }, - .sources = &exynos4_clkset_aclk, - .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 20, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 8, .size = 3 }, -}; - -struct clksrc_clk exynos4_clk_aclk_133 = { - .clk = { - .name = "aclk_133", - }, - .sources = &exynos4_clkset_aclk, - .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 24, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 12, .size = 3 }, -}; - -static struct clk *exynos4_clkset_vpllsrc_list[] = { - [0] = &clk_fin_vpll, - [1] = &exynos4_clk_sclk_hdmi27m, -}; - -static struct clksrc_sources exynos4_clkset_vpllsrc = { - .sources = exynos4_clkset_vpllsrc_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_vpllsrc_list), -}; - -static struct clksrc_clk exynos4_clk_vpllsrc = { - .clk = { - .name = "vpll_src", - .enable = exynos4_clksrc_mask_top_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos4_clkset_vpllsrc, - .reg_src = { .reg = EXYNOS4_CLKSRC_TOP1, .shift = 0, .size = 1 }, -}; - -static struct clk *exynos4_clkset_sclk_vpll_list[] = { - [0] = &exynos4_clk_vpllsrc.clk, - [1] = &clk_fout_vpll, -}; - -static struct clksrc_sources exynos4_clkset_sclk_vpll = { - .sources = exynos4_clkset_sclk_vpll_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_sclk_vpll_list), -}; - -static struct clksrc_clk exynos4_clk_sclk_vpll = { - .clk = { - .name = "sclk_vpll", - }, - .sources = &exynos4_clkset_sclk_vpll, - .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 8, .size = 1 }, -}; - -static struct clk exynos4_init_clocks_off[] = { - { - .name = "timers", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1<<24), - }, { - .name = "csis", - .devname = "s5p-mipi-csis.0", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "csis", - .devname = "s5p-mipi-csis.1", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 5), - }, { - .name = "jpeg", - .id = 0, - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 6), - }, { - .name = "fimc", - .devname = "exynos4-fimc.0", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "fimc", - .devname = "exynos4-fimc.1", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 1), - }, { - .name = "fimc", - .devname = "exynos4-fimc.2", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 2), - }, { - .name = "fimc", - .devname = "exynos4-fimc.3", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "tsi", - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "hsmmc", - .devname = "exynos4-sdhci.0", - .parent = &exynos4_clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 5), - }, { - .name = "hsmmc", - .devname = "exynos4-sdhci.1", - .parent = &exynos4_clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 6), - }, { - .name = "hsmmc", - .devname = "exynos4-sdhci.2", - .parent = &exynos4_clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 7), - }, { - .name = "hsmmc", - .devname = "exynos4-sdhci.3", - .parent = &exynos4_clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 8), - }, { - .name = "biu", - .parent = &exynos4_clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 9), - }, { - .name = "onenand", - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 15), - }, { - .name = "nfcon", - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 16), - }, { - .name = "dac", - .devname = "s5p-sdo", - .enable = exynos4_clk_ip_tv_ctrl, - .ctrlbit = (1 << 2), - }, { - .name = "mixer", - .devname = "s5p-mixer", - .enable = exynos4_clk_ip_tv_ctrl, - .ctrlbit = (1 << 1), - }, { - .name = "vp", - .devname = "s5p-mixer", - .enable = exynos4_clk_ip_tv_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "hdmi", - .devname = "exynos4-hdmi", - .enable = exynos4_clk_ip_tv_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "hdmiphy", - .devname = "exynos4-hdmi", - .enable = exynos4_clk_hdmiphy_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "dacphy", - .devname = "s5p-sdo", - .enable = exynos4_clk_dac_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "adc", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 15), - }, { - .name = "tmu_apbif", - .enable = exynos4_clk_ip_perir_ctrl, - .ctrlbit = (1 << 17), - }, { - .name = "keypad", - .enable = exynos4_clk_ip_perir_ctrl, - .ctrlbit = (1 << 16), - }, { - .name = "rtc", - .enable = exynos4_clk_ip_perir_ctrl, - .ctrlbit = (1 << 15), - }, { - .name = "watchdog", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_perir_ctrl, - .ctrlbit = (1 << 14), - }, { - .name = "usbhost", - .enable = exynos4_clk_ip_fsys_ctrl , - .ctrlbit = (1 << 12), - }, { - .name = "otg", - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 13), - }, { - .name = "spi", - .devname = "exynos4210-spi.0", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 16), - }, { - .name = "spi", - .devname = "exynos4210-spi.1", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 17), - }, { - .name = "spi", - .devname = "exynos4210-spi.2", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 18), - }, { - .name = "iis", - .devname = "samsung-i2s.1", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 20), - }, { - .name = "iis", - .devname = "samsung-i2s.2", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 21), - }, { - .name = "pcm", - .devname = "samsung-pcm.1", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 22), - }, { - .name = "pcm", - .devname = "samsung-pcm.2", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 23), - }, { - .name = "slimbus", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 25), - }, { - .name = "spdif", - .devname = "samsung-spdif", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 26), - }, { - .name = "ac97", - .devname = "samsung-ac97", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 27), - }, { - .name = "mfc", - .devname = "s5p-mfc", - .enable = exynos4_clk_ip_mfc_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.0", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 6), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.1", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 7), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.2", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 8), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.3", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 9), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.4", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 10), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.5", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 11), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.6", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 12), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.7", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 13), - }, { - .name = "i2c", - .devname = "s3c2440-hdmiphy-i2c", - .parent = &exynos4_clk_aclk_100.clk, - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 14), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.0", - .enable = exynos4_clk_ip_mfc_ctrl, - .ctrlbit = (1 << 1), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.1", - .enable = exynos4_clk_ip_mfc_ctrl, - .ctrlbit = (1 << 2), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.2", - .enable = exynos4_clk_ip_tv_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.3", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 11), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.4", - .enable = exynos4_clk_ip_image_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.5", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 7), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.6", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 8), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.7", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 9), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.8", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 10), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.10", - .enable = exynos4_clk_ip_lcd0_ctrl, - .ctrlbit = (1 << 4), - } -}; - -static struct clk exynos4_init_clocks_on[] = { - { - .name = "uart", - .devname = "s5pv210-uart.0", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "uart", - .devname = "s5pv210-uart.1", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 1), - }, { - .name = "uart", - .devname = "s5pv210-uart.2", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 2), - }, { - .name = "uart", - .devname = "s5pv210-uart.3", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "uart", - .devname = "s5pv210-uart.4", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "uart", - .devname = "s5pv210-uart.5", - .enable = exynos4_clk_ip_peril_ctrl, - .ctrlbit = (1 << 5), - } -}; - -static struct clk exynos4_clk_pdma0 = { - .name = "dma", - .devname = "dma-pl330.0", - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 0), -}; - -static struct clk exynos4_clk_pdma1 = { - .name = "dma", - .devname = "dma-pl330.1", - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 1), -}; - -static struct clk exynos4_clk_mdma1 = { - .name = "dma", - .devname = "dma-pl330.2", - .enable = exynos4_clk_ip_image_ctrl, - .ctrlbit = ((1 << 8) | (1 << 5) | (1 << 2)), -}; - -static struct clk exynos4_clk_fimd0 = { - .name = "fimd", - .devname = "exynos4-fb.0", - .enable = exynos4_clk_ip_lcd0_ctrl, - .ctrlbit = (1 << 0), -}; - -struct clk *exynos4_clkset_group_list[] = { - [0] = &clk_ext_xtal_mux, - [1] = &clk_xusbxti, - [2] = &exynos4_clk_sclk_hdmi27m, - [3] = &exynos4_clk_sclk_usbphy0, - [4] = &exynos4_clk_sclk_usbphy1, - [5] = &exynos4_clk_sclk_hdmiphy, - [6] = &exynos4_clk_mout_mpll.clk, - [7] = &exynos4_clk_mout_epll.clk, - [8] = &exynos4_clk_sclk_vpll.clk, -}; - -struct clksrc_sources exynos4_clkset_group = { - .sources = exynos4_clkset_group_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_group_list), -}; - -static struct clk *exynos4_clkset_mout_g2d0_list[] = { - [0] = &exynos4_clk_mout_mpll.clk, - [1] = &exynos4_clk_sclk_apll.clk, -}; - -struct clksrc_sources exynos4_clkset_mout_g2d0 = { - .sources = exynos4_clkset_mout_g2d0_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_g2d0_list), -}; - -static struct clk *exynos4_clkset_mout_g2d1_list[] = { - [0] = &exynos4_clk_mout_epll.clk, - [1] = &exynos4_clk_sclk_vpll.clk, -}; - -struct clksrc_sources exynos4_clkset_mout_g2d1 = { - .sources = exynos4_clkset_mout_g2d1_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_g2d1_list), -}; - -static struct clk *exynos4_clkset_mout_mfc0_list[] = { - [0] = &exynos4_clk_mout_mpll.clk, - [1] = &exynos4_clk_sclk_apll.clk, -}; - -static struct clksrc_sources exynos4_clkset_mout_mfc0 = { - .sources = exynos4_clkset_mout_mfc0_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_mfc0_list), -}; - -static struct clksrc_clk exynos4_clk_mout_mfc0 = { - .clk = { - .name = "mout_mfc0", - }, - .sources = &exynos4_clkset_mout_mfc0, - .reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 0, .size = 1 }, -}; - -static struct clk *exynos4_clkset_mout_mfc1_list[] = { - [0] = &exynos4_clk_mout_epll.clk, - [1] = &exynos4_clk_sclk_vpll.clk, -}; - -static struct clksrc_sources exynos4_clkset_mout_mfc1 = { - .sources = exynos4_clkset_mout_mfc1_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_mfc1_list), -}; - -static struct clksrc_clk exynos4_clk_mout_mfc1 = { - .clk = { - .name = "mout_mfc1", - }, - .sources = &exynos4_clkset_mout_mfc1, - .reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 4, .size = 1 }, -}; - -static struct clk *exynos4_clkset_mout_mfc_list[] = { - [0] = &exynos4_clk_mout_mfc0.clk, - [1] = &exynos4_clk_mout_mfc1.clk, -}; - -static struct clksrc_sources exynos4_clkset_mout_mfc = { - .sources = exynos4_clkset_mout_mfc_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_mfc_list), -}; - -static struct clk *exynos4_clkset_sclk_dac_list[] = { - [0] = &exynos4_clk_sclk_vpll.clk, - [1] = &exynos4_clk_sclk_hdmiphy, -}; - -static struct clksrc_sources exynos4_clkset_sclk_dac = { - .sources = exynos4_clkset_sclk_dac_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_sclk_dac_list), -}; - -static struct clksrc_clk exynos4_clk_sclk_dac = { - .clk = { - .name = "sclk_dac", - .enable = exynos4_clksrc_mask_tv_ctrl, - .ctrlbit = (1 << 8), - }, - .sources = &exynos4_clkset_sclk_dac, - .reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 8, .size = 1 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_pixel = { - .clk = { - .name = "sclk_pixel", - .parent = &exynos4_clk_sclk_vpll.clk, - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_TV, .shift = 0, .size = 4 }, -}; - -static struct clk *exynos4_clkset_sclk_hdmi_list[] = { - [0] = &exynos4_clk_sclk_pixel.clk, - [1] = &exynos4_clk_sclk_hdmiphy, -}; - -static struct clksrc_sources exynos4_clkset_sclk_hdmi = { - .sources = exynos4_clkset_sclk_hdmi_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_sclk_hdmi_list), -}; - -static struct clksrc_clk exynos4_clk_sclk_hdmi = { - .clk = { - .name = "sclk_hdmi", - .enable = exynos4_clksrc_mask_tv_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos4_clkset_sclk_hdmi, - .reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 0, .size = 1 }, -}; - -static struct clk *exynos4_clkset_sclk_mixer_list[] = { - [0] = &exynos4_clk_sclk_dac.clk, - [1] = &exynos4_clk_sclk_hdmi.clk, -}; - -static struct clksrc_sources exynos4_clkset_sclk_mixer = { - .sources = exynos4_clkset_sclk_mixer_list, - .nr_sources = ARRAY_SIZE(exynos4_clkset_sclk_mixer_list), -}; - -static struct clksrc_clk exynos4_clk_sclk_mixer = { - .clk = { - .name = "sclk_mixer", - .enable = exynos4_clksrc_mask_tv_ctrl, - .ctrlbit = (1 << 4), - }, - .sources = &exynos4_clkset_sclk_mixer, - .reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 4, .size = 1 }, -}; - -static struct clksrc_clk *exynos4_sclk_tv[] = { - &exynos4_clk_sclk_dac, - &exynos4_clk_sclk_pixel, - &exynos4_clk_sclk_hdmi, - &exynos4_clk_sclk_mixer, -}; - -static struct clksrc_clk exynos4_clk_dout_mmc0 = { - .clk = { - .name = "dout_mmc0", - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 0, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_dout_mmc1 = { - .clk = { - .name = "dout_mmc1", - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 4, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 16, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_dout_mmc2 = { - .clk = { - .name = "dout_mmc2", - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 8, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_dout_mmc3 = { - .clk = { - .name = "dout_mmc3", - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 12, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 16, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_dout_mmc4 = { - .clk = { - .name = "dout_mmc4", - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 16, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS3, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clksrcs[] = { - { - .clk = { - .name = "sclk_pwm", - .enable = exynos4_clksrc_mask_peril0_ctrl, - .ctrlbit = (1 << 24), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 24, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL3, .shift = 0, .size = 4 }, - }, { - .clk = { - .name = "sclk_csis", - .devname = "s5p-mipi-csis.0", - .enable = exynos4_clksrc_mask_cam_ctrl, - .ctrlbit = (1 << 24), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 24, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 24, .size = 4 }, - }, { - .clk = { - .name = "sclk_csis", - .devname = "s5p-mipi-csis.1", - .enable = exynos4_clksrc_mask_cam_ctrl, - .ctrlbit = (1 << 28), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 28, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 28, .size = 4 }, - }, { - .clk = { - .name = "sclk_cam0", - .enable = exynos4_clksrc_mask_cam_ctrl, - .ctrlbit = (1 << 16), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 16, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 16, .size = 4 }, - }, { - .clk = { - .name = "sclk_cam1", - .enable = exynos4_clksrc_mask_cam_ctrl, - .ctrlbit = (1 << 20), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 20, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 20, .size = 4 }, - }, { - .clk = { - .name = "sclk_fimc", - .devname = "exynos4-fimc.0", - .enable = exynos4_clksrc_mask_cam_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 0, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 0, .size = 4 }, - }, { - .clk = { - .name = "sclk_fimc", - .devname = "exynos4-fimc.1", - .enable = exynos4_clksrc_mask_cam_ctrl, - .ctrlbit = (1 << 4), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 4, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 4, .size = 4 }, - }, { - .clk = { - .name = "sclk_fimc", - .devname = "exynos4-fimc.2", - .enable = exynos4_clksrc_mask_cam_ctrl, - .ctrlbit = (1 << 8), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 8, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 8, .size = 4 }, - }, { - .clk = { - .name = "sclk_fimc", - .devname = "exynos4-fimc.3", - .enable = exynos4_clksrc_mask_cam_ctrl, - .ctrlbit = (1 << 12), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 12, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 12, .size = 4 }, - }, { - .clk = { - .name = "sclk_fimd", - .devname = "exynos4-fb.0", - .enable = exynos4_clksrc_mask_lcd0_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_LCD0, .shift = 0, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_LCD0, .shift = 0, .size = 4 }, - }, { - .clk = { - .name = "sclk_mfc", - .devname = "s5p-mfc", - }, - .sources = &exynos4_clkset_mout_mfc, - .reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 8, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_MFC, .shift = 0, .size = 4 }, - }, { - .clk = { - .name = "ciu", - .parent = &exynos4_clk_dout_mmc4.clk, - .enable = exynos4_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 16), - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS3, .shift = 8, .size = 8 }, - } -}; - -static struct clksrc_clk exynos4_clk_sclk_uart0 = { - .clk = { - .name = "uclk1", - .devname = "exynos4210-uart.0", - .enable = exynos4_clksrc_mask_peril0_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 0, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_uart1 = { - .clk = { - .name = "uclk1", - .devname = "exynos4210-uart.1", - .enable = exynos4_clksrc_mask_peril0_ctrl, - .ctrlbit = (1 << 4), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 4, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 4, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_uart2 = { - .clk = { - .name = "uclk1", - .devname = "exynos4210-uart.2", - .enable = exynos4_clksrc_mask_peril0_ctrl, - .ctrlbit = (1 << 8), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 8, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 8, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_uart3 = { - .clk = { - .name = "uclk1", - .devname = "exynos4210-uart.3", - .enable = exynos4_clksrc_mask_peril0_ctrl, - .ctrlbit = (1 << 12), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 12, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 12, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_mmc0 = { - .clk = { - .name = "sclk_mmc", - .devname = "exynos4-sdhci.0", - .parent = &exynos4_clk_dout_mmc0.clk, - .enable = exynos4_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 0), - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 8, .size = 8 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_mmc1 = { - .clk = { - .name = "sclk_mmc", - .devname = "exynos4-sdhci.1", - .parent = &exynos4_clk_dout_mmc1.clk, - .enable = exynos4_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 4), - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 24, .size = 8 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_mmc2 = { - .clk = { - .name = "sclk_mmc", - .devname = "exynos4-sdhci.2", - .parent = &exynos4_clk_dout_mmc2.clk, - .enable = exynos4_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 8), - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 8, .size = 8 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_mmc3 = { - .clk = { - .name = "sclk_mmc", - .devname = "exynos4-sdhci.3", - .parent = &exynos4_clk_dout_mmc3.clk, - .enable = exynos4_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 12), - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 24, .size = 8 }, -}; - -static struct clksrc_clk exynos4_clk_mdout_spi0 = { - .clk = { - .name = "mdout_spi", - .devname = "exynos4210-spi.0", - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 16, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_mdout_spi1 = { - .clk = { - .name = "mdout_spi", - .devname = "exynos4210-spi.1", - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 20, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 16, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_mdout_spi2 = { - .clk = { - .name = "mdout_spi", - .devname = "exynos4210-spi.2", - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 24, .size = 4 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL2, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_spi0 = { - .clk = { - .name = "sclk_spi", - .devname = "exynos4210-spi.0", - .parent = &exynos4_clk_mdout_spi0.clk, - .enable = exynos4_clksrc_mask_peril1_ctrl, - .ctrlbit = (1 << 16), - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 8, .size = 8 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_spi1 = { - .clk = { - .name = "sclk_spi", - .devname = "exynos4210-spi.1", - .parent = &exynos4_clk_mdout_spi1.clk, - .enable = exynos4_clksrc_mask_peril1_ctrl, - .ctrlbit = (1 << 20), - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 24, .size = 8 }, -}; - -static struct clksrc_clk exynos4_clk_sclk_spi2 = { - .clk = { - .name = "sclk_spi", - .devname = "exynos4210-spi.2", - .parent = &exynos4_clk_mdout_spi2.clk, - .enable = exynos4_clksrc_mask_peril1_ctrl, - .ctrlbit = (1 << 24), - }, - .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL2, .shift = 8, .size = 8 }, -}; - -/* Clock initialization code */ -static struct clksrc_clk *exynos4_sysclks[] = { - &exynos4_clk_mout_apll, - &exynos4_clk_sclk_apll, - &exynos4_clk_mout_epll, - &exynos4_clk_mout_mpll, - &exynos4_clk_moutcore, - &exynos4_clk_coreclk, - &exynos4_clk_armclk, - &exynos4_clk_aclk_corem0, - &exynos4_clk_aclk_cores, - &exynos4_clk_aclk_corem1, - &exynos4_clk_periphclk, - &exynos4_clk_mout_corebus, - &exynos4_clk_sclk_dmc, - &exynos4_clk_aclk_cored, - &exynos4_clk_aclk_corep, - &exynos4_clk_aclk_acp, - &exynos4_clk_pclk_acp, - &exynos4_clk_vpllsrc, - &exynos4_clk_sclk_vpll, - &exynos4_clk_aclk_200, - &exynos4_clk_aclk_100, - &exynos4_clk_aclk_160, - &exynos4_clk_aclk_133, - &exynos4_clk_dout_mmc0, - &exynos4_clk_dout_mmc1, - &exynos4_clk_dout_mmc2, - &exynos4_clk_dout_mmc3, - &exynos4_clk_dout_mmc4, - &exynos4_clk_mout_mfc0, - &exynos4_clk_mout_mfc1, -}; - -static struct clk *exynos4_clk_cdev[] = { - &exynos4_clk_pdma0, - &exynos4_clk_pdma1, - &exynos4_clk_mdma1, - &exynos4_clk_fimd0, -}; - -static struct clksrc_clk *exynos4_clksrc_cdev[] = { - &exynos4_clk_sclk_uart0, - &exynos4_clk_sclk_uart1, - &exynos4_clk_sclk_uart2, - &exynos4_clk_sclk_uart3, - &exynos4_clk_sclk_mmc0, - &exynos4_clk_sclk_mmc1, - &exynos4_clk_sclk_mmc2, - &exynos4_clk_sclk_mmc3, - &exynos4_clk_sclk_spi0, - &exynos4_clk_sclk_spi1, - &exynos4_clk_sclk_spi2, - &exynos4_clk_mdout_spi0, - &exynos4_clk_mdout_spi1, - &exynos4_clk_mdout_spi2, -}; - -static struct clk_lookup exynos4_clk_lookup[] = { - CLKDEV_INIT("exynos4210-uart.0", "clk_uart_baud0", &exynos4_clk_sclk_uart0.clk), - CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &exynos4_clk_sclk_uart1.clk), - CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &exynos4_clk_sclk_uart2.clk), - CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &exynos4_clk_sclk_uart3.clk), - CLKDEV_INIT("exynos4-sdhci.0", "mmc_busclk.2", &exynos4_clk_sclk_mmc0.clk), - CLKDEV_INIT("exynos4-sdhci.1", "mmc_busclk.2", &exynos4_clk_sclk_mmc1.clk), - CLKDEV_INIT("exynos4-sdhci.2", "mmc_busclk.2", &exynos4_clk_sclk_mmc2.clk), - CLKDEV_INIT("exynos4-sdhci.3", "mmc_busclk.2", &exynos4_clk_sclk_mmc3.clk), - CLKDEV_INIT("exynos4-fb.0", "lcd", &exynos4_clk_fimd0), - CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos4_clk_pdma0), - CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos4_clk_pdma1), - CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos4_clk_mdma1), - CLKDEV_INIT("exynos4210-spi.0", "spi_busclk0", &exynos4_clk_sclk_spi0.clk), - CLKDEV_INIT("exynos4210-spi.1", "spi_busclk0", &exynos4_clk_sclk_spi1.clk), - CLKDEV_INIT("exynos4210-spi.2", "spi_busclk0", &exynos4_clk_sclk_spi2.clk), -}; - -static int xtal_rate; - -static unsigned long exynos4_fout_apll_get_rate(struct clk *clk) -{ - if (soc_is_exynos4210()) - return s5p_get_pll45xx(xtal_rate, __raw_readl(EXYNOS4_APLL_CON0), - pll_4508); - else if (soc_is_exynos4212() || soc_is_exynos4412()) - return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS4_APLL_CON0)); - else - return 0; -} - -static struct clk_ops exynos4_fout_apll_ops = { - .get_rate = exynos4_fout_apll_get_rate, -}; - -static u32 exynos4_vpll_div[][8] = { - { 54000000, 3, 53, 3, 1024, 0, 17, 0 }, - { 108000000, 3, 53, 2, 1024, 0, 17, 0 }, -}; - -static unsigned long exynos4_vpll_get_rate(struct clk *clk) -{ - return clk->rate; -} - -static int exynos4_vpll_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int vpll_con0, vpll_con1 = 0; - unsigned int i; - - /* Return if nothing changed */ - if (clk->rate == rate) - return 0; - - vpll_con0 = __raw_readl(EXYNOS4_VPLL_CON0); - vpll_con0 &= ~(0x1 << 27 | \ - PLL90XX_MDIV_MASK << PLL46XX_MDIV_SHIFT | \ - PLL90XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | \ - PLL90XX_SDIV_MASK << PLL46XX_SDIV_SHIFT); - - vpll_con1 = __raw_readl(EXYNOS4_VPLL_CON1); - vpll_con1 &= ~(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT | \ - PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT | \ - PLL4650C_KDIV_MASK << PLL46XX_KDIV_SHIFT); - - for (i = 0; i < ARRAY_SIZE(exynos4_vpll_div); i++) { - if (exynos4_vpll_div[i][0] == rate) { - vpll_con0 |= exynos4_vpll_div[i][1] << PLL46XX_PDIV_SHIFT; - vpll_con0 |= exynos4_vpll_div[i][2] << PLL46XX_MDIV_SHIFT; - vpll_con0 |= exynos4_vpll_div[i][3] << PLL46XX_SDIV_SHIFT; - vpll_con1 |= exynos4_vpll_div[i][4] << PLL46XX_KDIV_SHIFT; - vpll_con1 |= exynos4_vpll_div[i][5] << PLL46XX_MFR_SHIFT; - vpll_con1 |= exynos4_vpll_div[i][6] << PLL46XX_MRR_SHIFT; - vpll_con0 |= exynos4_vpll_div[i][7] << 27; - break; - } - } - - if (i == ARRAY_SIZE(exynos4_vpll_div)) { - printk(KERN_ERR "%s: Invalid Clock VPLL Frequency\n", - __func__); - return -EINVAL; - } - - __raw_writel(vpll_con0, EXYNOS4_VPLL_CON0); - __raw_writel(vpll_con1, EXYNOS4_VPLL_CON1); - - /* Wait for VPLL lock */ - while (!(__raw_readl(EXYNOS4_VPLL_CON0) & (1 << PLL46XX_LOCKED_SHIFT))) - continue; - - clk->rate = rate; - return 0; -} - -static struct clk_ops exynos4_vpll_ops = { - .get_rate = exynos4_vpll_get_rate, - .set_rate = exynos4_vpll_set_rate, -}; - -void __init_or_cpufreq exynos4_setup_clocks(void) -{ - struct clk *xtal_clk; - unsigned long apll = 0; - unsigned long mpll = 0; - unsigned long epll = 0; - unsigned long vpll = 0; - unsigned long vpllsrc; - unsigned long xtal; - unsigned long armclk; - unsigned long sclk_dmc; - unsigned long aclk_200; - unsigned long aclk_100; - unsigned long aclk_160; - unsigned long aclk_133; - unsigned int ptr; - - printk(KERN_DEBUG "%s: registering clocks\n", __func__); - - xtal_clk = clk_get(NULL, "xtal"); - BUG_ON(IS_ERR(xtal_clk)); - - xtal = clk_get_rate(xtal_clk); - - xtal_rate = xtal; - - clk_put(xtal_clk); - - printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal); - - if (soc_is_exynos4210()) { - apll = s5p_get_pll45xx(xtal, __raw_readl(EXYNOS4_APLL_CON0), - pll_4508); - mpll = s5p_get_pll45xx(xtal, __raw_readl(EXYNOS4_MPLL_CON0), - pll_4508); - epll = s5p_get_pll46xx(xtal, __raw_readl(EXYNOS4_EPLL_CON0), - __raw_readl(EXYNOS4_EPLL_CON1), pll_4600); - - vpllsrc = clk_get_rate(&exynos4_clk_vpllsrc.clk); - vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(EXYNOS4_VPLL_CON0), - __raw_readl(EXYNOS4_VPLL_CON1), pll_4650c); - } else if (soc_is_exynos4212() || soc_is_exynos4412()) { - apll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS4_APLL_CON0)); - mpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS4_MPLL_CON0)); - epll = s5p_get_pll36xx(xtal, __raw_readl(EXYNOS4_EPLL_CON0), - __raw_readl(EXYNOS4_EPLL_CON1)); - - vpllsrc = clk_get_rate(&exynos4_clk_vpllsrc.clk); - vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(EXYNOS4_VPLL_CON0), - __raw_readl(EXYNOS4_VPLL_CON1)); - } else { - /* nothing */ - } - - clk_fout_apll.ops = &exynos4_fout_apll_ops; - clk_fout_mpll.rate = mpll; - clk_fout_epll.rate = epll; - clk_fout_vpll.ops = &exynos4_vpll_ops; - clk_fout_vpll.rate = vpll; - - printk(KERN_INFO "EXYNOS4: PLL settings, A=%ld, M=%ld, E=%ld V=%ld", - apll, mpll, epll, vpll); - - armclk = clk_get_rate(&exynos4_clk_armclk.clk); - sclk_dmc = clk_get_rate(&exynos4_clk_sclk_dmc.clk); - - aclk_200 = clk_get_rate(&exynos4_clk_aclk_200.clk); - aclk_100 = clk_get_rate(&exynos4_clk_aclk_100.clk); - aclk_160 = clk_get_rate(&exynos4_clk_aclk_160.clk); - aclk_133 = clk_get_rate(&exynos4_clk_aclk_133.clk); - - printk(KERN_INFO "EXYNOS4: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n" - "ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n", - armclk, sclk_dmc, aclk_200, - aclk_100, aclk_160, aclk_133); - - clk_f.rate = armclk; - clk_h.rate = sclk_dmc; - clk_p.rate = aclk_100; - - for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clksrcs); ptr++) - s3c_set_clksrc(&exynos4_clksrcs[ptr], true); -} - -static struct clk *exynos4_clks[] __initdata = { - &exynos4_clk_sclk_hdmi27m, - &exynos4_clk_sclk_hdmiphy, - &exynos4_clk_sclk_usbphy0, - &exynos4_clk_sclk_usbphy1, -}; - -#ifdef CONFIG_PM_SLEEP -static int exynos4_clock_suspend(void) -{ - s3c_pm_do_save(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save)); - return 0; -} - -static void exynos4_clock_resume(void) -{ - s3c_pm_do_restore_core(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save)); -} - -#else -#define exynos4_clock_suspend NULL -#define exynos4_clock_resume NULL -#endif - -static struct syscore_ops exynos4_clock_syscore_ops = { - .suspend = exynos4_clock_suspend, - .resume = exynos4_clock_resume, -}; - -void __init exynos4_register_clocks(void) -{ - int ptr; - - s3c24xx_register_clocks(exynos4_clks, ARRAY_SIZE(exynos4_clks)); - - for (ptr = 0; ptr < ARRAY_SIZE(exynos4_sysclks); ptr++) - s3c_register_clksrc(exynos4_sysclks[ptr], 1); - - for (ptr = 0; ptr < ARRAY_SIZE(exynos4_sclk_tv); ptr++) - s3c_register_clksrc(exynos4_sclk_tv[ptr], 1); - - for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clksrc_cdev); ptr++) - s3c_register_clksrc(exynos4_clksrc_cdev[ptr], 1); - - s3c_register_clksrc(exynos4_clksrcs, ARRAY_SIZE(exynos4_clksrcs)); - s3c_register_clocks(exynos4_init_clocks_on, ARRAY_SIZE(exynos4_init_clocks_on)); - - s3c24xx_register_clocks(exynos4_clk_cdev, ARRAY_SIZE(exynos4_clk_cdev)); - for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clk_cdev); ptr++) - s3c_disable_clocks(exynos4_clk_cdev[ptr], 1); - - s3c_register_clocks(exynos4_init_clocks_off, ARRAY_SIZE(exynos4_init_clocks_off)); - s3c_disable_clocks(exynos4_init_clocks_off, ARRAY_SIZE(exynos4_init_clocks_off)); - clkdev_add_table(exynos4_clk_lookup, ARRAY_SIZE(exynos4_clk_lookup)); - - register_syscore_ops(&exynos4_clock_syscore_ops); - s3c24xx_register_clock(&dummy_apb_pclk); - - s3c_pwmclk_init(); -} diff --git a/arch/arm/mach-exynos/clock-exynos4.h b/arch/arm/mach-exynos/clock-exynos4.h deleted file mode 100644 index bd12d5f8b63d..000000000000 --- a/arch/arm/mach-exynos/clock-exynos4.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Header file for exynos4 clock support - * - * 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 __ASM_ARCH_CLOCK_H -#define __ASM_ARCH_CLOCK_H __FILE__ - -#include <linux/clk.h> - -extern struct clksrc_clk exynos4_clk_aclk_133; -extern struct clksrc_clk exynos4_clk_mout_mpll; - -extern struct clksrc_sources exynos4_clkset_mout_corebus; -extern struct clksrc_sources exynos4_clkset_group; - -extern struct clk *exynos4_clkset_aclk_top_list[]; -extern struct clk *exynos4_clkset_group_list[]; - -extern struct clksrc_sources exynos4_clkset_mout_g2d0; -extern struct clksrc_sources exynos4_clkset_mout_g2d1; - -extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable); -extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable); -extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable); -extern int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable); -extern int exynos4_clk_ip_dmc_ctrl(struct clk *clk, int enable); - -#endif /* __ASM_ARCH_CLOCK_H */ diff --git a/arch/arm/mach-exynos/clock-exynos4210.c b/arch/arm/mach-exynos/clock-exynos4210.c deleted file mode 100644 index 19af9f783c56..000000000000 --- a/arch/arm/mach-exynos/clock-exynos4210.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS4210 - Clock support - * - * 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/kernel.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/syscore_ops.h> - -#include <plat/cpu-freq.h> -#include <plat/clock.h> -#include <plat/cpu.h> -#include <plat/pll.h> -#include <plat/s5p-clock.h> -#include <plat/clock-clksrc.h> -#include <plat/pm.h> - -#include <mach/hardware.h> -#include <mach/map.h> -#include <mach/regs-clock.h> - -#include "common.h" -#include "clock-exynos4.h" - -#ifdef CONFIG_PM_SLEEP -static struct sleep_save exynos4210_clock_save[] = { - SAVE_ITEM(EXYNOS4_CLKSRC_IMAGE), - SAVE_ITEM(EXYNOS4_CLKDIV_IMAGE), - SAVE_ITEM(EXYNOS4210_CLKSRC_LCD1), - SAVE_ITEM(EXYNOS4210_CLKDIV_LCD1), - SAVE_ITEM(EXYNOS4210_CLKSRC_MASK_LCD1), - SAVE_ITEM(EXYNOS4210_CLKGATE_IP_IMAGE), - SAVE_ITEM(EXYNOS4210_CLKGATE_IP_LCD1), - SAVE_ITEM(EXYNOS4210_CLKGATE_IP_PERIR), -}; -#endif - -static struct clksrc_clk *sysclks[] = { - /* nothing here yet */ -}; - -static struct clksrc_clk exynos4210_clk_mout_g2d0 = { - .clk = { - .name = "mout_g2d0", - }, - .sources = &exynos4_clkset_mout_g2d0, - .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 0, .size = 1 }, -}; - -static struct clksrc_clk exynos4210_clk_mout_g2d1 = { - .clk = { - .name = "mout_g2d1", - }, - .sources = &exynos4_clkset_mout_g2d1, - .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 4, .size = 1 }, -}; - -static struct clk *exynos4210_clkset_mout_g2d_list[] = { - [0] = &exynos4210_clk_mout_g2d0.clk, - [1] = &exynos4210_clk_mout_g2d1.clk, -}; - -static struct clksrc_sources exynos4210_clkset_mout_g2d = { - .sources = exynos4210_clkset_mout_g2d_list, - .nr_sources = ARRAY_SIZE(exynos4210_clkset_mout_g2d_list), -}; - -static int exynos4_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4210_CLKSRC_MASK_LCD1, clk, enable); -} - -static struct clksrc_clk clksrcs[] = { - { - .clk = { - .name = "sclk_sata", - .id = -1, - .enable = exynos4_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 24), - }, - .sources = &exynos4_clkset_mout_corebus, - .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 24, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS0, .shift = 20, .size = 4 }, - }, { - .clk = { - .name = "sclk_fimd", - .devname = "exynos4-fb.1", - .enable = exynos4_clksrc_mask_lcd1_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos4_clkset_group, - .reg_src = { .reg = EXYNOS4210_CLKSRC_LCD1, .shift = 0, .size = 4 }, - .reg_div = { .reg = EXYNOS4210_CLKDIV_LCD1, .shift = 0, .size = 4 }, - }, { - .clk = { - .name = "sclk_fimg2d", - }, - .sources = &exynos4210_clkset_mout_g2d, - .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 8, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_IMAGE, .shift = 0, .size = 4 }, - }, -}; - -static struct clk init_clocks_off[] = { - { - .name = "sataphy", - .id = -1, - .parent = &exynos4_clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "sata", - .id = -1, - .parent = &exynos4_clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 10), - }, { - .name = "fimd", - .devname = "exynos4-fb.1", - .enable = exynos4_clk_ip_lcd1_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.9", - .enable = exynos4_clk_ip_image_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.11", - .enable = exynos4_clk_ip_lcd1_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "fimg2d", - .enable = exynos4_clk_ip_image_ctrl, - .ctrlbit = (1 << 0), - }, -}; - -#ifdef CONFIG_PM_SLEEP -static int exynos4210_clock_suspend(void) -{ - s3c_pm_do_save(exynos4210_clock_save, ARRAY_SIZE(exynos4210_clock_save)); - - return 0; -} - -static void exynos4210_clock_resume(void) -{ - s3c_pm_do_restore_core(exynos4210_clock_save, ARRAY_SIZE(exynos4210_clock_save)); -} - -#else -#define exynos4210_clock_suspend NULL -#define exynos4210_clock_resume NULL -#endif - -static struct syscore_ops exynos4210_clock_syscore_ops = { - .suspend = exynos4210_clock_suspend, - .resume = exynos4210_clock_resume, -}; - -void __init exynos4210_register_clocks(void) -{ - int ptr; - - exynos4_clk_mout_mpll.reg_src.reg = EXYNOS4_CLKSRC_CPU; - exynos4_clk_mout_mpll.reg_src.shift = 8; - exynos4_clk_mout_mpll.reg_src.size = 1; - - for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++) - s3c_register_clksrc(sysclks[ptr], 1); - - s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); - - s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - - register_syscore_ops(&exynos4210_clock_syscore_ops); -} diff --git a/arch/arm/mach-exynos/clock-exynos4212.c b/arch/arm/mach-exynos/clock-exynos4212.c deleted file mode 100644 index 529476f8ec71..000000000000 --- a/arch/arm/mach-exynos/clock-exynos4212.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS4212 - Clock support - * - * 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/kernel.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/syscore_ops.h> - -#include <plat/cpu-freq.h> -#include <plat/clock.h> -#include <plat/cpu.h> -#include <plat/pll.h> -#include <plat/s5p-clock.h> -#include <plat/clock-clksrc.h> -#include <plat/pm.h> - -#include <mach/hardware.h> -#include <mach/map.h> -#include <mach/regs-clock.h> - -#include "common.h" -#include "clock-exynos4.h" - -#ifdef CONFIG_PM_SLEEP -static struct sleep_save exynos4212_clock_save[] = { - SAVE_ITEM(EXYNOS4_CLKSRC_IMAGE), - SAVE_ITEM(EXYNOS4_CLKDIV_IMAGE), - SAVE_ITEM(EXYNOS4212_CLKGATE_IP_IMAGE), - SAVE_ITEM(EXYNOS4212_CLKGATE_IP_PERIR), -}; -#endif - -static int exynos4212_clk_ip_isp0_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_ISP0, clk, enable); -} - -static int exynos4212_clk_ip_isp1_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS4_CLKGATE_IP_ISP1, clk, enable); -} - -static struct clk *clk_src_mpll_user_list[] = { - [0] = &clk_fin_mpll, - [1] = &exynos4_clk_mout_mpll.clk, -}; - -static struct clksrc_sources clk_src_mpll_user = { - .sources = clk_src_mpll_user_list, - .nr_sources = ARRAY_SIZE(clk_src_mpll_user_list), -}; - -static struct clksrc_clk clk_mout_mpll_user = { - .clk = { - .name = "mout_mpll_user", - }, - .sources = &clk_src_mpll_user, - .reg_src = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 24, .size = 1 }, -}; - -static struct clksrc_clk exynos4x12_clk_mout_g2d0 = { - .clk = { - .name = "mout_g2d0", - }, - .sources = &exynos4_clkset_mout_g2d0, - .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 20, .size = 1 }, -}; - -static struct clksrc_clk exynos4x12_clk_mout_g2d1 = { - .clk = { - .name = "mout_g2d1", - }, - .sources = &exynos4_clkset_mout_g2d1, - .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 24, .size = 1 }, -}; - -static struct clk *exynos4x12_clkset_mout_g2d_list[] = { - [0] = &exynos4x12_clk_mout_g2d0.clk, - [1] = &exynos4x12_clk_mout_g2d1.clk, -}; - -static struct clksrc_sources exynos4x12_clkset_mout_g2d = { - .sources = exynos4x12_clkset_mout_g2d_list, - .nr_sources = ARRAY_SIZE(exynos4x12_clkset_mout_g2d_list), -}; - -static struct clksrc_clk *sysclks[] = { - &clk_mout_mpll_user, -}; - -static struct clksrc_clk clksrcs[] = { - { - .clk = { - .name = "sclk_fimg2d", - }, - .sources = &exynos4x12_clkset_mout_g2d, - .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 28, .size = 1 }, - .reg_div = { .reg = EXYNOS4_CLKDIV_DMC1, .shift = 0, .size = 4 }, - }, -}; - -static struct clk init_clocks_off[] = { - { - .name = "sysmmu", - .devname = "exynos-sysmmu.9", - .enable = exynos4_clk_ip_dmc_ctrl, - .ctrlbit = (1 << 24), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.12", - .enable = exynos4212_clk_ip_isp0_ctrl, - .ctrlbit = (7 << 8), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.13", - .enable = exynos4212_clk_ip_isp1_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.14", - .enable = exynos4212_clk_ip_isp0_ctrl, - .ctrlbit = (1 << 11), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.15", - .enable = exynos4212_clk_ip_isp0_ctrl, - .ctrlbit = (1 << 12), - }, { - .name = "flite", - .devname = "exynos-fimc-lite.0", - .enable = exynos4212_clk_ip_isp0_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "flite", - .devname = "exynos-fimc-lite.1", - .enable = exynos4212_clk_ip_isp0_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "fimg2d", - .enable = exynos4_clk_ip_dmc_ctrl, - .ctrlbit = (1 << 23), - }, -}; - -#ifdef CONFIG_PM_SLEEP -static int exynos4212_clock_suspend(void) -{ - s3c_pm_do_save(exynos4212_clock_save, ARRAY_SIZE(exynos4212_clock_save)); - - return 0; -} - -static void exynos4212_clock_resume(void) -{ - s3c_pm_do_restore_core(exynos4212_clock_save, ARRAY_SIZE(exynos4212_clock_save)); -} - -#else -#define exynos4212_clock_suspend NULL -#define exynos4212_clock_resume NULL -#endif - -static struct syscore_ops exynos4212_clock_syscore_ops = { - .suspend = exynos4212_clock_suspend, - .resume = exynos4212_clock_resume, -}; - -void __init exynos4212_register_clocks(void) -{ - int ptr; - - /* usbphy1 is removed */ - exynos4_clkset_group_list[4] = NULL; - - /* mout_mpll_user is used */ - exynos4_clkset_group_list[6] = &clk_mout_mpll_user.clk; - exynos4_clkset_aclk_top_list[0] = &clk_mout_mpll_user.clk; - - exynos4_clk_mout_mpll.reg_src.reg = EXYNOS4_CLKSRC_DMC; - exynos4_clk_mout_mpll.reg_src.shift = 12; - exynos4_clk_mout_mpll.reg_src.size = 1; - - for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++) - s3c_register_clksrc(sysclks[ptr], 1); - - s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); - - s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); - - register_syscore_ops(&exynos4212_clock_syscore_ops); -} diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c deleted file mode 100644 index b0ea31fc9fb8..000000000000 --- a/arch/arm/mach-exynos/clock-exynos5.c +++ /dev/null @@ -1,1645 +0,0 @@ -/* - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Clock support for EXYNOS5 SoCs - * - * 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/kernel.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/syscore_ops.h> - -#include <plat/cpu-freq.h> -#include <plat/clock.h> -#include <plat/cpu.h> -#include <plat/pll.h> -#include <plat/s5p-clock.h> -#include <plat/clock-clksrc.h> -#include <plat/pm.h> - -#include <mach/map.h> -#include <mach/regs-clock.h> - -#include "common.h" - -#ifdef CONFIG_PM_SLEEP -static struct sleep_save exynos5_clock_save[] = { - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_TOP), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_GSCL), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_DISP1_0), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_FSYS), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_MAUDIO), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_PERIC0), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_PERIC1), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_GSCL), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_DISP1), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_MFC), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_G3D), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_GEN), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_FSYS), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_PERIC), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_PERIS), - SAVE_ITEM(EXYNOS5_CLKGATE_BLOCK), - SAVE_ITEM(EXYNOS5_CLKDIV_TOP0), - SAVE_ITEM(EXYNOS5_CLKDIV_TOP1), - SAVE_ITEM(EXYNOS5_CLKDIV_GSCL), - SAVE_ITEM(EXYNOS5_CLKDIV_DISP1_0), - SAVE_ITEM(EXYNOS5_CLKDIV_GEN), - SAVE_ITEM(EXYNOS5_CLKDIV_MAUDIO), - SAVE_ITEM(EXYNOS5_CLKDIV_FSYS0), - SAVE_ITEM(EXYNOS5_CLKDIV_FSYS1), - SAVE_ITEM(EXYNOS5_CLKDIV_FSYS2), - SAVE_ITEM(EXYNOS5_CLKDIV_FSYS3), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC0), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC1), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC2), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC3), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC4), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC5), - SAVE_ITEM(EXYNOS5_SCLK_DIV_ISP), - SAVE_ITEM(EXYNOS5_CLKSRC_TOP0), - SAVE_ITEM(EXYNOS5_CLKSRC_TOP1), - SAVE_ITEM(EXYNOS5_CLKSRC_TOP2), - SAVE_ITEM(EXYNOS5_CLKSRC_TOP3), - SAVE_ITEM(EXYNOS5_CLKSRC_GSCL), - SAVE_ITEM(EXYNOS5_CLKSRC_DISP1_0), - SAVE_ITEM(EXYNOS5_CLKSRC_MAUDIO), - SAVE_ITEM(EXYNOS5_CLKSRC_FSYS), - SAVE_ITEM(EXYNOS5_CLKSRC_PERIC0), - SAVE_ITEM(EXYNOS5_CLKSRC_PERIC1), - SAVE_ITEM(EXYNOS5_SCLK_SRC_ISP), - SAVE_ITEM(EXYNOS5_EPLL_CON0), - SAVE_ITEM(EXYNOS5_EPLL_CON1), - SAVE_ITEM(EXYNOS5_EPLL_CON2), - SAVE_ITEM(EXYNOS5_VPLL_CON0), - SAVE_ITEM(EXYNOS5_VPLL_CON1), - SAVE_ITEM(EXYNOS5_VPLL_CON2), - SAVE_ITEM(EXYNOS5_PWR_CTRL1), - SAVE_ITEM(EXYNOS5_PWR_CTRL2), -}; -#endif - -static struct clk exynos5_clk_sclk_dptxphy = { - .name = "sclk_dptx", -}; - -static struct clk exynos5_clk_sclk_hdmi24m = { - .name = "sclk_hdmi24m", - .rate = 24000000, -}; - -static struct clk exynos5_clk_sclk_hdmi27m = { - .name = "sclk_hdmi27m", - .rate = 27000000, -}; - -static struct clk exynos5_clk_sclk_hdmiphy = { - .name = "sclk_hdmiphy", -}; - -static struct clk exynos5_clk_sclk_usbphy = { - .name = "sclk_usbphy", - .rate = 48000000, -}; - -static int exynos5_clksrc_mask_top_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_TOP, clk, enable); -} - -static int exynos5_clksrc_mask_disp1_0_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_DISP1_0, clk, enable); -} - -static int exynos5_clksrc_mask_fsys_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_FSYS, clk, enable); -} - -static int exynos5_clksrc_mask_gscl_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_GSCL, clk, enable); -} - -static int exynos5_clksrc_mask_peric0_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC0, clk, enable); -} - -static int exynos5_clksrc_mask_peric1_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC1, clk, enable); -} - -static int exynos5_clk_ip_acp_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ACP, clk, enable); -} - -static int exynos5_clk_ip_core_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_CORE, clk, enable); -} - -static int exynos5_clk_ip_disp1_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_DISP1, clk, enable); -} - -static int exynos5_clk_ip_fsys_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_FSYS, clk, enable); -} - -static int exynos5_clk_block_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_BLOCK, clk, enable); -} - -static int exynos5_clk_ip_gen_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GEN, clk, enable); -} - -static int exynos5_clk_ip_mfc_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_MFC, clk, enable); -} - -static int exynos5_clk_ip_peric_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIC, clk, enable); -} - -static int exynos5_clk_ip_peris_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIS, clk, enable); -} - -static int exynos5_clk_ip_gscl_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GSCL, clk, enable); -} - -static int exynos5_clk_ip_isp0_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ISP0, clk, enable); -} - -static int exynos5_clk_ip_isp1_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ISP1, clk, enable); -} - -static int exynos5_clk_hdmiphy_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable); -} - -/* Core list of CMU_CPU side */ - -static struct clksrc_clk exynos5_clk_mout_apll = { - .clk = { - .name = "mout_apll", - }, - .sources = &clk_src_apll, - .reg_src = { .reg = EXYNOS5_CLKSRC_CPU, .shift = 0, .size = 1 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_apll = { - .clk = { - .name = "sclk_apll", - .parent = &exynos5_clk_mout_apll.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 24, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_mout_bpll_fout = { - .clk = { - .name = "mout_bpll_fout", - }, - .sources = &clk_src_bpll_fout, - .reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 0, .size = 1 }, -}; - -static struct clk *exynos5_clk_src_bpll_list[] = { - [0] = &clk_fin_bpll, - [1] = &exynos5_clk_mout_bpll_fout.clk, -}; - -static struct clksrc_sources exynos5_clk_src_bpll = { - .sources = exynos5_clk_src_bpll_list, - .nr_sources = ARRAY_SIZE(exynos5_clk_src_bpll_list), -}; - -static struct clksrc_clk exynos5_clk_mout_bpll = { - .clk = { - .name = "mout_bpll", - }, - .sources = &exynos5_clk_src_bpll, - .reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 0, .size = 1 }, -}; - -static struct clk *exynos5_clk_src_bpll_user_list[] = { - [0] = &clk_fin_mpll, - [1] = &exynos5_clk_mout_bpll.clk, -}; - -static struct clksrc_sources exynos5_clk_src_bpll_user = { - .sources = exynos5_clk_src_bpll_user_list, - .nr_sources = ARRAY_SIZE(exynos5_clk_src_bpll_user_list), -}; - -static struct clksrc_clk exynos5_clk_mout_bpll_user = { - .clk = { - .name = "mout_bpll_user", - }, - .sources = &exynos5_clk_src_bpll_user, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 24, .size = 1 }, -}; - -static struct clksrc_clk exynos5_clk_mout_cpll = { - .clk = { - .name = "mout_cpll", - }, - .sources = &clk_src_cpll, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 8, .size = 1 }, -}; - -static struct clksrc_clk exynos5_clk_mout_epll = { - .clk = { - .name = "mout_epll", - }, - .sources = &clk_src_epll, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 12, .size = 1 }, -}; - -static struct clksrc_clk exynos5_clk_mout_mpll_fout = { - .clk = { - .name = "mout_mpll_fout", - }, - .sources = &clk_src_mpll_fout, - .reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 4, .size = 1 }, -}; - -static struct clk *exynos5_clk_src_mpll_list[] = { - [0] = &clk_fin_mpll, - [1] = &exynos5_clk_mout_mpll_fout.clk, -}; - -static struct clksrc_sources exynos5_clk_src_mpll = { - .sources = exynos5_clk_src_mpll_list, - .nr_sources = ARRAY_SIZE(exynos5_clk_src_mpll_list), -}; - -static struct clksrc_clk exynos5_clk_mout_mpll = { - .clk = { - .name = "mout_mpll", - }, - .sources = &exynos5_clk_src_mpll, - .reg_src = { .reg = EXYNOS5_CLKSRC_CORE1, .shift = 8, .size = 1 }, -}; - -static struct clk *exynos_clkset_vpllsrc_list[] = { - [0] = &clk_fin_vpll, - [1] = &exynos5_clk_sclk_hdmi27m, -}; - -static struct clksrc_sources exynos5_clkset_vpllsrc = { - .sources = exynos_clkset_vpllsrc_list, - .nr_sources = ARRAY_SIZE(exynos_clkset_vpllsrc_list), -}; - -static struct clksrc_clk exynos5_clk_vpllsrc = { - .clk = { - .name = "vpll_src", - .enable = exynos5_clksrc_mask_top_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos5_clkset_vpllsrc, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 0, .size = 1 }, -}; - -static struct clk *exynos5_clkset_sclk_vpll_list[] = { - [0] = &exynos5_clk_vpllsrc.clk, - [1] = &clk_fout_vpll, -}; - -static struct clksrc_sources exynos5_clkset_sclk_vpll = { - .sources = exynos5_clkset_sclk_vpll_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_sclk_vpll_list), -}; - -static struct clksrc_clk exynos5_clk_sclk_vpll = { - .clk = { - .name = "sclk_vpll", - }, - .sources = &exynos5_clkset_sclk_vpll, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 16, .size = 1 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_pixel = { - .clk = { - .name = "sclk_pixel", - .parent = &exynos5_clk_sclk_vpll.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 28, .size = 4 }, -}; - -static struct clk *exynos5_clkset_sclk_hdmi_list[] = { - [0] = &exynos5_clk_sclk_pixel.clk, - [1] = &exynos5_clk_sclk_hdmiphy, -}; - -static struct clksrc_sources exynos5_clkset_sclk_hdmi = { - .sources = exynos5_clkset_sclk_hdmi_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_sclk_hdmi_list), -}; - -static struct clksrc_clk exynos5_clk_sclk_hdmi = { - .clk = { - .name = "sclk_hdmi", - .enable = exynos5_clksrc_mask_disp1_0_ctrl, - .ctrlbit = (1 << 20), - }, - .sources = &exynos5_clkset_sclk_hdmi, - .reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 20, .size = 1 }, -}; - -static struct clksrc_clk *exynos5_sclk_tv[] = { - &exynos5_clk_sclk_pixel, - &exynos5_clk_sclk_hdmi, -}; - -static struct clk *exynos5_clk_src_mpll_user_list[] = { - [0] = &clk_fin_mpll, - [1] = &exynos5_clk_mout_mpll.clk, -}; - -static struct clksrc_sources exynos5_clk_src_mpll_user = { - .sources = exynos5_clk_src_mpll_user_list, - .nr_sources = ARRAY_SIZE(exynos5_clk_src_mpll_user_list), -}; - -static struct clksrc_clk exynos5_clk_mout_mpll_user = { - .clk = { - .name = "mout_mpll_user", - }, - .sources = &exynos5_clk_src_mpll_user, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 20, .size = 1 }, -}; - -static struct clk *exynos5_clkset_mout_cpu_list[] = { - [0] = &exynos5_clk_mout_apll.clk, - [1] = &exynos5_clk_mout_mpll.clk, -}; - -static struct clksrc_sources exynos5_clkset_mout_cpu = { - .sources = exynos5_clkset_mout_cpu_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_mout_cpu_list), -}; - -static struct clksrc_clk exynos5_clk_mout_cpu = { - .clk = { - .name = "mout_cpu", - }, - .sources = &exynos5_clkset_mout_cpu, - .reg_src = { .reg = EXYNOS5_CLKSRC_CPU, .shift = 16, .size = 1 }, -}; - -static struct clksrc_clk exynos5_clk_dout_armclk = { - .clk = { - .name = "dout_armclk", - .parent = &exynos5_clk_mout_cpu.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 0, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_dout_arm2clk = { - .clk = { - .name = "dout_arm2clk", - .parent = &exynos5_clk_dout_armclk.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 28, .size = 3 }, -}; - -static struct clk exynos5_clk_armclk = { - .name = "armclk", - .parent = &exynos5_clk_dout_arm2clk.clk, -}; - -/* Core list of CMU_CDREX side */ - -static struct clk *exynos5_clkset_cdrex_list[] = { - [0] = &exynos5_clk_mout_mpll.clk, - [1] = &exynos5_clk_mout_bpll.clk, -}; - -static struct clksrc_sources exynos5_clkset_cdrex = { - .sources = exynos5_clkset_cdrex_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_cdrex_list), -}; - -static struct clksrc_clk exynos5_clk_cdrex = { - .clk = { - .name = "clk_cdrex", - }, - .sources = &exynos5_clkset_cdrex, - .reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 4, .size = 1 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_CDREX, .shift = 16, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_aclk_acp = { - .clk = { - .name = "aclk_acp", - .parent = &exynos5_clk_mout_mpll.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_ACP, .shift = 0, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_pclk_acp = { - .clk = { - .name = "pclk_acp", - .parent = &exynos5_clk_aclk_acp.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_ACP, .shift = 4, .size = 3 }, -}; - -/* Core list of CMU_TOP side */ - -static struct clk *exynos5_clkset_aclk_top_list[] = { - [0] = &exynos5_clk_mout_mpll_user.clk, - [1] = &exynos5_clk_mout_bpll_user.clk, -}; - -static struct clksrc_sources exynos5_clkset_aclk = { - .sources = exynos5_clkset_aclk_top_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_top_list), -}; - -static struct clksrc_clk exynos5_clk_aclk_400 = { - .clk = { - .name = "aclk_400", - }, - .sources = &exynos5_clkset_aclk, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 20, .size = 1 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 }, -}; - -static struct clk *exynos5_clkset_aclk_333_166_list[] = { - [0] = &exynos5_clk_mout_cpll.clk, - [1] = &exynos5_clk_mout_mpll_user.clk, -}; - -static struct clksrc_sources exynos5_clkset_aclk_333_166 = { - .sources = exynos5_clkset_aclk_333_166_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_333_166_list), -}; - -static struct clksrc_clk exynos5_clk_aclk_333 = { - .clk = { - .name = "aclk_333", - }, - .sources = &exynos5_clkset_aclk_333_166, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 16, .size = 1 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 20, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_aclk_166 = { - .clk = { - .name = "aclk_166", - }, - .sources = &exynos5_clkset_aclk_333_166, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 8, .size = 1 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 8, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_aclk_266 = { - .clk = { - .name = "aclk_266", - .parent = &exynos5_clk_mout_mpll_user.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 16, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_aclk_200 = { - .clk = { - .name = "aclk_200", - }, - .sources = &exynos5_clkset_aclk, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 12, .size = 1 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 12, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_aclk_66_pre = { - .clk = { - .name = "aclk_66_pre", - .parent = &exynos5_clk_mout_mpll_user.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_TOP1, .shift = 24, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_aclk_66 = { - .clk = { - .name = "aclk_66", - .parent = &exynos5_clk_aclk_66_pre.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 0, .size = 3 }, -}; - -static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl_mid = { - .clk = { - .name = "mout_aclk_300_gscl_mid", - }, - .sources = &exynos5_clkset_aclk, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 24, .size = 1 }, -}; - -static struct clk *exynos5_clkset_aclk_300_mid1_list[] = { - [0] = &exynos5_clk_sclk_vpll.clk, - [1] = &exynos5_clk_mout_cpll.clk, -}; - -static struct clksrc_sources exynos5_clkset_aclk_300_gscl_mid1 = { - .sources = exynos5_clkset_aclk_300_mid1_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_300_mid1_list), -}; - -static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl_mid1 = { - .clk = { - .name = "mout_aclk_300_gscl_mid1", - }, - .sources = &exynos5_clkset_aclk_300_gscl_mid1, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP1, .shift = 12, .size = 1 }, -}; - -static struct clk *exynos5_clkset_aclk_300_gscl_list[] = { - [0] = &exynos5_clk_mout_aclk_300_gscl_mid.clk, - [1] = &exynos5_clk_mout_aclk_300_gscl_mid1.clk, -}; - -static struct clksrc_sources exynos5_clkset_aclk_300_gscl = { - .sources = exynos5_clkset_aclk_300_gscl_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_300_gscl_list), -}; - -static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl = { - .clk = { - .name = "mout_aclk_300_gscl", - }, - .sources = &exynos5_clkset_aclk_300_gscl, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 25, .size = 1 }, -}; - -static struct clk *exynos5_clk_src_gscl_300_list[] = { - [0] = &clk_ext_xtal_mux, - [1] = &exynos5_clk_mout_aclk_300_gscl.clk, -}; - -static struct clksrc_sources exynos5_clk_src_gscl_300 = { - .sources = exynos5_clk_src_gscl_300_list, - .nr_sources = ARRAY_SIZE(exynos5_clk_src_gscl_300_list), -}; - -static struct clksrc_clk exynos5_clk_aclk_300_gscl = { - .clk = { - .name = "aclk_300_gscl", - }, - .sources = &exynos5_clk_src_gscl_300, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 10, .size = 1 }, -}; - -static struct clk exynos5_init_clocks_off[] = { - { - .name = "timers", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 24), - }, { - .name = "tmu_apbif", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peris_ctrl, - .ctrlbit = (1 << 21), - }, { - .name = "rtc", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peris_ctrl, - .ctrlbit = (1 << 20), - }, { - .name = "watchdog", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peris_ctrl, - .ctrlbit = (1 << 19), - }, { - .name = "biu", /* bus interface unit clock */ - .devname = "dw_mmc.0", - .parent = &exynos5_clk_aclk_200.clk, - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 12), - }, { - .name = "biu", - .devname = "dw_mmc.1", - .parent = &exynos5_clk_aclk_200.clk, - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 13), - }, { - .name = "biu", - .devname = "dw_mmc.2", - .parent = &exynos5_clk_aclk_200.clk, - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 14), - }, { - .name = "biu", - .devname = "dw_mmc.3", - .parent = &exynos5_clk_aclk_200.clk, - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 15), - }, { - .name = "sata", - .devname = "exynos5-sata", - .parent = &exynos5_clk_aclk_200.clk, - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 6), - }, { - .name = "sata-phy", - .devname = "exynos5-sata-phy", - .parent = &exynos5_clk_aclk_200.clk, - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 24), - }, { - .name = "i2c", - .devname = "exynos5-sata-phy-i2c", - .parent = &exynos5_clk_aclk_200.clk, - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 25), - }, { - .name = "mfc", - .devname = "s5p-mfc-v6", - .enable = exynos5_clk_ip_mfc_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "hdmi", - .devname = "exynos5-hdmi", - .enable = exynos5_clk_ip_disp1_ctrl, - .ctrlbit = (1 << 6), - }, { - .name = "hdmiphy", - .devname = "exynos5-hdmi", - .enable = exynos5_clk_hdmiphy_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "mixer", - .devname = "exynos5-mixer", - .enable = exynos5_clk_ip_disp1_ctrl, - .ctrlbit = (1 << 5), - }, { - .name = "dp", - .devname = "exynos-dp", - .enable = exynos5_clk_ip_disp1_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "jpeg", - .enable = exynos5_clk_ip_gen_ctrl, - .ctrlbit = (1 << 2), - }, { - .name = "dsim0", - .enable = exynos5_clk_ip_disp1_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "iis", - .devname = "samsung-i2s.1", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 20), - }, { - .name = "iis", - .devname = "samsung-i2s.2", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 21), - }, { - .name = "pcm", - .devname = "samsung-pcm.1", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 22), - }, { - .name = "pcm", - .devname = "samsung-pcm.2", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 23), - }, { - .name = "spdif", - .devname = "samsung-spdif", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 26), - }, { - .name = "ac97", - .devname = "samsung-ac97", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 27), - }, { - .name = "usbhost", - .enable = exynos5_clk_ip_fsys_ctrl , - .ctrlbit = (1 << 18), - }, { - .name = "usbotg", - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 7), - }, { - .name = "nfcon", - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 22), - }, { - .name = "iop", - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = ((1 << 30) | (1 << 26) | (1 << 23)), - }, { - .name = "core_iop", - .enable = exynos5_clk_ip_core_ctrl, - .ctrlbit = ((1 << 21) | (1 << 3)), - }, { - .name = "mcu_iop", - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.0", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 6), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.1", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 7), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.2", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 8), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.3", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 9), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.4", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 10), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.5", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 11), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.6", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 12), - }, { - .name = "i2c", - .devname = "s3c2440-i2c.7", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 13), - }, { - .name = "i2c", - .devname = "s3c2440-hdmiphy-i2c", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 14), - }, { - .name = "spi", - .devname = "exynos4210-spi.0", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 16), - }, { - .name = "spi", - .devname = "exynos4210-spi.1", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 17), - }, { - .name = "spi", - .devname = "exynos4210-spi.2", - .parent = &exynos5_clk_aclk_66.clk, - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 18), - }, { - .name = "gscl", - .devname = "exynos-gsc.0", - .enable = exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "gscl", - .devname = "exynos-gsc.1", - .enable = exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 1), - }, { - .name = "gscl", - .devname = "exynos-gsc.2", - .enable = exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 2), - }, { - .name = "gscl", - .devname = "exynos-gsc.3", - .enable = exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.1", - .enable = &exynos5_clk_ip_mfc_ctrl, - .ctrlbit = (1 << 1), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.0", - .enable = &exynos5_clk_ip_mfc_ctrl, - .ctrlbit = (1 << 2), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.2", - .enable = &exynos5_clk_ip_disp1_ctrl, - .ctrlbit = (1 << 9) - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.3", - .enable = &exynos5_clk_ip_gen_ctrl, - .ctrlbit = (1 << 7), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.4", - .enable = &exynos5_clk_ip_gen_ctrl, - .ctrlbit = (1 << 6) - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.5", - .enable = &exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 7), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.6", - .enable = &exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 8), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.7", - .enable = &exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 9), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.8", - .enable = &exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 10), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.9", - .enable = &exynos5_clk_ip_isp0_ctrl, - .ctrlbit = (0x3F << 8), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.10", - .enable = &exynos5_clk_ip_isp1_ctrl, - .ctrlbit = (0xF << 4), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.11", - .enable = &exynos5_clk_ip_disp1_ctrl, - .ctrlbit = (1 << 8) - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.12", - .enable = &exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 11), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.13", - .enable = &exynos5_clk_ip_gscl_ctrl, - .ctrlbit = (1 << 12), - }, { - .name = "sysmmu", - .devname = "exynos-sysmmu.14", - .enable = &exynos5_clk_ip_acp_ctrl, - .ctrlbit = (1 << 7) - } -}; - -static struct clk exynos5_init_clocks_on[] = { - { - .name = "uart", - .devname = "s5pv210-uart.0", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "uart", - .devname = "s5pv210-uart.1", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 1), - }, { - .name = "uart", - .devname = "s5pv210-uart.2", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 2), - }, { - .name = "uart", - .devname = "s5pv210-uart.3", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "uart", - .devname = "s5pv210-uart.4", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "uart", - .devname = "s5pv210-uart.5", - .enable = exynos5_clk_ip_peric_ctrl, - .ctrlbit = (1 << 5), - } -}; - -static struct clk exynos5_clk_pdma0 = { - .name = "dma", - .devname = "dma-pl330.0", - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 1), -}; - -static struct clk exynos5_clk_pdma1 = { - .name = "dma", - .devname = "dma-pl330.1", - .enable = exynos5_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 2), -}; - -static struct clk exynos5_clk_mdma1 = { - .name = "dma", - .devname = "dma-pl330.2", - .enable = exynos5_clk_ip_gen_ctrl, - .ctrlbit = (1 << 4), -}; - -static struct clk exynos5_clk_fimd1 = { - .name = "fimd", - .devname = "exynos5-fb.1", - .enable = exynos5_clk_ip_disp1_ctrl, - .ctrlbit = (1 << 0), -}; - -static struct clk *exynos5_clkset_group_list[] = { - [0] = &clk_ext_xtal_mux, - [1] = NULL, - [2] = &exynos5_clk_sclk_hdmi24m, - [3] = &exynos5_clk_sclk_dptxphy, - [4] = &exynos5_clk_sclk_usbphy, - [5] = &exynos5_clk_sclk_hdmiphy, - [6] = &exynos5_clk_mout_mpll_user.clk, - [7] = &exynos5_clk_mout_epll.clk, - [8] = &exynos5_clk_sclk_vpll.clk, - [9] = &exynos5_clk_mout_cpll.clk, -}; - -static struct clksrc_sources exynos5_clkset_group = { - .sources = exynos5_clkset_group_list, - .nr_sources = ARRAY_SIZE(exynos5_clkset_group_list), -}; - -/* Possible clock sources for aclk_266_gscl_sub Mux */ -static struct clk *clk_src_gscl_266_list[] = { - [0] = &clk_ext_xtal_mux, - [1] = &exynos5_clk_aclk_266.clk, -}; - -static struct clksrc_sources clk_src_gscl_266 = { - .sources = clk_src_gscl_266_list, - .nr_sources = ARRAY_SIZE(clk_src_gscl_266_list), -}; - -static struct clksrc_clk exynos5_clk_dout_mmc0 = { - .clk = { - .name = "dout_mmc0", - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 0, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_dout_mmc1 = { - .clk = { - .name = "dout_mmc1", - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 4, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 16, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_dout_mmc2 = { - .clk = { - .name = "dout_mmc2", - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 8, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_dout_mmc3 = { - .clk = { - .name = "dout_mmc3", - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 12, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 16, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_dout_mmc4 = { - .clk = { - .name = "dout_mmc4", - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 16, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS3, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_uart0 = { - .clk = { - .name = "uclk1", - .devname = "exynos4210-uart.0", - .enable = exynos5_clksrc_mask_peric0_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 0, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_uart1 = { - .clk = { - .name = "uclk1", - .devname = "exynos4210-uart.1", - .enable = exynos5_clksrc_mask_peric0_ctrl, - .ctrlbit = (1 << 4), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 4, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 4, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_uart2 = { - .clk = { - .name = "uclk1", - .devname = "exynos4210-uart.2", - .enable = exynos5_clksrc_mask_peric0_ctrl, - .ctrlbit = (1 << 8), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 8, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 8, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_uart3 = { - .clk = { - .name = "uclk1", - .devname = "exynos4210-uart.3", - .enable = exynos5_clksrc_mask_peric0_ctrl, - .ctrlbit = (1 << 12), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 12, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 12, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_mmc0 = { - .clk = { - .name = "ciu", /* card interface unit clock */ - .devname = "dw_mmc.0", - .parent = &exynos5_clk_dout_mmc0.clk, - .enable = exynos5_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 0), - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 8, .size = 8 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_mmc1 = { - .clk = { - .name = "ciu", - .devname = "dw_mmc.1", - .parent = &exynos5_clk_dout_mmc1.clk, - .enable = exynos5_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 4), - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 24, .size = 8 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_mmc2 = { - .clk = { - .name = "ciu", - .devname = "dw_mmc.2", - .parent = &exynos5_clk_dout_mmc2.clk, - .enable = exynos5_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 8), - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 8, .size = 8 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_mmc3 = { - .clk = { - .name = "ciu", - .devname = "dw_mmc.3", - .parent = &exynos5_clk_dout_mmc3.clk, - .enable = exynos5_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 12), - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 24, .size = 8 }, -}; - -static struct clksrc_clk exynos5_clk_mdout_spi0 = { - .clk = { - .name = "mdout_spi", - .devname = "exynos4210-spi.0", - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 16, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_mdout_spi1 = { - .clk = { - .name = "mdout_spi", - .devname = "exynos4210-spi.1", - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 20, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 16, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_mdout_spi2 = { - .clk = { - .name = "mdout_spi", - .devname = "exynos4210-spi.2", - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 24, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC2, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_spi0 = { - .clk = { - .name = "sclk_spi", - .devname = "exynos4210-spi.0", - .parent = &exynos5_clk_mdout_spi0.clk, - .enable = exynos5_clksrc_mask_peric1_ctrl, - .ctrlbit = (1 << 16), - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 8, .size = 8 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_spi1 = { - .clk = { - .name = "sclk_spi", - .devname = "exynos4210-spi.1", - .parent = &exynos5_clk_mdout_spi1.clk, - .enable = exynos5_clksrc_mask_peric1_ctrl, - .ctrlbit = (1 << 20), - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 24, .size = 8 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_spi2 = { - .clk = { - .name = "sclk_spi", - .devname = "exynos4210-spi.2", - .parent = &exynos5_clk_mdout_spi2.clk, - .enable = exynos5_clksrc_mask_peric1_ctrl, - .ctrlbit = (1 << 24), - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC2, .shift = 8, .size = 8 }, -}; - -static struct clksrc_clk exynos5_clk_sclk_fimd1 = { - .clk = { - .name = "sclk_fimd", - .devname = "exynos5-fb.1", - .enable = exynos5_clksrc_mask_disp1_0_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 0, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 0, .size = 4 }, -}; - -static struct clksrc_clk exynos5_clksrcs[] = { - { - .clk = { - .name = "aclk_266_gscl", - }, - .sources = &clk_src_gscl_266, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 8, .size = 1 }, - }, { - .clk = { - .name = "sclk_g3d", - .devname = "mali-t604.0", - .enable = exynos5_clk_block_ctrl, - .ctrlbit = (1 << 1), - }, - .sources = &exynos5_clkset_aclk, - .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 20, .size = 1 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 }, - }, { - .clk = { - .name = "sclk_sata", - .devname = "exynos5-sata", - .enable = exynos5_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 24), - }, - .sources = &exynos5_clkset_aclk, - .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 24, .size = 1 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS0, .shift = 20, .size = 4 }, - }, { - .clk = { - .name = "sclk_gscl_wrap", - .devname = "s5p-mipi-csis.0", - .enable = exynos5_clksrc_mask_gscl_ctrl, - .ctrlbit = (1 << 24), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 24, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 24, .size = 4 }, - }, { - .clk = { - .name = "sclk_gscl_wrap", - .devname = "s5p-mipi-csis.1", - .enable = exynos5_clksrc_mask_gscl_ctrl, - .ctrlbit = (1 << 28), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 28, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 28, .size = 4 }, - }, { - .clk = { - .name = "sclk_cam0", - .enable = exynos5_clksrc_mask_gscl_ctrl, - .ctrlbit = (1 << 16), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 16, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 16, .size = 4 }, - }, { - .clk = { - .name = "sclk_cam1", - .enable = exynos5_clksrc_mask_gscl_ctrl, - .ctrlbit = (1 << 20), - }, - .sources = &exynos5_clkset_group, - .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 20, .size = 4 }, - .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 20, .size = 4 }, - }, { - .clk = { - .name = "sclk_jpeg", - .parent = &exynos5_clk_mout_cpll.clk, - }, - .reg_div = { .reg = EXYNOS5_CLKDIV_GEN, .shift = 4, .size = 3 }, - }, -}; - -/* Clock initialization code */ -static struct clksrc_clk *exynos5_sysclks[] = { - &exynos5_clk_mout_apll, - &exynos5_clk_sclk_apll, - &exynos5_clk_mout_bpll, - &exynos5_clk_mout_bpll_fout, - &exynos5_clk_mout_bpll_user, - &exynos5_clk_mout_cpll, - &exynos5_clk_mout_epll, - &exynos5_clk_mout_mpll, - &exynos5_clk_mout_mpll_fout, - &exynos5_clk_mout_mpll_user, - &exynos5_clk_vpllsrc, - &exynos5_clk_sclk_vpll, - &exynos5_clk_mout_cpu, - &exynos5_clk_dout_armclk, - &exynos5_clk_dout_arm2clk, - &exynos5_clk_cdrex, - &exynos5_clk_aclk_400, - &exynos5_clk_aclk_333, - &exynos5_clk_aclk_266, - &exynos5_clk_aclk_200, - &exynos5_clk_aclk_166, - &exynos5_clk_aclk_300_gscl, - &exynos5_clk_mout_aclk_300_gscl, - &exynos5_clk_mout_aclk_300_gscl_mid, - &exynos5_clk_mout_aclk_300_gscl_mid1, - &exynos5_clk_aclk_66_pre, - &exynos5_clk_aclk_66, - &exynos5_clk_dout_mmc0, - &exynos5_clk_dout_mmc1, - &exynos5_clk_dout_mmc2, - &exynos5_clk_dout_mmc3, - &exynos5_clk_dout_mmc4, - &exynos5_clk_aclk_acp, - &exynos5_clk_pclk_acp, - &exynos5_clk_sclk_spi0, - &exynos5_clk_sclk_spi1, - &exynos5_clk_sclk_spi2, - &exynos5_clk_mdout_spi0, - &exynos5_clk_mdout_spi1, - &exynos5_clk_mdout_spi2, - &exynos5_clk_sclk_fimd1, -}; - -static struct clk *exynos5_clk_cdev[] = { - &exynos5_clk_pdma0, - &exynos5_clk_pdma1, - &exynos5_clk_mdma1, - &exynos5_clk_fimd1, -}; - -static struct clksrc_clk *exynos5_clksrc_cdev[] = { - &exynos5_clk_sclk_uart0, - &exynos5_clk_sclk_uart1, - &exynos5_clk_sclk_uart2, - &exynos5_clk_sclk_uart3, - &exynos5_clk_sclk_mmc0, - &exynos5_clk_sclk_mmc1, - &exynos5_clk_sclk_mmc2, - &exynos5_clk_sclk_mmc3, -}; - -static struct clk_lookup exynos5_clk_lookup[] = { - CLKDEV_INIT("exynos4210-uart.0", "clk_uart_baud0", &exynos5_clk_sclk_uart0.clk), - CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &exynos5_clk_sclk_uart1.clk), - CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &exynos5_clk_sclk_uart2.clk), - CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &exynos5_clk_sclk_uart3.clk), - CLKDEV_INIT("exynos4-sdhci.0", "mmc_busclk.2", &exynos5_clk_sclk_mmc0.clk), - CLKDEV_INIT("exynos4-sdhci.1", "mmc_busclk.2", &exynos5_clk_sclk_mmc1.clk), - CLKDEV_INIT("exynos4-sdhci.2", "mmc_busclk.2", &exynos5_clk_sclk_mmc2.clk), - CLKDEV_INIT("exynos4-sdhci.3", "mmc_busclk.2", &exynos5_clk_sclk_mmc3.clk), - CLKDEV_INIT("exynos4210-spi.0", "spi_busclk0", &exynos5_clk_sclk_spi0.clk), - CLKDEV_INIT("exynos4210-spi.1", "spi_busclk0", &exynos5_clk_sclk_spi1.clk), - CLKDEV_INIT("exynos4210-spi.2", "spi_busclk0", &exynos5_clk_sclk_spi2.clk), - CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos5_clk_pdma0), - CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos5_clk_pdma1), - CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos5_clk_mdma1), - CLKDEV_INIT("exynos5-fb.1", "lcd", &exynos5_clk_fimd1), -}; - -static unsigned long exynos5_epll_get_rate(struct clk *clk) -{ - return clk->rate; -} - -static struct clk *exynos5_clks[] __initdata = { - &exynos5_clk_sclk_hdmi27m, - &exynos5_clk_sclk_hdmiphy, - &clk_fout_bpll, - &clk_fout_bpll_div2, - &clk_fout_cpll, - &clk_fout_mpll_div2, - &exynos5_clk_armclk, -}; - -static u32 epll_div[][6] = { - { 192000000, 0, 48, 3, 1, 0 }, - { 180000000, 0, 45, 3, 1, 0 }, - { 73728000, 1, 73, 3, 3, 47710 }, - { 67737600, 1, 90, 4, 3, 20762 }, - { 49152000, 0, 49, 3, 3, 9961 }, - { 45158400, 0, 45, 3, 3, 10381 }, - { 180633600, 0, 45, 3, 1, 10381 }, -}; - -static int exynos5_epll_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int epll_con, epll_con_k; - unsigned int i; - unsigned int tmp; - unsigned int epll_rate; - unsigned int locktime; - unsigned int lockcnt; - - /* Return if nothing changed */ - if (clk->rate == rate) - return 0; - - if (clk->parent) - epll_rate = clk_get_rate(clk->parent); - else - epll_rate = clk_ext_xtal_mux.rate; - - if (epll_rate != 24000000) { - pr_err("Invalid Clock : recommended clock is 24MHz.\n"); - return -EINVAL; - } - - epll_con = __raw_readl(EXYNOS5_EPLL_CON0); - epll_con &= ~(0x1 << 27 | \ - PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT | \ - PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | \ - PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT); - - for (i = 0; i < ARRAY_SIZE(epll_div); i++) { - if (epll_div[i][0] == rate) { - epll_con_k = epll_div[i][5] << 0; - epll_con |= epll_div[i][1] << 27; - epll_con |= epll_div[i][2] << PLL46XX_MDIV_SHIFT; - epll_con |= epll_div[i][3] << PLL46XX_PDIV_SHIFT; - epll_con |= epll_div[i][4] << PLL46XX_SDIV_SHIFT; - break; - } - } - - if (i == ARRAY_SIZE(epll_div)) { - printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", - __func__); - return -EINVAL; - } - - epll_rate /= 1000000; - - /* 3000 max_cycls : specification data */ - locktime = 3000 / epll_rate * epll_div[i][3]; - lockcnt = locktime * 10000 / (10000 / epll_rate); - - __raw_writel(lockcnt, EXYNOS5_EPLL_LOCK); - - __raw_writel(epll_con, EXYNOS5_EPLL_CON0); - __raw_writel(epll_con_k, EXYNOS5_EPLL_CON1); - - do { - tmp = __raw_readl(EXYNOS5_EPLL_CON0); - } while (!(tmp & 0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT)); - - clk->rate = rate; - - return 0; -} - -static struct clk_ops exynos5_epll_ops = { - .get_rate = exynos5_epll_get_rate, - .set_rate = exynos5_epll_set_rate, -}; - -static int xtal_rate; - -static unsigned long exynos5_fout_apll_get_rate(struct clk *clk) -{ - return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS5_APLL_CON0)); -} - -static struct clk_ops exynos5_fout_apll_ops = { - .get_rate = exynos5_fout_apll_get_rate, -}; - -#ifdef CONFIG_PM -static int exynos5_clock_suspend(void) -{ - s3c_pm_do_save(exynos5_clock_save, ARRAY_SIZE(exynos5_clock_save)); - - return 0; -} - -static void exynos5_clock_resume(void) -{ - s3c_pm_do_restore_core(exynos5_clock_save, ARRAY_SIZE(exynos5_clock_save)); -} -#else -#define exynos5_clock_suspend NULL -#define exynos5_clock_resume NULL -#endif - -static struct syscore_ops exynos5_clock_syscore_ops = { - .suspend = exynos5_clock_suspend, - .resume = exynos5_clock_resume, -}; - -void __init_or_cpufreq exynos5_setup_clocks(void) -{ - struct clk *xtal_clk; - unsigned long apll; - unsigned long bpll; - unsigned long cpll; - unsigned long mpll; - unsigned long epll; - unsigned long vpll; - unsigned long vpllsrc; - unsigned long xtal; - unsigned long armclk; - unsigned long mout_cdrex; - unsigned long aclk_400; - unsigned long aclk_333; - unsigned long aclk_266; - unsigned long aclk_200; - unsigned long aclk_166; - unsigned long aclk_66; - unsigned int ptr; - - printk(KERN_DEBUG "%s: registering clocks\n", __func__); - - xtal_clk = clk_get(NULL, "xtal"); - BUG_ON(IS_ERR(xtal_clk)); - - xtal = clk_get_rate(xtal_clk); - - xtal_rate = xtal; - - clk_put(xtal_clk); - - printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal); - - apll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_APLL_CON0)); - bpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_BPLL_CON0)); - cpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_CPLL_CON0)); - mpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_MPLL_CON0)); - epll = s5p_get_pll36xx(xtal, __raw_readl(EXYNOS5_EPLL_CON0), - __raw_readl(EXYNOS5_EPLL_CON1)); - - vpllsrc = clk_get_rate(&exynos5_clk_vpllsrc.clk); - vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(EXYNOS5_VPLL_CON0), - __raw_readl(EXYNOS5_VPLL_CON1)); - - clk_fout_apll.ops = &exynos5_fout_apll_ops; - clk_fout_bpll.rate = bpll; - clk_fout_bpll_div2.rate = bpll >> 1; - clk_fout_cpll.rate = cpll; - clk_fout_mpll.rate = mpll; - clk_fout_mpll_div2.rate = mpll >> 1; - clk_fout_epll.rate = epll; - clk_fout_vpll.rate = vpll; - - printk(KERN_INFO "EXYNOS5: PLL settings, A=%ld, B=%ld, C=%ld\n" - "M=%ld, E=%ld V=%ld", - apll, bpll, cpll, mpll, epll, vpll); - - armclk = clk_get_rate(&exynos5_clk_armclk); - mout_cdrex = clk_get_rate(&exynos5_clk_cdrex.clk); - - aclk_400 = clk_get_rate(&exynos5_clk_aclk_400.clk); - aclk_333 = clk_get_rate(&exynos5_clk_aclk_333.clk); - aclk_266 = clk_get_rate(&exynos5_clk_aclk_266.clk); - aclk_200 = clk_get_rate(&exynos5_clk_aclk_200.clk); - aclk_166 = clk_get_rate(&exynos5_clk_aclk_166.clk); - aclk_66 = clk_get_rate(&exynos5_clk_aclk_66.clk); - - printk(KERN_INFO "EXYNOS5: ARMCLK=%ld, CDREX=%ld, ACLK400=%ld\n" - "ACLK333=%ld, ACLK266=%ld, ACLK200=%ld\n" - "ACLK166=%ld, ACLK66=%ld\n", - armclk, mout_cdrex, aclk_400, - aclk_333, aclk_266, aclk_200, - aclk_166, aclk_66); - - - clk_fout_epll.ops = &exynos5_epll_ops; - - if (clk_set_parent(&exynos5_clk_mout_epll.clk, &clk_fout_epll)) - printk(KERN_ERR "Unable to set parent %s of clock %s.\n", - clk_fout_epll.name, exynos5_clk_mout_epll.clk.name); - - clk_set_rate(&exynos5_clk_sclk_apll.clk, 100000000); - clk_set_rate(&exynos5_clk_aclk_266.clk, 300000000); - - clk_set_rate(&exynos5_clk_aclk_acp.clk, 267000000); - clk_set_rate(&exynos5_clk_pclk_acp.clk, 134000000); - - for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrcs); ptr++) - s3c_set_clksrc(&exynos5_clksrcs[ptr], true); -} - -void __init exynos5_register_clocks(void) -{ - int ptr; - - s3c24xx_register_clocks(exynos5_clks, ARRAY_SIZE(exynos5_clks)); - - for (ptr = 0; ptr < ARRAY_SIZE(exynos5_sysclks); ptr++) - s3c_register_clksrc(exynos5_sysclks[ptr], 1); - - for (ptr = 0; ptr < ARRAY_SIZE(exynos5_sclk_tv); ptr++) - s3c_register_clksrc(exynos5_sclk_tv[ptr], 1); - - for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrc_cdev); ptr++) - s3c_register_clksrc(exynos5_clksrc_cdev[ptr], 1); - - s3c_register_clksrc(exynos5_clksrcs, ARRAY_SIZE(exynos5_clksrcs)); - s3c_register_clocks(exynos5_init_clocks_on, ARRAY_SIZE(exynos5_init_clocks_on)); - - s3c24xx_register_clocks(exynos5_clk_cdev, ARRAY_SIZE(exynos5_clk_cdev)); - for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clk_cdev); ptr++) - s3c_disable_clocks(exynos5_clk_cdev[ptr], 1); - - s3c_register_clocks(exynos5_init_clocks_off, ARRAY_SIZE(exynos5_init_clocks_off)); - s3c_disable_clocks(exynos5_init_clocks_off, ARRAY_SIZE(exynos5_init_clocks_off)); - clkdev_add_table(exynos5_clk_lookup, ARRAY_SIZE(exynos5_clk_lookup)); - - register_syscore_ops(&exynos5_clock_syscore_ops); - s3c_pwmclk_init(); -} diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index d63d399c7bae..939bda77defa 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -25,6 +25,8 @@ #include <linux/irqdomain.h> #include <linux/irqchip.h> #include <linux/of_address.h> +#include <linux/clocksource.h> +#include <linux/clk-provider.h> #include <linux/irqchip/arm-gic.h> #include <asm/proc-fns.h> @@ -37,9 +39,9 @@ #include <mach/regs-irq.h> #include <mach/regs-pmu.h> #include <mach/regs-gpio.h> +#include <mach/irqs.h> #include <plat/cpu.h> -#include <plat/clock.h> #include <plat/devs.h> #include <plat/pm.h> #include <plat/sdhci.h> @@ -65,17 +67,16 @@ static const char name_exynos5440[] = "EXYNOS5440"; static void exynos4_map_io(void); static void exynos5_map_io(void); static void exynos5440_map_io(void); -static void exynos4_init_clocks(int xtal); -static void exynos5_init_clocks(int xtal); static void exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no); static int exynos_init(void); +unsigned long xxti_f = 0, xusbxti_f = 0; + static struct cpu_table cpu_ids[] __initdata = { { .idcode = EXYNOS4210_CPU_ID, .idmask = EXYNOS4_CPU_MASK, .map_io = exynos4_map_io, - .init_clocks = exynos4_init_clocks, .init_uarts = exynos4_init_uarts, .init = exynos_init, .name = name_exynos4210, @@ -83,7 +84,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = EXYNOS4212_CPU_ID, .idmask = EXYNOS4_CPU_MASK, .map_io = exynos4_map_io, - .init_clocks = exynos4_init_clocks, .init_uarts = exynos4_init_uarts, .init = exynos_init, .name = name_exynos4212, @@ -91,7 +91,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = EXYNOS4412_CPU_ID, .idmask = EXYNOS4_CPU_MASK, .map_io = exynos4_map_io, - .init_clocks = exynos4_init_clocks, .init_uarts = exynos4_init_uarts, .init = exynos_init, .name = name_exynos4412, @@ -99,7 +98,6 @@ static struct cpu_table cpu_ids[] __initdata = { .idcode = EXYNOS5250_SOC_ID, .idmask = EXYNOS5_SOC_MASK, .map_io = exynos5_map_io, - .init_clocks = exynos5_init_clocks, .init = exynos_init, .name = name_exynos5250, }, { @@ -257,11 +255,6 @@ static struct map_desc exynos5_iodesc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE, }, { - .virtual = (unsigned long)S5P_VA_SYSTIMER, - .pfn = __phys_to_pfn(EXYNOS5_PA_SYSTIMER), - .length = SZ_4K, - .type = MT_DEVICE, - }, { .virtual = (unsigned long)S5P_VA_SYSRAM, .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM), .length = SZ_4K, @@ -402,43 +395,26 @@ static void __init exynos5_map_io(void) iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc)); } -static void __init exynos4_init_clocks(int xtal) -{ - printk(KERN_DEBUG "%s: initializing clocks\n", __func__); - - s3c24xx_register_baseclocks(xtal); - s5p_register_clocks(xtal); - - if (soc_is_exynos4210()) - exynos4210_register_clocks(); - else if (soc_is_exynos4212() || soc_is_exynos4412()) - exynos4212_register_clocks(); - - exynos4_register_clocks(); - exynos4_setup_clocks(); -} - static void __init exynos5440_map_io(void) { iotable_init(exynos5440_iodesc0, ARRAY_SIZE(exynos5440_iodesc0)); } -static void __init exynos5_init_clocks(int xtal) +void __init exynos_init_time(void) { - printk(KERN_DEBUG "%s: initializing clocks\n", __func__); - - /* EXYNOS5440 can support only common clock framework */ - - if (soc_is_exynos5440()) - return; - -#ifdef CONFIG_SOC_EXYNOS5250 - s3c24xx_register_baseclocks(xtal); - s5p_register_clocks(xtal); - - exynos5_register_clocks(); - exynos5_setup_clocks(); + if (of_have_populated_dt()) { +#ifdef CONFIG_OF + of_clk_init(NULL); + clocksource_of_init(); +#endif + } else { + /* todo: remove after migrating legacy E4 platforms to dt */ +#ifdef CONFIG_ARCH_EXYNOS4 + exynos4_clk_init(NULL); + exynos4_clk_register_fixed_ext(xxti_f, xusbxti_f); #endif + mct_init(); + } } void __init exynos4_init_irq(void) @@ -822,6 +798,7 @@ static int __init exynos_init_irq_eint(void) static const struct of_device_id exynos_pinctrl_ids[] = { { .compatible = "samsung,exynos4210-pinctrl", }, { .compatible = "samsung,exynos4x12-pinctrl", }, + { .compatible = "samsung,exynos5250-pinctrl", }, }; struct device_node *pctrl_np, *wkup_np; const char *wkup_compat = "samsung,exynos4210-wakeup-eint"; @@ -875,3 +852,30 @@ static int __init exynos_init_irq_eint(void) return 0; } arch_initcall(exynos_init_irq_eint); + +static struct resource exynos4_pmu_resource[] = { + DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU), + DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU1), +#if defined(CONFIG_SOC_EXYNOS4412) + DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU2), + DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU3), +#endif +}; + +static struct platform_device exynos4_device_pmu = { + .name = "arm-pmu", + .num_resources = ARRAY_SIZE(exynos4_pmu_resource), + .resource = exynos4_pmu_resource, +}; + +static int __init exynos_armpmu_init(void) +{ + if (!of_have_populated_dt()) { + if (soc_is_exynos4210() || soc_is_exynos4212()) + exynos4_device_pmu.num_resources = 2; + platform_device_register(&exynos4_device_pmu); + } + + return 0; +} +arch_initcall(exynos_armpmu_init); diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 9339bb8954be..cb89ab886950 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -12,7 +12,11 @@ #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H #define __ARCH_ARM_MACH_EXYNOS_COMMON_H -extern void exynos4_timer_init(void); +#include <linux/of.h> + +extern void mct_init(void); +void exynos_init_time(void); +extern unsigned long xxti_f, xusbxti_f; struct map_desc; void exynos_init_io(struct map_desc *mach_desc, int size); @@ -22,6 +26,10 @@ void exynos4_restart(char mode, const char *cmd); void exynos5_restart(char mode, const char *cmd); void exynos_init_late(void); +/* ToDo: remove these after migrating legacy exynos4 platforms to dt */ +void exynos4_clk_init(struct device_node *np); +void exynos4_clk_register_fixed_ext(unsigned long, unsigned long); + #ifdef CONFIG_PM_GENERIC_DOMAINS int exynos_pm_late_initcall(void); #else diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h index 1f4dc35cd4b9..35fe6d52d230 100644 --- a/arch/arm/mach-exynos/include/mach/irqs.h +++ b/arch/arm/mach-exynos/include/mach/irqs.h @@ -30,8 +30,6 @@ /* For EXYNOS4 and EXYNOS5 */ -#define EXYNOS_IRQ_MCT_LOCALTIMER IRQ_PPI(12) - #define EXYNOS_IRQ_EINT16_31 IRQ_SPI(32) /* For EXYNOS4 SoCs */ @@ -128,7 +126,7 @@ #define EXYNOS4_IRQ_ADC1 IRQ_SPI(107) #define EXYNOS4_IRQ_PEN1 IRQ_SPI(108) #define EXYNOS4_IRQ_KEYPAD IRQ_SPI(109) -#define EXYNOS4_IRQ_PMU IRQ_SPI(110) +#define EXYNOS4_IRQ_POWER_PMU IRQ_SPI(110) #define EXYNOS4_IRQ_GPS IRQ_SPI(111) #define EXYNOS4_IRQ_INTFEEDCTRL_SSS IRQ_SPI(112) #define EXYNOS4_IRQ_SLIMBUS IRQ_SPI(113) @@ -136,6 +134,11 @@ #define EXYNOS4_IRQ_TSI IRQ_SPI(115) #define EXYNOS4_IRQ_SATA IRQ_SPI(116) +#define EXYNOS4_IRQ_PMU COMBINER_IRQ(2, 2) +#define EXYNOS4_IRQ_PMU_CPU1 COMBINER_IRQ(3, 2) +#define EXYNOS4_IRQ_PMU_CPU2 COMBINER_IRQ(18, 2) +#define EXYNOS4_IRQ_PMU_CPU3 COMBINER_IRQ(19, 2) + #define EXYNOS4_IRQ_TMU_TRIG0 COMBINER_IRQ(2, 4) #define EXYNOS4_IRQ_TMU_TRIG1 COMBINER_IRQ(3, 4) @@ -168,7 +171,10 @@ #define EXYNOS4_IRQ_FIMD0_VSYNC COMBINER_IRQ(11, 1) #define EXYNOS4_IRQ_FIMD0_SYSTEM COMBINER_IRQ(11, 2) -#define EXYNOS4_MAX_COMBINER_NR 16 +#define EXYNOS4210_MAX_COMBINER_NR 16 +#define EXYNOS4212_MAX_COMBINER_NR 18 +#define EXYNOS4412_MAX_COMBINER_NR 20 +#define EXYNOS4_MAX_COMBINER_NR EXYNOS4412_MAX_COMBINER_NR #define EXYNOS4_IRQ_GPIO1_NR_GROUPS 16 #define EXYNOS4_IRQ_GPIO2_NR_GROUPS 9 @@ -233,7 +239,6 @@ #define IRQ_TC EXYNOS4_IRQ_PEN0 #define IRQ_KEYPAD EXYNOS4_IRQ_KEYPAD -#define IRQ_PMU EXYNOS4_IRQ_PMU #define IRQ_FIMD0_FIFO EXYNOS4_IRQ_FIMD0_FIFO #define IRQ_FIMD0_VSYNC EXYNOS4_IRQ_FIMD0_VSYNC @@ -323,8 +328,6 @@ #define EXYNOS5_IRQ_CEC IRQ_SPI(114) #define EXYNOS5_IRQ_SATA IRQ_SPI(115) -#define EXYNOS5_IRQ_MCT_L0 IRQ_SPI(120) -#define EXYNOS5_IRQ_MCT_L1 IRQ_SPI(121) #define EXYNOS5_IRQ_MMC44 IRQ_SPI(123) #define EXYNOS5_IRQ_MDMA1 IRQ_SPI(124) #define EXYNOS5_IRQ_FIMC_LITE0 IRQ_SPI(125) @@ -419,8 +422,6 @@ #define EXYNOS5_IRQ_PMU_CPU1 COMBINER_IRQ(22, 4) #define EXYNOS5_IRQ_EINT0 COMBINER_IRQ(23, 0) -#define EXYNOS5_IRQ_MCT_G0 COMBINER_IRQ(23, 3) -#define EXYNOS5_IRQ_MCT_G1 COMBINER_IRQ(23, 4) #define EXYNOS5_IRQ_EINT1 COMBINER_IRQ(24, 0) #define EXYNOS5_IRQ_SYSMMU_LITE1_0 COMBINER_IRQ(24, 1) diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 1df6abbf53b8..7f99b7b187d6 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -65,7 +65,6 @@ #define EXYNOS5_PA_CMU 0x10010000 #define EXYNOS4_PA_SYSTIMER 0x10050000 -#define EXYNOS5_PA_SYSTIMER 0x101C0000 #define EXYNOS4_PA_WATCHDOG 0x10060000 #define EXYNOS5_PA_WATCHDOG 0x101D0000 diff --git a/arch/arm/mach-exynos/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h index d36ad76ad6a4..20fbbdddd105 100644 --- a/arch/arm/mach-exynos/include/mach/regs-clock.h +++ b/arch/arm/mach-exynos/include/mach/regs-clock.h @@ -256,113 +256,6 @@ #define EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT (0) #define EXYNOS4_CLKDIV_CAM1_JPEG_MASK (0xf << EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT) -/* For EXYNOS5250 */ - -#define EXYNOS5_APLL_LOCK EXYNOS_CLKREG(0x00000) -#define EXYNOS5_APLL_CON0 EXYNOS_CLKREG(0x00100) -#define EXYNOS5_CLKSRC_CPU EXYNOS_CLKREG(0x00200) -#define EXYNOS5_CLKMUX_STATCPU EXYNOS_CLKREG(0x00400) -#define EXYNOS5_CLKDIV_CPU0 EXYNOS_CLKREG(0x00500) -#define EXYNOS5_CLKDIV_CPU1 EXYNOS_CLKREG(0x00504) -#define EXYNOS5_CLKDIV_STATCPU0 EXYNOS_CLKREG(0x00600) -#define EXYNOS5_CLKDIV_STATCPU1 EXYNOS_CLKREG(0x00604) - -#define EXYNOS5_PWR_CTRL1 EXYNOS_CLKREG(0x01020) -#define EXYNOS5_PWR_CTRL2 EXYNOS_CLKREG(0x01024) - -#define EXYNOS5_MPLL_CON0 EXYNOS_CLKREG(0x04100) -#define EXYNOS5_CLKSRC_CORE1 EXYNOS_CLKREG(0x04204) - -#define EXYNOS5_CLKGATE_IP_CORE EXYNOS_CLKREG(0x04900) - -#define EXYNOS5_CLKDIV_ACP EXYNOS_CLKREG(0x08500) - -#define EXYNOS5_EPLL_CON0 EXYNOS_CLKREG(0x10130) -#define EXYNOS5_EPLL_CON1 EXYNOS_CLKREG(0x10134) -#define EXYNOS5_EPLL_CON2 EXYNOS_CLKREG(0x10138) -#define EXYNOS5_VPLL_CON0 EXYNOS_CLKREG(0x10140) -#define EXYNOS5_VPLL_CON1 EXYNOS_CLKREG(0x10144) -#define EXYNOS5_VPLL_CON2 EXYNOS_CLKREG(0x10148) -#define EXYNOS5_CPLL_CON0 EXYNOS_CLKREG(0x10120) - -#define EXYNOS5_CLKSRC_TOP0 EXYNOS_CLKREG(0x10210) -#define EXYNOS5_CLKSRC_TOP1 EXYNOS_CLKREG(0x10214) -#define EXYNOS5_CLKSRC_TOP2 EXYNOS_CLKREG(0x10218) -#define EXYNOS5_CLKSRC_TOP3 EXYNOS_CLKREG(0x1021C) -#define EXYNOS5_CLKSRC_GSCL EXYNOS_CLKREG(0x10220) -#define EXYNOS5_CLKSRC_DISP1_0 EXYNOS_CLKREG(0x1022C) -#define EXYNOS5_CLKSRC_MAUDIO EXYNOS_CLKREG(0x10240) -#define EXYNOS5_CLKSRC_FSYS EXYNOS_CLKREG(0x10244) -#define EXYNOS5_CLKSRC_PERIC0 EXYNOS_CLKREG(0x10250) -#define EXYNOS5_CLKSRC_PERIC1 EXYNOS_CLKREG(0x10254) -#define EXYNOS5_SCLK_SRC_ISP EXYNOS_CLKREG(0x10270) - -#define EXYNOS5_CLKSRC_MASK_TOP EXYNOS_CLKREG(0x10310) -#define EXYNOS5_CLKSRC_MASK_GSCL EXYNOS_CLKREG(0x10320) -#define EXYNOS5_CLKSRC_MASK_DISP1_0 EXYNOS_CLKREG(0x1032C) -#define EXYNOS5_CLKSRC_MASK_MAUDIO EXYNOS_CLKREG(0x10334) -#define EXYNOS5_CLKSRC_MASK_FSYS EXYNOS_CLKREG(0x10340) -#define EXYNOS5_CLKSRC_MASK_PERIC0 EXYNOS_CLKREG(0x10350) -#define EXYNOS5_CLKSRC_MASK_PERIC1 EXYNOS_CLKREG(0x10354) - -#define EXYNOS5_CLKDIV_TOP0 EXYNOS_CLKREG(0x10510) -#define EXYNOS5_CLKDIV_TOP1 EXYNOS_CLKREG(0x10514) -#define EXYNOS5_CLKDIV_GSCL EXYNOS_CLKREG(0x10520) -#define EXYNOS5_CLKDIV_DISP1_0 EXYNOS_CLKREG(0x1052C) -#define EXYNOS5_CLKDIV_GEN EXYNOS_CLKREG(0x1053C) -#define EXYNOS5_CLKDIV_MAUDIO EXYNOS_CLKREG(0x10544) -#define EXYNOS5_CLKDIV_FSYS0 EXYNOS_CLKREG(0x10548) -#define EXYNOS5_CLKDIV_FSYS1 EXYNOS_CLKREG(0x1054C) -#define EXYNOS5_CLKDIV_FSYS2 EXYNOS_CLKREG(0x10550) -#define EXYNOS5_CLKDIV_FSYS3 EXYNOS_CLKREG(0x10554) -#define EXYNOS5_CLKDIV_PERIC0 EXYNOS_CLKREG(0x10558) -#define EXYNOS5_CLKDIV_PERIC1 EXYNOS_CLKREG(0x1055C) -#define EXYNOS5_CLKDIV_PERIC2 EXYNOS_CLKREG(0x10560) -#define EXYNOS5_CLKDIV_PERIC3 EXYNOS_CLKREG(0x10564) -#define EXYNOS5_CLKDIV_PERIC4 EXYNOS_CLKREG(0x10568) -#define EXYNOS5_CLKDIV_PERIC5 EXYNOS_CLKREG(0x1056C) -#define EXYNOS5_SCLK_DIV_ISP EXYNOS_CLKREG(0x10580) - -#define EXYNOS5_CLKGATE_IP_ACP EXYNOS_CLKREG(0x08800) -#define EXYNOS5_CLKGATE_IP_ISP0 EXYNOS_CLKREG(0x0C800) -#define EXYNOS5_CLKGATE_IP_ISP1 EXYNOS_CLKREG(0x0C804) -#define EXYNOS5_CLKGATE_IP_GSCL EXYNOS_CLKREG(0x10920) -#define EXYNOS5_CLKGATE_IP_DISP1 EXYNOS_CLKREG(0x10928) -#define EXYNOS5_CLKGATE_IP_MFC EXYNOS_CLKREG(0x1092C) -#define EXYNOS5_CLKGATE_IP_G3D EXYNOS_CLKREG(0x10930) -#define EXYNOS5_CLKGATE_IP_GEN EXYNOS_CLKREG(0x10934) -#define EXYNOS5_CLKGATE_IP_FSYS EXYNOS_CLKREG(0x10944) -#define EXYNOS5_CLKGATE_IP_GPS EXYNOS_CLKREG(0x1094C) -#define EXYNOS5_CLKGATE_IP_PERIC EXYNOS_CLKREG(0x10950) -#define EXYNOS5_CLKGATE_IP_PERIS EXYNOS_CLKREG(0x10960) -#define EXYNOS5_CLKGATE_BLOCK EXYNOS_CLKREG(0x10980) - -#define EXYNOS5_BPLL_CON0 EXYNOS_CLKREG(0x20110) -#define EXYNOS5_CLKSRC_CDREX EXYNOS_CLKREG(0x20200) -#define EXYNOS5_CLKDIV_CDREX EXYNOS_CLKREG(0x20500) - -#define EXYNOS5_PLL_DIV2_SEL EXYNOS_CLKREG(0x20A24) - -#define EXYNOS5_EPLL_LOCK EXYNOS_CLKREG(0x10030) - -#define EXYNOS5_EPLLCON0_LOCKED_SHIFT (29) - -#define PWR_CTRL1_CORE2_DOWN_RATIO (7 << 28) -#define PWR_CTRL1_CORE1_DOWN_RATIO (7 << 16) -#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9) -#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8) -#define PWR_CTRL1_USE_CORE1_WFE (1 << 5) -#define PWR_CTRL1_USE_CORE0_WFE (1 << 4) -#define PWR_CTRL1_USE_CORE1_WFI (1 << 1) -#define PWR_CTRL1_USE_CORE0_WFI (1 << 0) - -#define PWR_CTRL2_DIV2_UP_EN (1 << 25) -#define PWR_CTRL2_DIV1_UP_EN (1 << 24) -#define PWR_CTRL2_DUR_STANDBY2_VAL (1 << 16) -#define PWR_CTRL2_DUR_STANDBY1_VAL (1 << 8) -#define PWR_CTRL2_CORE2_UP_RATIO (1 << 4) -#define PWR_CTRL2_CORE1_UP_RATIO (1 << 0) - /* Compatibility defines and inclusion */ #include <mach/regs-pmu.h> diff --git a/arch/arm/mach-exynos/include/mach/regs-mct.h b/arch/arm/mach-exynos/include/mach/regs-mct.h deleted file mode 100644 index 80dd02ad6d61..000000000000 --- a/arch/arm/mach-exynos/include/mach/regs-mct.h +++ /dev/null @@ -1,53 +0,0 @@ -/* arch/arm/mach-exynos4/include/mach/regs-mct.h - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS4 MCT configutation - * - * 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 __ASM_ARCH_REGS_MCT_H -#define __ASM_ARCH_REGS_MCT_H __FILE__ - -#include <mach/map.h> - -#define EXYNOS4_MCTREG(x) (S5P_VA_SYSTIMER + (x)) - -#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100) -#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104) -#define EXYNOS4_MCT_G_CNT_WSTAT EXYNOS4_MCTREG(0x110) - -#define EXYNOS4_MCT_G_COMP0_L EXYNOS4_MCTREG(0x200) -#define EXYNOS4_MCT_G_COMP0_U EXYNOS4_MCTREG(0x204) -#define EXYNOS4_MCT_G_COMP0_ADD_INCR EXYNOS4_MCTREG(0x208) - -#define EXYNOS4_MCT_G_TCON EXYNOS4_MCTREG(0x240) - -#define EXYNOS4_MCT_G_INT_CSTAT EXYNOS4_MCTREG(0x244) -#define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248) -#define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C) - -#define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300) -#define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * x)) -#define EXYNOS4_MCT_L_MASK (0xffffff00) - -#define MCT_L_TCNTB_OFFSET (0x00) -#define MCT_L_ICNTB_OFFSET (0x08) -#define MCT_L_TCON_OFFSET (0x20) -#define MCT_L_INT_CSTAT_OFFSET (0x30) -#define MCT_L_INT_ENB_OFFSET (0x34) -#define MCT_L_WSTAT_OFFSET (0x40) - -#define MCT_G_TCON_START (1 << 8) -#define MCT_G_TCON_COMP0_AUTO_INC (1 << 1) -#define MCT_G_TCON_COMP0_ENABLE (1 << 0) - -#define MCT_L_TCON_INTERVAL_MODE (1 << 2) -#define MCT_L_TCON_INT_START (1 << 1) -#define MCT_L_TCON_TIMER_START (1 << 0) - -#endif /* __ASM_ARCH_REGS_MCT_H */ diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c index 685f29173afa..2c23b659ae3e 100644 --- a/arch/arm/mach-exynos/mach-armlex4210.c +++ b/arch/arm/mach-exynos/mach-armlex4210.c @@ -177,7 +177,6 @@ static void __init armlex4210_smsc911x_init(void) static void __init armlex4210_map_io(void) { exynos_init_io(NULL, 0); - s3c24xx_init_clocks(24000000); s3c24xx_init_uarts(armlex4210_uartcfgs, ARRAY_SIZE(armlex4210_uartcfgs)); } @@ -202,6 +201,6 @@ MACHINE_START(ARMLEX4210, "ARMLEX4210") .map_io = armlex4210_map_io, .init_machine = armlex4210_machine_init, .init_late = exynos_init_late, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .restart = exynos4_restart, MACHINE_END diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c index 3358088c822a..ac27f3cd121f 100644 --- a/arch/arm/mach-exynos/mach-exynos4-dt.c +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c @@ -11,121 +11,26 @@ * published by the Free Software Foundation. */ +#include <linux/kernel.h> #include <linux/of_platform.h> +#include <linux/of_fdt.h> #include <linux/serial_core.h> +#include <linux/memblock.h> +#include <linux/clocksource.h> #include <asm/mach/arch.h> -#include <mach/map.h> - -#include <plat/cpu.h> -#include <plat/regs-serial.h> +#include <plat/mfc.h> #include "common.h" -/* - * The following lookup table is used to override device names when devices - * are registered from device tree. This is temporarily added to enable - * device tree support addition for the Exynos4 architecture. - * - * For drivers that require platform data to be provided from the machine - * file, a platform data pointer can also be supplied along with the - * devices names. Usually, the platform data elements that cannot be parsed - * from the device tree by the drivers (example: function pointers) are - * supplied. But it should be noted that this is a temporary mechanism and - * at some point, the drivers should be capable of parsing all the platform - * data from the device tree. - */ -static const struct of_dev_auxdata exynos4_auxdata_lookup[] __initconst = { - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART0, - "exynos4210-uart.0", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART1, - "exynos4210-uart.1", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART2, - "exynos4210-uart.2", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART3, - "exynos4210-uart.3", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(0), - "exynos4-sdhci.0", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(1), - "exynos4-sdhci.1", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(2), - "exynos4-sdhci.2", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(3), - "exynos4-sdhci.3", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(0), - "s3c2440-i2c.0", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(1), - "s3c2440-i2c.1", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(2), - "s3c2440-i2c.2", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(3), - "s3c2440-i2c.3", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(4), - "s3c2440-i2c.4", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(5), - "s3c2440-i2c.5", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(6), - "s3c2440-i2c.6", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(7), - "s3c2440-i2c.7", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS4_PA_SPI0, - "exynos4210-spi.0", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS4_PA_SPI1, - "exynos4210-spi.1", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS4_PA_SPI2, - "exynos4210-spi.2", NULL), - OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_PDMA0, "dma-pl330.0", NULL), - OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_PDMA1, "dma-pl330.1", NULL), - OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_MDMA1, "dma-pl330.2", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-tmu", EXYNOS4_PA_TMU, - "exynos-tmu", NULL), - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13620000, - "exynos-sysmmu.0", NULL), /* MFC_L */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13630000, - "exynos-sysmmu.1", NULL), /* MFC_R */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13E20000, - "exynos-sysmmu.2", NULL), /* TV */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11A60000, - "exynos-sysmmu.3", NULL), /* JPEG */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x12A30000, - "exynos-sysmmu.4", NULL), /* ROTATOR */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11A20000, - "exynos-sysmmu.5", NULL), /* FIMC0 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11A30000, - "exynos-sysmmu.6", NULL), /* FIMC1 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11A40000, - "exynos-sysmmu.7", NULL), /* FIMC2 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11A50000, - "exynos-sysmmu.8", NULL), /* FIMC3 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x12A20000, - "exynos-sysmmu.9", NULL), /* G2D(4210) */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x10A40000, - "exynos-sysmmu.9", NULL), /* G2D(4x12) */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11E20000, - "exynos-sysmmu.10", NULL), /* FIMD0 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x12220000, - "exynos-sysmmu.11", NULL), /* FIMD1(4210) */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x12260000, - "exynos-sysmmu.12", NULL), /* IS0(4x12) */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x122B0000, - "exynos-sysmmu.13", NULL), /* IS1(4x12) */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x123B0000, - "exynos-sysmmu.14", NULL), /* FIMC-LITE0(4x12) */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x123C0000, - "exynos-sysmmu.15", NULL), /* FIMC-LITE1(4x12) */ - {}, -}; - static void __init exynos4_dt_map_io(void) { exynos_init_io(NULL, 0); - s3c24xx_init_clocks(24000000); } static void __init exynos4_dt_machine_init(void) { - of_platform_populate(NULL, of_default_bus_match_table, - exynos4_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static char const *exynos4_dt_compat[] __initdata = { @@ -135,6 +40,18 @@ static char const *exynos4_dt_compat[] __initdata = { NULL }; +static void __init exynos4_reserve(void) +{ +#ifdef CONFIG_S5P_DEV_MFC + struct s5p_mfc_dt_meminfo mfc_mem; + + /* Reserve memory for MFC only if it's available */ + mfc_mem.compatible = "samsung,mfc-v5"; + if (of_scan_flat_dt(s5p_fdt_find_mfc_mem, &mfc_mem)) + s5p_mfc_reserve_mem(mfc_mem.roff, mfc_mem.rsize, mfc_mem.loff, + mfc_mem.lsize); +#endif +} DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)") /* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */ .smp = smp_ops(exynos_smp_ops), @@ -142,7 +59,8 @@ DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)") .map_io = exynos4_dt_map_io, .init_machine = exynos4_dt_machine_init, .init_late = exynos_init_late, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .dt_compat = exynos4_dt_compat, .restart = exynos4_restart, + .reserve = exynos4_reserve, MACHINE_END diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index acaeb14db54b..753b94f3fca7 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -11,151 +11,21 @@ #include <linux/of_platform.h> #include <linux/of_fdt.h> -#include <linux/serial_core.h> #include <linux/memblock.h> #include <linux/io.h> +#include <linux/clocksource.h> #include <asm/mach/arch.h> -#include <mach/map.h> #include <mach/regs-pmu.h> #include <plat/cpu.h> -#include <plat/regs-serial.h> #include <plat/mfc.h> #include "common.h" -/* - * The following lookup table is used to override device names when devices - * are registered from device tree. This is temporarily added to enable - * device tree support addition for the EXYNOS5 architecture. - * - * For drivers that require platform data to be provided from the machine - * file, a platform data pointer can also be supplied along with the - * devices names. Usually, the platform data elements that cannot be parsed - * from the device tree by the drivers (example: function pointers) are - * supplied. But it should be noted that this is a temporary mechanism and - * at some point, the drivers should be capable of parsing all the platform - * data from the device tree. - */ -static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART0, - "exynos4210-uart.0", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART1, - "exynos4210-uart.1", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART2, - "exynos4210-uart.2", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART3, - "exynos4210-uart.3", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(0), - "s3c2440-i2c.0", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(1), - "s3c2440-i2c.1", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(2), - "s3c2440-i2c.2", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(3), - "s3c2440-i2c.3", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(4), - "s3c2440-i2c.4", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(5), - "s3c2440-i2c.5", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(6), - "s3c2440-i2c.6", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(7), - "s3c2440-i2c.7", NULL), - OF_DEV_AUXDATA("samsung,s3c2440-hdmiphy-i2c", EXYNOS5_PA_IIC(8), - "s3c2440-hdmiphy-i2c", NULL), - OF_DEV_AUXDATA("samsung,exynos5250-dw-mshc", EXYNOS5_PA_DWMCI0, - "dw_mmc.0", NULL), - OF_DEV_AUXDATA("samsung,exynos5250-dw-mshc", EXYNOS5_PA_DWMCI1, - "dw_mmc.1", NULL), - OF_DEV_AUXDATA("samsung,exynos5250-dw-mshc", EXYNOS5_PA_DWMCI2, - "dw_mmc.2", NULL), - OF_DEV_AUXDATA("samsung,exynos5250-dw-mshc", EXYNOS5_PA_DWMCI3, - "dw_mmc.3", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS5_PA_SPI0, - "exynos4210-spi.0", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS5_PA_SPI1, - "exynos4210-spi.1", NULL), - OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS5_PA_SPI2, - "exynos4210-spi.2", NULL), - OF_DEV_AUXDATA("samsung,exynos5-sata-ahci", 0x122F0000, - "exynos5-sata", NULL), - OF_DEV_AUXDATA("samsung,exynos5-sata-phy", 0x12170000, - "exynos5-sata-phy", NULL), - OF_DEV_AUXDATA("samsung,exynos5-sata-phy-i2c", 0x121D0000, - "exynos5-sata-phy-i2c", NULL), - OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL), - OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL), - OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_MDMA1, "dma-pl330.2", NULL), - OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC0, - "exynos-gsc.0", NULL), - OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC1, - "exynos-gsc.1", NULL), - OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC2, - "exynos-gsc.2", NULL), - OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC3, - "exynos-gsc.3", NULL), - OF_DEV_AUXDATA("samsung,exynos5-hdmi", 0x14530000, - "exynos5-hdmi", NULL), - OF_DEV_AUXDATA("samsung,exynos5-mixer", 0x14450000, - "exynos5-mixer", NULL), - OF_DEV_AUXDATA("samsung,mfc-v6", 0x11000000, "s5p-mfc-v6", NULL), - OF_DEV_AUXDATA("samsung,exynos5250-tmu", 0x10060000, - "exynos-tmu", NULL), - OF_DEV_AUXDATA("samsung,i2s-v5", 0x03830000, - "samsung-i2s.0", NULL), - OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D60000, - "samsung-i2s.1", NULL), - OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D70000, - "samsung-i2s.2", NULL), - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11210000, - "exynos-sysmmu.0", "mfc"), /* MFC_L */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11200000, - "exynos-sysmmu.1", "mfc"), /* MFC_R */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x14650000, - "exynos-sysmmu.2", NULL), /* TV */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11F20000, - "exynos-sysmmu.3", "jpeg"), /* JPEG */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x11D40000, - "exynos-sysmmu.4", NULL), /* ROTATOR */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13E80000, - "exynos-sysmmu.5", "gscl"), /* GSCL0 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13E90000, - "exynos-sysmmu.6", "gscl"), /* GSCL1 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13EA0000, - "exynos-sysmmu.7", "gscl"), /* GSCL2 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13EB0000, - "exynos-sysmmu.8", "gscl"), /* GSCL3 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13260000, - "exynos-sysmmu.9", NULL), /* FIMC-IS0 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x132C0000, - "exynos-sysmmu.10", NULL), /* FIMC-IS1 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x14640000, - "exynos-sysmmu.11", NULL), /* FIMD1 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13C40000, - "exynos-sysmmu.12", NULL), /* FIMC-LITE0 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x13C50000, - "exynos-sysmmu.13", NULL), /* FIMC-LITE1 */ - OF_DEV_AUXDATA("samsung,exynos-sysmmu", 0x10A60000, - "exynos-sysmmu.14", NULL), /* G2D */ - {}, -}; - -static const struct of_dev_auxdata exynos5440_auxdata_lookup[] __initconst = { - OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5440_PA_UART0, - "exynos4210-uart.0", NULL), - {}, -}; - static void __init exynos5_dt_map_io(void) { - unsigned long root = of_get_flat_dt_root(); - exynos_init_io(NULL, 0); - - if (of_flat_dt_is_compatible(root, "samsung,exynos5250")) - s3c24xx_init_clocks(24000000); } static void __init exynos5_dt_machine_init(void) @@ -182,12 +52,7 @@ static void __init exynos5_dt_machine_init(void) } } - if (of_machine_is_compatible("samsung,exynos5250")) - of_platform_populate(NULL, of_default_bus_match_table, - exynos5250_auxdata_lookup, NULL); - else if (of_machine_is_compatible("samsung,exynos5440")) - of_platform_populate(NULL, of_default_bus_match_table, - exynos5440_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static char const *exynos5_dt_compat[] __initdata = { @@ -216,7 +81,7 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)") .map_io = exynos5_dt_map_io, .init_machine = exynos5_dt_machine_init, .init_late = exynos_init_late, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .dt_compat = exynos5_dt_compat, .restart = exynos5_restart, .reserve = exynos5_reserve, diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 1ea79730187f..0c10852423c3 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1330,8 +1330,9 @@ static struct platform_device *nuri_devices[] __initdata = { static void __init nuri_map_io(void) { exynos_init_io(NULL, 0); - s3c24xx_init_clocks(clk_xusbxti.rate); s3c24xx_init_uarts(nuri_uartcfgs, ARRAY_SIZE(nuri_uartcfgs)); + xxti_f = 0; + xusbxti_f = 24000000; } static void __init nuri_reserve(void) @@ -1380,7 +1381,7 @@ MACHINE_START(NURI, "NURI") .map_io = nuri_map_io, .init_machine = nuri_machine_init, .init_late = exynos_init_late, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .reserve = &nuri_reserve, .restart = exynos4_restart, MACHINE_END diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 579d2d171daa..a9aa5c034b23 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -754,8 +754,9 @@ static void s5p_tv_setup(void) static void __init origen_map_io(void) { exynos_init_io(NULL, 0); - s3c24xx_init_clocks(clk_xusbxti.rate); s3c24xx_init_uarts(origen_uartcfgs, ARRAY_SIZE(origen_uartcfgs)); + xxti_f = 0; + xusbxti_f = 24000000; } static void __init origen_power_init(void) @@ -815,7 +816,7 @@ MACHINE_START(ORIGEN, "ORIGEN") .map_io = origen_map_io, .init_machine = origen_machine_init, .init_late = exynos_init_late, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .reserve = &origen_reserve, .restart = exynos4_restart, MACHINE_END diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c index fe6149624b84..184faa3bd93a 100644 --- a/arch/arm/mach-exynos/mach-smdk4x12.c +++ b/arch/arm/mach-exynos/mach-smdk4x12.c @@ -322,7 +322,6 @@ static struct platform_device *smdk4x12_devices[] __initdata = { static void __init smdk4x12_map_io(void) { exynos_init_io(NULL, 0); - s3c24xx_init_clocks(clk_xusbxti.rate); s3c24xx_init_uarts(smdk4x12_uartcfgs, ARRAY_SIZE(smdk4x12_uartcfgs)); } @@ -376,7 +375,7 @@ MACHINE_START(SMDK4212, "SMDK4212") .init_irq = exynos4_init_irq, .map_io = smdk4x12_map_io, .init_machine = smdk4x12_machine_init, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .restart = exynos4_restart, .reserve = &smdk4x12_reserve, MACHINE_END @@ -390,7 +389,7 @@ MACHINE_START(SMDK4412, "SMDK4412") .map_io = smdk4x12_map_io, .init_machine = smdk4x12_machine_init, .init_late = exynos_init_late, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .restart = exynos4_restart, .reserve = &smdk4x12_reserve, MACHINE_END diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index d71672922b19..75eca7d4e128 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -371,8 +371,9 @@ static void s5p_tv_setup(void) static void __init smdkv310_map_io(void) { exynos_init_io(NULL, 0); - s3c24xx_init_clocks(clk_xusbxti.rate); s3c24xx_init_uarts(smdkv310_uartcfgs, ARRAY_SIZE(smdkv310_uartcfgs)); + xxti_f = 12000000; + xusbxti_f = 24000000; } static void __init smdkv310_reserve(void) @@ -423,7 +424,7 @@ MACHINE_START(SMDKV310, "SMDKV310") .init_irq = exynos4_init_irq, .map_io = smdkv310_map_io, .init_machine = smdkv310_machine_init, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .reserve = &smdkv310_reserve, .restart = exynos4_restart, MACHINE_END @@ -436,7 +437,7 @@ MACHINE_START(SMDKC210, "SMDKC210") .map_io = smdkv310_map_io, .init_machine = smdkv310_machine_init, .init_late = exynos_init_late, - .init_time = exynos4_timer_init, + .init_time = exynos_init_time, .reserve = &smdkv310_reserve, .restart = exynos4_restart, MACHINE_END diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 497fcb793dc1..72f08fd7cfa9 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -41,7 +41,7 @@ #include <plat/mfc.h> #include <plat/sdhci.h> #include <plat/fimc-core.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> #include <plat/camport.h> #include <mach/map.h> @@ -1092,9 +1092,10 @@ static struct platform_device *universal_devices[] __initdata = { static void __init universal_map_io(void) { exynos_init_io(NULL, 0); - s3c24xx_init_clocks(clk_xusbxti.rate); s3c24xx_init_uarts(universal_uartcfgs, ARRAY_SIZE(universal_uartcfgs)); - s5p_set_timer_source(S5P_PWM2, S5P_PWM4); + samsung_set_timer_source(SAMSUNG_PWM2, SAMSUNG_PWM4); + xxti_f = 0; + xusbxti_f = 24000000; } static void s5p_tv_setup(void) @@ -1152,7 +1153,7 @@ MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") .map_io = universal_map_io, .init_machine = universal_machine_init, .init_late = exynos_init_late, - .init_time = s5p_timer_init, + .init_time = samsung_timer_init, .reserve = &universal_reserve, .restart = exynos4_restart, MACHINE_END diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index a4f9f50247d4..76c1170b3528 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -32,7 +32,6 @@ #include <asm/cacheflush.h> #include <asm/cputype.h> #include <asm/smp_plat.h> -#include <asm/smp_twd.h> #include <asm/hardware/arm_timer.h> #include <asm/hardware/timer-sp.h> #include <asm/hardware/cache-l2x0.h> @@ -119,10 +118,10 @@ static void __init highbank_timer_init(void) sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1"); sp804_clockevents_init(timer_base, irq, "timer0"); - twd_local_timer_of_register(); - arch_timer_of_register(); arch_timer_sched_clock_init(); + + clocksource_of_init(); } static void highbank_power_off(void) diff --git a/arch/arm/mach-imx/clk-busy.c b/arch/arm/mach-imx/clk-busy.c index 1ab91b5209e6..85b728cc27ab 100644 --- a/arch/arm/mach-imx/clk-busy.c +++ b/arch/arm/mach-imx/clk-busy.c @@ -169,7 +169,7 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, busy->mux.reg = reg; busy->mux.shift = shift; - busy->mux.width = width; + busy->mux.mask = BIT(width) - 1; busy->mux.lock = &imx_ccm_lock; busy->mux_ops = &clk_mux_ops; diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 9ffd103b27e4..b59ddcb57c78 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -12,6 +12,7 @@ #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/clocksource.h> #include <linux/cpu.h> #include <linux/delay.h> #include <linux/export.h> @@ -28,11 +29,9 @@ #include <linux/regmap.h> #include <linux/micrel_phy.h> #include <linux/mfd/syscon.h> -#include <asm/smp_twd.h> #include <asm/hardware/cache-l2x0.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <asm/mach/time.h> #include <asm/system_misc.h> #include "common.h" @@ -292,7 +291,7 @@ static void __init imx6q_init_irq(void) static void __init imx6q_timer_init(void) { mx6q_clocks_init(); - twd_local_timer_of_register(); + clocksource_of_init(); imx_print_silicon_rev("i.MX6Q", imx6q_revision()); } diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index ea961445e0e9..b23c8e4f28e8 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -536,16 +536,14 @@ static void __init ap_init_of(void) 'A' + (ap_sc_id & 0x0f)); soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR_OR_NULL(soc_dev)) { + if (IS_ERR(soc_dev)) { kfree(soc_dev_attr->revision); kfree(soc_dev_attr); return; } parent = soc_device_to_device(soc_dev); - - if (!IS_ERR_OR_NULL(parent)) - integrator_init_sysfs(parent, ap_sc_id); + integrator_init_sysfs(parent, ap_sc_id); of_platform_populate(root, of_default_bus_match_table, ap_auxdata_lookup, parent); diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 2b0db82a5381..da1091be0887 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -360,17 +360,14 @@ static void __init intcp_init_of(void) 'A' + (intcp_sc_id & 0x0f)); soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR_OR_NULL(soc_dev)) { + if (IS_ERR(soc_dev)) { kfree(soc_dev_attr->revision); kfree(soc_dev_attr); return; } parent = soc_device_to_device(soc_dev); - - if (!IS_ERR_OR_NULL(parent)) - integrator_init_sysfs(parent, intcp_sc_id); - + integrator_init_sysfs(parent, intcp_sc_id); of_platform_populate(root, of_default_bus_match_table, intcp_auxdata_lookup, parent); } diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 3218f1f2c0e0..e7b781d3788f 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -41,8 +41,6 @@ static struct fb_videomode mx23evk_video_modes[] = { .lower_margin = 4, .hsync_len = 1, .vsync_len = 1, - .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT | - FB_SYNC_DOTCLK_FAILING_ACT, }, }; @@ -59,8 +57,6 @@ static struct fb_videomode mx28evk_video_modes[] = { .lower_margin = 10, .hsync_len = 10, .vsync_len = 10, - .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT | - FB_SYNC_DOTCLK_FAILING_ACT, }, }; @@ -77,7 +73,6 @@ static struct fb_videomode m28evk_video_modes[] = { .lower_margin = 45, .hsync_len = 1, .vsync_len = 1, - .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT, }, }; @@ -94,9 +89,7 @@ static struct fb_videomode apx4devkit_video_modes[] = { .lower_margin = 13, .hsync_len = 48, .vsync_len = 3, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | - FB_SYNC_DATA_ENABLE_HIGH_ACT | - FB_SYNC_DOTCLK_FAILING_ACT, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, }, }; @@ -113,9 +106,7 @@ static struct fb_videomode apf28dev_video_modes[] = { .lower_margin = 0x15, .hsync_len = 64, .vsync_len = 4, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | - FB_SYNC_DATA_ENABLE_HIGH_ACT | - FB_SYNC_DOTCLK_FAILING_ACT, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, }, }; @@ -132,7 +123,6 @@ static struct fb_videomode cfa10049_video_modes[] = { .lower_margin = 2, .hsync_len = 15, .vsync_len = 15, - .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT }, }; @@ -259,6 +249,8 @@ static void __init imx23_evk_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes); mxsfb_pdata.default_bpp = 32; mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT | + MXSFB_SYNC_DOTCLK_FAILING_ACT; } static inline void enable_clk_enet_out(void) @@ -278,6 +270,8 @@ static void __init imx28_evk_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes); mxsfb_pdata.default_bpp = 32; mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT | + MXSFB_SYNC_DOTCLK_FAILING_ACT; mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0); } @@ -297,6 +291,7 @@ static void __init m28evk_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes); mxsfb_pdata.default_bpp = 16; mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT; } static void __init sc_sps1_init(void) @@ -322,6 +317,8 @@ static void __init apx4devkit_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(apx4devkit_video_modes); mxsfb_pdata.default_bpp = 32; mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT | + MXSFB_SYNC_DOTCLK_FAILING_ACT; } #define ENET0_MDC__GPIO_4_0 MXS_GPIO_NR(4, 0) @@ -407,6 +404,7 @@ static void __init cfa10049_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(cfa10049_video_modes); mxsfb_pdata.default_bpp = 32; mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT; } static void __init cfa10037_init(void) @@ -423,6 +421,8 @@ static void __init apf28_init(void) mxsfb_pdata.mode_count = ARRAY_SIZE(apf28dev_video_modes); mxsfb_pdata.default_bpp = 16; mxsfb_pdata.ld_intf_width = STMLCDIF_16BIT; + mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT | + MXSFB_SYNC_DOTCLK_FAILING_ACT; } static void __init mxs_machine_init(void) diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 903da8eb886c..cdd05f2e67ee 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -55,12 +55,6 @@ config MACH_OMAP_H3 TI OMAP 1710 H3 board support. Say Y here if you have such a board. -config MACH_OMAP_HTCWIZARD - bool "HTC Wizard" - depends on ARCH_OMAP850 - help - HTC Wizard smartphone support (AKA QTEK 9100, ...) - config MACH_HERALD bool "HTC Herald" depends on ARCH_OMAP850 diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 8111cd9ff3e5..b9c0ed3f648c 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -408,7 +408,7 @@ config OMAP3_SDRC_AC_TIMING config OMAP4_ERRATA_I688 bool "OMAP4 errata: Async Bridge Corruption" - depends on ARCH_OMAP4 && !ARCH_MULTIPLATFORM + depends on (ARCH_OMAP4 || SOC_OMAP5) && !ARCH_MULTIPLATFORM select ARCH_HAS_BARRIERS help If a data is stalled inside asynchronous bridge because of back diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index a3e0aaa4886b..cb0596b631cf 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -166,7 +166,7 @@ static void __init sdp2430_display_init(void) omap_display_init(&sdp2430_dss_data); } -#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE) +#if IS_ENABLED(CONFIG_SMC91X) static struct omap_smc91x_platform_data board_smc91x_data = { .cs = 5, diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index ce812decfaca..7eb9651dd0f7 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -445,16 +445,23 @@ static void enable_board_wakeup_source(void) OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); } +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 1, + .reset_gpio = 57, + .vcc_gpio = -EINVAL, + }, + { + .port = 2, + .reset_gpio = 61, + .vcc_gpio = -EINVAL, + }, +}; + 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, - - .phy_reset = true, - .reset_gpio_port[0] = 57, - .reset_gpio_port[1] = 61, - .reset_gpio_port[2] = -EINVAL }; #ifdef CONFIG_OMAP_MUX @@ -606,6 +613,8 @@ static void __init omap_3430sdp_init(void) board_flash_init(sdp_flash_partitions, chip_sel_3430, 0); sdp3430_display_init(); enable_board_wakeup_source(); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); } diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c index 67447bd4564f..20d6d8189240 100644 --- a/arch/arm/mach-omap2/board-3630sdp.c +++ b/arch/arm/mach-omap2/board-3630sdp.c @@ -53,16 +53,23 @@ static void enable_board_wakeup_source(void) OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); } +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 1, + .reset_gpio = 126, + .vcc_gpio = -EINVAL, + }, + { + .port = 2, + .reset_gpio = 61, + .vcc_gpio = -EINVAL, + }, +}; + 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, - - .phy_reset = true, - .reset_gpio_port[0] = 126, - .reset_gpio_port[1] = 61, - .reset_gpio_port[2] = -EINVAL }; #ifdef CONFIG_OMAP_MUX @@ -199,6 +206,8 @@ static void __init omap_sdp_init(void) board_smc91x_init(); board_flash_init(sdp_flash_partitions, chip_sel_sdp, NAND_BUSWIDTH_16); enable_board_wakeup_source(); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); } diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c index 7d3358b2e593..fc53911d0d13 100644 --- a/arch/arm/mach-omap2/board-am3517crane.c +++ b/arch/arm/mach-omap2/board-am3517crane.c @@ -47,15 +47,17 @@ static struct omap_board_mux board_mux[] __initdata = { }; #endif +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 1, + .reset_gpio = GPIO_USB_NRESET, + .vcc_gpio = GPIO_USB_POWER, + .vcc_polarity = 1, + }, +}; + 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, - - .phy_reset = true, - .reset_gpio_port[0] = GPIO_USB_NRESET, - .reset_gpio_port[1] = -EINVAL, - .reset_gpio_port[2] = -EINVAL }; static struct mtd_partition crane_nand_partitions[] = { @@ -131,13 +133,7 @@ static void __init am3517_crane_init(void) return; } - ret = gpio_request_one(GPIO_USB_POWER, GPIOF_OUT_INIT_HIGH, - "usb_ehci_enable"); - if (ret < 0) { - pr_err("Can not request GPIO %d\n", GPIO_USB_POWER); - return; - } - + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1); } diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 9fb85908a61e..191f9762ba63 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -274,6 +274,14 @@ static __init void am3517_evm_mcbsp1_init(void) omap_ctrl_writel(devconf0, OMAP2_CONTROL_DEVCONF0); } +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 1, + .reset_gpio = 57, + .vcc_gpio = -EINVAL, + }, +}; + static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, #if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \ @@ -282,12 +290,6 @@ static struct usbhs_omap_platform_data usbhs_bdata __initdata = { #else .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, #endif - .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, - - .phy_reset = true, - .reset_gpio_port[0] = 57, - .reset_gpio_port[1] = -EINVAL, - .reset_gpio_port[2] = -EINVAL }; #ifdef CONFIG_OMAP_MUX @@ -349,7 +351,6 @@ static struct omap2_hsmmc_info mmc[] = { {} /* Terminator */ }; - static void __init am3517_evm_init(void) { omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); @@ -361,6 +362,8 @@ static void __init am3517_evm_init(void) /* Configure GPIO for EHCI port */ omap_mux_init_gpio(57, OMAP_PIN_OUTPUT); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); am3517_evm_hecc_init(&am3517_evm_hecc_pdata); /* DSS */ diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index af2bb219e214..7fda3f5f8a7f 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -419,15 +419,22 @@ static struct omap2_hsmmc_info mmc[] = { {} /* Terminator */ }; +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 1, + .reset_gpio = OMAP_MAX_GPIO_LINES + 6, + .vcc_gpio = -EINVAL, + }, + { + .port = 2, + .reset_gpio = OMAP_MAX_GPIO_LINES + 7, + .vcc_gpio = -EINVAL, + }, +}; + 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, - - .phy_reset = true, - .reset_gpio_port[0] = OMAP_MAX_GPIO_LINES + 6, - .reset_gpio_port[1] = OMAP_MAX_GPIO_LINES + 7, - .reset_gpio_port[2] = -EINVAL }; static void __init cm_t35_init_usbh(void) @@ -444,6 +451,7 @@ static void __init cm_t35_init_usbh(void) msleep(1); } + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); } diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c index a66da808cc4a..4eb5e6f2f7f5 100644 --- a/arch/arm/mach-omap2/board-cm-t3517.c +++ b/arch/arm/mach-omap2/board-cm-t3517.c @@ -188,15 +188,22 @@ static inline void cm_t3517_init_rtc(void) {} #define HSUSB2_RESET_GPIO (147) #define USB_HUB_RESET_GPIO (152) +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 1, + .reset_gpio = HSUSB1_RESET_GPIO, + .vcc_gpio = -EINVAL, + }, + { + .port = 2, + .reset_gpio = HSUSB2_RESET_GPIO, + .vcc_gpio = -EINVAL, + }, +}; + 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, - - .phy_reset = true, - .reset_gpio_port[0] = HSUSB1_RESET_GPIO, - .reset_gpio_port[1] = HSUSB2_RESET_GPIO, - .reset_gpio_port[2] = -EINVAL, }; static int __init cm_t3517_init_usbh(void) @@ -213,6 +220,7 @@ static int __init cm_t3517_init_usbh(void) msleep(1); } + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&cm_t3517_ehci_pdata); return 0; @@ -324,6 +332,6 @@ MACHINE_START(CM_T3517, "Compulab CM-T3517") .handle_irq = omap3_intc_handle_irq, .init_machine = cm_t3517_init, .init_late = am35xx_init_late, - .init_time = omap3_gp_gptimer_timer_init, + .init_time = omap3_gptimer_timer_init, .restart = omap3xxx_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c index 53056c3b0836..42fbf1ef12a9 100644 --- a/arch/arm/mach-omap2/board-devkit8000.c +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -437,15 +437,7 @@ static struct platform_device *devkit8000_devices[] __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, - - .phy_reset = true, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = -EINVAL, - .reset_gpio_port[2] = -EINVAL }; #ifdef CONFIG_OMAP_MUX diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index e54a48060198..78813b397209 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -140,7 +140,7 @@ DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)") .init_irq = omap_intc_of_init, .handle_irq = omap3_intc_handle_irq, .init_machine = omap_generic_init, - .init_time = omap3_am33xx_gptimer_timer_init, + .init_time = omap3_gptimer_timer_init, .dt_compat = am33xx_boards_compat, .restart = am33xx_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 812c829fa46f..5b4ec51c385f 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -246,7 +246,7 @@ static u32 is_gpmc_muxed(void) return 0; } -#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE) +#if IS_ENABLED(CONFIG_SMC91X) static struct omap_smc91x_platform_data board_smc91x_data = { .cs = 1, diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index bf92678a01d0..95ccec0eeab9 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -527,26 +527,28 @@ static void __init igep_i2c_init(void) omap3_pmic_init("twl4030", &igep_twldata); } +static struct usbhs_phy_data igep2_phy_data[] __initdata = { + { + .port = 1, + .reset_gpio = IGEP2_GPIO_USBH_NRESET, + .vcc_gpio = -EINVAL, + }, +}; + +static struct usbhs_phy_data igep3_phy_data[] __initdata = { + { + .port = 2, + .reset_gpio = IGEP3_GPIO_USBH_NRESET, + .vcc_gpio = -EINVAL, + }, +}; + 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, - - .phy_reset = true, - .reset_gpio_port[0] = IGEP2_GPIO_USBH_NRESET, - .reset_gpio_port[1] = -EINVAL, - .reset_gpio_port[2] = -EINVAL, }; 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, - - .phy_reset = true, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = IGEP3_GPIO_USBH_NRESET, - .reset_gpio_port[2] = -EINVAL, }; #ifdef CONFIG_OMAP_MUX @@ -642,8 +644,10 @@ static void __init igep_init(void) if (machine_is_igep0020()) { omap_display_init(&igep2_dss_data); igep2_init_smsc911x(); + usbhs_init_phys(igep2_phy_data, ARRAY_SIZE(igep2_phy_data)); usbhs_init(&igep2_usbhs_bdata); } else { + usbhs_init_phys(igep3_phy_data, ARRAY_SIZE(igep3_phy_data)); usbhs_init(&igep3_usbhs_bdata); } } diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index c3558f93d42c..6955a428f534 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -33,6 +33,7 @@ #include <linux/mtd/nand.h> #include <linux/mmc/host.h> #include <linux/usb/phy.h> +#include <linux/usb/nop-usb-xceiv.h> #include <linux/regulator/machine.h> #include <linux/i2c/twl.h> @@ -277,6 +278,21 @@ static struct regulator_consumer_supply beagle_vsim_supply[] = { static struct gpio_led gpio_leds[]; +/* PHY's VCC regulator might be added later, so flag that we need it */ +static struct nop_usb_xceiv_platform_data hsusb2_phy_data = { + .needs_vcc = true, +}; + +static struct usbhs_phy_data phy_data[] = { + { + .port = 2, + .reset_gpio = 147, + .vcc_gpio = -1, /* updated in beagle_twl_gpio_setup */ + .vcc_polarity = 1, /* updated in beagle_twl_gpio_setup */ + .platform_data = &hsusb2_phy_data, + }, +}; + static int beagle_twl_gpio_setup(struct device *dev, unsigned gpio, unsigned ngpio) { @@ -318,9 +334,11 @@ static int beagle_twl_gpio_setup(struct device *dev, } dvi_panel.power_down_gpio = beagle_config.dvi_pd_gpio; - gpio_request_one(gpio + TWL4030_GPIO_MAX, beagle_config.usb_pwr_level, - "nEN_USB_PWR"); + /* TWL4030_GPIO_MAX i.e. LED_GPO controls HS USB Port 2 power */ + phy_data[0].vcc_gpio = gpio + TWL4030_GPIO_MAX; + phy_data[0].vcc_polarity = beagle_config.usb_pwr_level; + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); return 0; } @@ -453,15 +471,7 @@ static struct platform_device *omap3_beagle_devices[] __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, - .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, - - .phy_reset = true, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = 147, - .reset_gpio_port[2] = -EINVAL }; #ifdef CONFIG_OMAP_MUX @@ -479,7 +489,7 @@ static int __init beagle_opp_init(void) /* Initialize the omap3 opp table if not already created. */ r = omap3_opp_init(); - if (IS_ERR_VALUE(r) && (r != -EEXIST)) { + if (r < 0 && (r != -EEXIST)) { pr_err("%s: opp default init failed\n", __func__); return r; } @@ -543,7 +553,9 @@ static void __init omap3_beagle_init(void) usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb"); usb_musb_init(NULL); + usbhs_init(&usbhs_bdata); + board_nand_init(omap3beagle_nand_partitions, ARRAY_SIZE(omap3beagle_nand_partitions), NAND_CS, NAND_BUSWIDTH_16, NULL); diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 48789e0bb915..2de92facc8a3 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -496,7 +496,7 @@ struct wl12xx_platform_data omap3evm_wlan_data __initdata = { static struct regulator_consumer_supply omap3evm_vaux2_supplies[] = { REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"), /* OMAP ISP */ REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"), /* OMAP ISP */ - REGULATOR_SUPPLY("hsusb1", "ehci-omap.0"), + REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */ REGULATOR_SUPPLY("vaux2", NULL), }; @@ -539,17 +539,16 @@ static int __init omap3_evm_i2c_init(void) return 0; } -static struct usbhs_omap_platform_data usbhs_bdata __initdata = { +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 2, + .reset_gpio = -1, /* set at runtime */ + .vcc_gpio = -EINVAL, + }, +}; - .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, +static struct usbhs_omap_platform_data usbhs_bdata __initdata = { .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, - .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, - - .phy_reset = true, - /* PHY reset GPIO will be runtime programmed based on EVM version */ - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = -EINVAL, - .reset_gpio_port[2] = -EINVAL }; #ifdef CONFIG_OMAP_MUX @@ -725,7 +724,7 @@ static void __init omap3_evm_init(void) /* setup EHCI phy reset config */ omap_mux_init_gpio(21, OMAP_PIN_INPUT_PULLUP); - usbhs_bdata.reset_gpio_port[1] = 21; + phy_data[0].reset_gpio = 21; /* EVM REV >= E can supply 500mA with EXTVBUS programming */ musb_board_data.power = 500; @@ -733,10 +732,12 @@ static void __init omap3_evm_init(void) } else { /* setup EHCI phy reset on MDC */ omap_mux_init_gpio(135, OMAP_PIN_OUTPUT); - usbhs_bdata.reset_gpio_port[1] = 135; + phy_data[0].reset_gpio = 135; } usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb"); usb_musb_init(&musb_board_data); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); board_nand_init(omap3evm_nand_partitions, ARRAY_SIZE(omap3evm_nand_partitions), NAND_CS, diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index 2bba362148a0..1004d2aaa68f 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -346,7 +346,7 @@ static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = { }; static struct regulator_consumer_supply pandora_usb_phy_supply[] = { - REGULATOR_SUPPLY("hsusb1", "ehci-omap.0"), + REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */ }; /* ads7846 on SPI and 2 nub controllers on I2C */ @@ -561,6 +561,14 @@ fail: printk(KERN_ERR "wl1251 board initialisation failed\n"); } +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 2, + .reset_gpio = 16, + .vcc_gpio = -EINVAL, + }, +}; + static struct platform_device *omap3pandora_devices[] __initdata = { &pandora_leds_gpio, &pandora_keys_gpio, @@ -569,15 +577,7 @@ static struct platform_device *omap3pandora_devices[] __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, - .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, - - .phy_reset = true, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = 16, - .reset_gpio_port[2] = -EINVAL }; #ifdef CONFIG_OMAP_MUX @@ -601,7 +601,10 @@ static void __init omap3pandora_init(void) spi_register_board_info(omap3pandora_spi_board_info, ARRAY_SIZE(omap3pandora_spi_board_info)); omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); + usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb"); usb_musb_init(NULL); gpmc_nand_init(&pandora_nand_data, NULL); diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c index 95c10b3aa678..bf0956489899 100644 --- a/arch/arm/mach-omap2/board-omap3stalker.c +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -358,19 +358,20 @@ static int __init omap3_stalker_i2c_init(void) #define OMAP3_STALKER_TS_GPIO 175 +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 2, + .reset_gpio = 21, + .vcc_gpio = -EINVAL, + }, +}; + static struct platform_device *omap3_stalker_devices[] __initdata = { &keys_gpio, }; 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, - - .phy_reset = true, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = 21, - .reset_gpio_port[2] = -EINVAL, }; #ifdef CONFIG_OMAP_MUX @@ -407,6 +408,8 @@ static void __init omap3_stalker_init(void) omap_sdrc_init(mt46h32m32lf6_sdrc_params, NULL); usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb"); usb_musb_init(NULL); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); omap_ads7846_init(1, OMAP3_STALKER_TS_GPIO, 310, NULL); diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c index bcd44fbcd877..7da48bc42bbf 100644 --- a/arch/arm/mach-omap2/board-omap3touchbook.c +++ b/arch/arm/mach-omap2/board-omap3touchbook.c @@ -305,21 +305,22 @@ static struct omap_board_mux board_mux[] __initdata = { }; #endif +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 2, + .reset_gpio = 147, + .vcc_gpio = -EINVAL, + }, +}; + static struct platform_device *omap3_touchbook_devices[] __initdata = { &leds_gpio, &keys_gpio, }; 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, - - .phy_reset = true, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = 147, - .reset_gpio_port[2] = -EINVAL }; static void omap3_touchbook_poweroff(void) @@ -368,6 +369,8 @@ static void __init omap3_touchbook_init(void) omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata); usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb"); usb_musb_init(NULL); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); board_nand_init(omap3touchbook_nand_partitions, ARRAY_SIZE(omap3touchbook_nand_partitions), NAND_CS, diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index b02c2f00609b..a71ad345f20d 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -31,6 +31,7 @@ #include <linux/ti_wilink_st.h> #include <linux/usb/musb.h> #include <linux/usb/phy.h> +#include <linux/usb/nop-usb-xceiv.h> #include <linux/wl12xx.h> #include <linux/irqchip/arm-gic.h> #include <linux/platform_data/omap-abe-twl6040.h> @@ -132,6 +133,22 @@ static struct platform_device btwilink_device = { .id = -1, }; +/* PHY device on HS USB Port 1 i.e. nop_usb_xceiv.1 */ +static struct nop_usb_xceiv_platform_data hsusb1_phy_data = { + /* FREF_CLK3 provides the 19.2 MHz reference clock to the PHY */ + .clk_rate = 19200000, +}; + +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 1, + .reset_gpio = GPIO_HUB_NRESET, + .vcc_gpio = GPIO_HUB_POWER, + .vcc_polarity = 1, + .platform_data = &hsusb1_phy_data, + }, +}; + static struct platform_device *panda_devices[] __initdata = { &leds_gpio, &wl1271_device, @@ -142,49 +159,19 @@ static struct platform_device *panda_devices[] __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, - .phy_reset = false, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = -EINVAL, - .reset_gpio_port[2] = -EINVAL -}; - -static struct gpio panda_ehci_gpios[] __initdata = { - { GPIO_HUB_POWER, GPIOF_OUT_INIT_LOW, "hub_power" }, - { GPIO_HUB_NRESET, GPIOF_OUT_INIT_LOW, "hub_nreset" }, }; static void __init omap4_ehci_init(void) { int ret; - struct clk *phy_ref_clk; /* FREF_CLK3 provides the 19.2 MHz reference clock to the PHY */ - phy_ref_clk = clk_get(NULL, "auxclk3_ck"); - if (IS_ERR(phy_ref_clk)) { - pr_err("Cannot request auxclk3\n"); - return; - } - clk_set_rate(phy_ref_clk, 19200000); - clk_prepare_enable(phy_ref_clk); - - /* disable the power to the usb hub prior to init and reset phy+hub */ - ret = gpio_request_array(panda_ehci_gpios, - ARRAY_SIZE(panda_ehci_gpios)); - if (ret) { - pr_err("Unable to initialize EHCI power/reset\n"); - return; - } - - gpio_export(GPIO_HUB_POWER, 0); - gpio_export(GPIO_HUB_NRESET, 0); - gpio_set_value(GPIO_HUB_NRESET, 1); + ret = clk_add_alias("main_clk", "nop_usb_xceiv.1", "auxclk3_ck", NULL); + if (ret) + pr_err("Failed to add main_clk alias to auxclk3_ck\n"); + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); - - /* enable power to hub */ - gpio_set_value(GPIO_HUB_POWER, 1); } static struct omap_musb_board_data musb_board_data = { diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index 86bab51154ee..ab79a4422bcc 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -458,14 +458,16 @@ static int __init overo_spi_init(void) return 0; } +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 2, + .reset_gpio = OVERO_GPIO_USBH_NRESET, + .vcc_gpio = -EINVAL, + }, +}; + 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, - .phy_reset = true, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = OVERO_GPIO_USBH_NRESET, - .reset_gpio_port[2] = -EINVAL }; #ifdef CONFIG_OMAP_MUX @@ -502,6 +504,8 @@ static void __init overo_init(void) ARRAY_SIZE(overo_nand_partitions), NAND_CS, 0, NULL); usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb"); usb_musb_init(NULL); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); overo_spi_init(); overo_init_smsc911x(); diff --git a/arch/arm/mach-omap2/board-zoom.c b/arch/arm/mach-omap2/board-zoom.c index 5e4d4c9fe61a..1a3dd865d8eb 100644 --- a/arch/arm/mach-omap2/board-zoom.c +++ b/arch/arm/mach-omap2/board-zoom.c @@ -92,14 +92,16 @@ static struct mtd_partition zoom_nand_partitions[] = { }, }; +static struct usbhs_phy_data phy_data[] __initdata = { + { + .port = 2, + .reset_gpio = ZOOM3_EHCI_RESET_GPIO, + .vcc_gpio = -EINVAL, + }, +}; + 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, - .phy_reset = true, - .reset_gpio_port[0] = -EINVAL, - .reset_gpio_port[1] = ZOOM3_EHCI_RESET_GPIO, - .reset_gpio_port[2] = -EINVAL, }; static void __init omap_zoom_init(void) @@ -109,6 +111,8 @@ static void __init omap_zoom_init(void) } else if (machine_is_omap_zoom3()) { omap3_mux_init(board_mux, OMAP_PACKAGE_CBP); omap_mux_init_gpio(ZOOM3_EHCI_RESET_GPIO, OMAP_PIN_OUTPUT); + + usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data)); usbhs_init(&usbhs_bdata); } diff --git a/arch/arm/mach-omap2/cclock33xx_data.c b/arch/arm/mach-omap2/cclock33xx_data.c index 476b82066cb6..7f091c85384e 100644 --- a/arch/arm/mach-omap2/cclock33xx_data.c +++ b/arch/arm/mach-omap2/cclock33xx_data.c @@ -958,6 +958,14 @@ int __init am33xx_clk_init(void) clk_set_parent(&timer3_fck, &sys_clkin_ck); clk_set_parent(&timer6_fck, &sys_clkin_ck); + /* + * The On-Chip 32K RC Osc clock is not an accurate clock-source as per + * the design/spec, so as a result, for example, timer which supposed + * to get expired @60Sec, but will expire somewhere ~@40Sec, which is + * not expected by any use-case, so change WDT1 clock source to PRCM + * 32KHz clock. + */ + clk_set_parent(&wdt1_fck, &clkdiv32k_ick); return 0; } diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index e4ec3a69ee2e..2191f25ad21b 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -596,7 +596,7 @@ int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name) return -ENOENT; r = clk_set_rate(mpurate_ck, mpurate); - if (IS_ERR_VALUE(r)) { + if (r < 0) { WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n", mpurate_ck_name, mpurate, r); clk_put(mpurate_ck); diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 40f4a03d728f..bf70e2b57ff8 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -82,8 +82,7 @@ extern void omap2_init_common_infrastructure(void); extern void omap2_sync32k_timer_init(void); extern void omap3_sync32k_timer_init(void); extern void omap3_secure_sync32k_timer_init(void); -extern void omap3_gp_gptimer_timer_init(void); -extern void omap3_am33xx_gptimer_timer_init(void); +extern void omap3_gptimer_timer_init(void); extern void omap4_local_timer_init(void); extern void omap5_realtime_timer_init(void); diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index 3aed4b0b9563..3a0296cfcace 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -307,10 +307,10 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) _omap3_noncore_dpll_bypass(clk); /* - * Set jitter correction. No jitter correction for OMAP4 and 3630 - * since freqsel field is no longer present + * Set jitter correction. Jitter correction applicable for OMAP343X + * only since freqsel field is no longer present on other devices. */ - if (!soc_is_am33xx() && !cpu_is_omap44xx() && !cpu_is_omap3630()) { + if (cpu_is_omap343x()) { v = __raw_readl(dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); @@ -480,29 +480,30 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, if (!dd) return -EINVAL; - __clk_prepare(dd->clk_bypass); - clk_enable(dd->clk_bypass); - __clk_prepare(dd->clk_ref); - clk_enable(dd->clk_ref); - if (__clk_get_rate(dd->clk_bypass) == rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { pr_debug("%s: %s: set rate: entering bypass.\n", __func__, __clk_get_name(hw->clk)); + __clk_prepare(dd->clk_bypass); + clk_enable(dd->clk_bypass); ret = _omap3_noncore_dpll_bypass(clk); if (!ret) new_parent = dd->clk_bypass; + clk_disable(dd->clk_bypass); + __clk_unprepare(dd->clk_bypass); } else { + __clk_prepare(dd->clk_ref); + clk_enable(dd->clk_ref); + if (dd->last_rounded_rate != rate) rate = __clk_round_rate(hw->clk, rate); if (dd->last_rounded_rate == 0) return -EINVAL; - /* No freqsel on AM335x, OMAP4 and OMAP3630 */ - if (!soc_is_am33xx() && !cpu_is_omap44xx() && - !cpu_is_omap3630()) { + /* Freqsel is available only on OMAP343X devices */ + if (cpu_is_omap343x()) { freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); WARN_ON(!freqsel); @@ -514,6 +515,8 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, ret = omap3_noncore_dpll_program(clk, freqsel); if (!ret) new_parent = dd->clk_ref; + clk_disable(dd->clk_ref); + __clk_unprepare(dd->clk_ref); } /* * FIXME - this is all wrong. common code handles reparenting and @@ -525,11 +528,6 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, if (!ret) __clk_reparent(hw->clk, new_parent); - clk_disable(dd->clk_ref); - __clk_unprepare(dd->clk_ref); - clk_disable(dd->clk_bypass); - __clk_unprepare(dd->clk_bypass); - return 0; } diff --git a/arch/arm/mach-omap2/dsp.c b/arch/arm/mach-omap2/dsp.c index b155500e84a8..b8208b4b1bd9 100644 --- a/arch/arm/mach-omap2/dsp.c +++ b/arch/arm/mach-omap2/dsp.c @@ -26,7 +26,7 @@ #include "control.h" #include "cm2xxx_3xxx.h" #include "prm2xxx_3xxx.h" -#ifdef CONFIG_BRIDGE_DVFS +#ifdef CONFIG_TIDSPBRIDGE_DVFS #include "omap-pm.h" #endif @@ -35,7 +35,7 @@ static struct platform_device *omap_dsp_pdev; static struct omap_dsp_platform_data omap_dsp_pdata __initdata = { -#ifdef CONFIG_BRIDGE_DVFS +#ifdef CONFIG_TIDSPBRIDGE_DVFS .dsp_set_min_opp = omap_pm_dsp_set_min_opp, .dsp_get_opp = omap_pm_dsp_get_opp, .cpu_set_freq = omap_pm_cpu_set_freq, diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index afc1e8c32d6c..d9c27195caf0 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -74,14 +74,6 @@ static int omap2_nand_gpmc_retime( t.cs_wr_off = gpmc_t->cs_wr_off; t.wr_cycle = gpmc_t->wr_cycle; - /* Configure GPMC */ - if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 1); - else - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0); - gpmc_cs_configure(gpmc_nand_data->cs, - GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND); - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0); err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); if (err) return err; @@ -115,14 +107,18 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, struct gpmc_timings *gpmc_t) { int err = 0; + struct gpmc_settings s; struct device *dev = &gpmc_nand_device.dev; + memset(&s, 0, sizeof(struct gpmc_settings)); + gpmc_nand_device.dev.platform_data = gpmc_nand_data; err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, (unsigned long *)&gpmc_nand_resource[0].start); if (err < 0) { - dev_err(dev, "Cannot request GPMC CS\n"); + dev_err(dev, "Cannot request GPMC CS %d, error %d\n", + gpmc_nand_data->cs, err); return err; } @@ -140,11 +136,31 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, dev_err(dev, "Unable to set gpmc timings: %d\n", err); return err; } - } - /* Enable RD PIN Monitoring Reg */ - if (gpmc_nand_data->dev_ready) { - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1); + if (gpmc_nand_data->of_node) { + gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); + } else { + s.device_nand = true; + + /* Enable RD PIN Monitoring Reg */ + if (gpmc_nand_data->dev_ready) { + s.wait_on_read = true; + s.wait_on_write = true; + } + } + + if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) + s.device_width = GPMC_DEVWIDTH_16BIT; + else + s.device_width = GPMC_DEVWIDTH_8BIT; + + err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s); + if (err < 0) + goto out_free_cs; + + err = gpmc_configure(GPMC_CONFIG_WP, 0); + if (err < 0) + goto out_free_cs; } gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs); diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index fadd87435cd0..64b5a8346982 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -47,11 +47,23 @@ static struct platform_device gpmc_onenand_device = { .resource = &gpmc_onenand_resource, }; -static struct gpmc_timings omap2_onenand_calc_async_timings(void) +static struct gpmc_settings onenand_async = { + .device_width = GPMC_DEVWIDTH_16BIT, + .mux_add_data = GPMC_MUX_AD, +}; + +static struct gpmc_settings onenand_sync = { + .burst_read = true, + .burst_wrap = true, + .burst_len = GPMC_BURST_16, + .device_width = GPMC_DEVWIDTH_16BIT, + .mux_add_data = GPMC_MUX_AD, + .wait_pin = 0, +}; + +static void omap2_onenand_calc_async_timings(struct gpmc_timings *t) { struct gpmc_device_timings dev_t; - struct gpmc_timings t; - const int t_cer = 15; const int t_avdp = 12; const int t_aavdh = 7; @@ -64,7 +76,6 @@ static struct gpmc_timings omap2_onenand_calc_async_timings(void) memset(&dev_t, 0, sizeof(dev_t)); - dev_t.mux = true; dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000; dev_t.t_avdp_w = dev_t.t_avdp_r; dev_t.t_aavdh = t_aavdh * 1000; @@ -76,19 +87,7 @@ static struct gpmc_timings omap2_onenand_calc_async_timings(void) dev_t.t_wpl = t_wpl * 1000; dev_t.t_wph = t_wph * 1000; - gpmc_calc_timings(&t, &dev_t); - - return t; -} - -static int gpmc_set_async_mode(int cs, struct gpmc_timings *t) -{ - /* Configure GPMC for asynchronous read */ - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, - GPMC_CONFIG1_DEVICESIZE_16 | - GPMC_CONFIG1_MUXADDDATA); - - return gpmc_cs_set_timings(cs, t); + gpmc_calc_timings(t, &onenand_async, &dev_t); } static void omap2_onenand_set_async_mode(void __iomem *onenand_base) @@ -158,12 +157,11 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg, return freq; } -static struct gpmc_timings -omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, - int freq) +static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t, + unsigned int flags, + int freq) { struct gpmc_device_timings dev_t; - struct gpmc_timings t; const int t_cer = 15; const int t_avdp = 12; const int t_cez = 20; /* max of t_cez, t_oez */ @@ -172,9 +170,9 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo; int div, gpmc_clk_ns; - if (cfg->flags & ONENAND_SYNC_READ) + if (flags & ONENAND_SYNC_READ) onenand_flags = ONENAND_FLAG_SYNCREAD; - else if (cfg->flags & ONENAND_SYNC_READWRITE) + else if (flags & ONENAND_SYNC_READWRITE) onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE; switch (freq) { @@ -239,10 +237,11 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, /* Set synchronous read timings */ memset(&dev_t, 0, sizeof(dev_t)); - dev_t.mux = true; - dev_t.sync_read = true; + if (onenand_flags & ONENAND_FLAG_SYNCREAD) + onenand_sync.sync_read = true; if (onenand_flags & ONENAND_FLAG_SYNCWRITE) { - dev_t.sync_write = true; + onenand_sync.sync_write = true; + onenand_sync.burst_write = true; } else { dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000; dev_t.t_wpl = t_wpl * 1000; @@ -265,32 +264,7 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, dev_t.cyc_aavdh_oe = 1; dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period; - gpmc_calc_timings(&t, &dev_t); - - return t; -} - -static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t) -{ - unsigned sync_read = onenand_flags & ONENAND_FLAG_SYNCREAD; - unsigned sync_write = onenand_flags & ONENAND_FLAG_SYNCWRITE; - - /* Configure GPMC for synchronous read */ - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, - GPMC_CONFIG1_WRAPBURST_SUPP | - GPMC_CONFIG1_READMULTIPLE_SUPP | - (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) | - (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) | - (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) | - GPMC_CONFIG1_PAGE_LEN(2) | - (cpu_is_omap34xx() ? 0 : - (GPMC_CONFIG1_WAIT_READ_MON | - GPMC_CONFIG1_WAIT_PIN_SEL(0))) | - GPMC_CONFIG1_DEVICESIZE_16 | - GPMC_CONFIG1_DEVICETYPE_NOR | - GPMC_CONFIG1_MUXADDDATA); - - return gpmc_cs_set_timings(cs, t); + gpmc_calc_timings(t, &onenand_sync, &dev_t); } static int omap2_onenand_setup_async(void __iomem *onenand_base) @@ -298,12 +272,20 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base) struct gpmc_timings t; int ret; + if (gpmc_onenand_data->of_node) + gpmc_read_settings_dt(gpmc_onenand_data->of_node, + &onenand_async); + omap2_onenand_set_async_mode(onenand_base); - t = omap2_onenand_calc_async_timings(); + omap2_onenand_calc_async_timings(&t); + + ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async); + if (ret < 0) + return ret; - ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t); - if (IS_ERR_VALUE(ret)) + ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); + if (ret < 0) return ret; omap2_onenand_set_async_mode(onenand_base); @@ -322,10 +304,26 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr) set_onenand_cfg(onenand_base); } - t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq); + if (gpmc_onenand_data->of_node) { + gpmc_read_settings_dt(gpmc_onenand_data->of_node, + &onenand_sync); + } else { + /* + * FIXME: Appears to be legacy code from initial ONENAND commit. + * Unclear what boards this is for and if this can be removed. + */ + if (!cpu_is_omap34xx()) + onenand_sync.wait_on_read = true; + } + + omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq); - ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t); - if (IS_ERR_VALUE(ret)) + ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_sync); + if (ret < 0) + return ret; + + ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); + if (ret < 0) return ret; set_onenand_cfg(onenand_base); @@ -359,6 +357,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) { int err; + struct device *dev = &gpmc_onenand_device.dev; gpmc_onenand_data = _onenand_data; gpmc_onenand_data->onenand_setup = gpmc_onenand_setup; @@ -366,7 +365,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) if (cpu_is_omap24xx() && (gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) { - printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n"); + dev_warn(dev, "OneNAND using only SYNC_READ on 24xx\n"); gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE; gpmc_onenand_data->flags |= ONENAND_SYNC_READ; } @@ -379,7 +378,8 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE, (unsigned long *)&gpmc_onenand_resource.start); if (err < 0) { - pr_err("%s: Cannot request GPMC CS\n", __func__); + dev_err(dev, "Cannot request GPMC CS %d, error %d\n", + gpmc_onenand_data->cs, err); return; } @@ -387,7 +387,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) ONENAND_IO_SIZE - 1; if (platform_device_register(&gpmc_onenand_device) < 0) { - pr_err("%s: Unable to register OneNAND device\n", __func__); + dev_err(dev, "Unable to register OneNAND device\n"); gpmc_cs_free(gpmc_onenand_data->cs); return; } diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c index 11d0b756f098..61a063595e66 100644 --- a/arch/arm/mach-omap2/gpmc-smc91x.c +++ b/arch/arm/mach-omap2/gpmc-smc91x.c @@ -49,6 +49,10 @@ static struct platform_device gpmc_smc91x_device = { .resource = gpmc_smc91x_resources, }; +static struct gpmc_settings smc91x_settings = { + .device_width = GPMC_DEVWIDTH_16BIT, +}; + /* * Set the gpmc timings for smc91c96. The timings are taken * from the data sheet available at: @@ -67,18 +71,6 @@ static int smc91c96_gpmc_retime(void) const int t7 = 5; /* Figure 12.4 write */ const int t8 = 5; /* Figure 12.4 write */ const int t20 = 185; /* Figure 12.2 read and 12.4 write */ - u32 l; - - l = GPMC_CONFIG1_DEVICESIZE_16; - if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA) - l |= GPMC_CONFIG1_MUXADDDATA; - if (gpmc_cfg->flags & GPMC_READ_MON) - l |= GPMC_CONFIG1_WAIT_READ_MON; - if (gpmc_cfg->flags & GPMC_WRITE_MON) - l |= GPMC_CONFIG1_WAIT_WRITE_MON; - if (gpmc_cfg->wait_pin) - l |= GPMC_CONFIG1_WAIT_PIN_SEL(gpmc_cfg->wait_pin); - gpmc_cs_write_reg(gpmc_cfg->cs, GPMC_CS_CONFIG1, l); /* * FIXME: Calculate the address and data bus muxed timings. @@ -104,7 +96,7 @@ static int smc91c96_gpmc_retime(void) dev_t.t_cez_w = t4_w * 1000; dev_t.t_wr_cycle = (t20 - t3) * 1000; - gpmc_calc_timings(&t, &dev_t); + gpmc_calc_timings(&t, &smc91x_settings, &dev_t); return gpmc_cs_set_timings(gpmc_cfg->cs, &t); } @@ -133,6 +125,18 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data) gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f; gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK); + if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA) + smc91x_settings.mux_add_data = GPMC_MUX_AD; + if (gpmc_cfg->flags & GPMC_READ_MON) + smc91x_settings.wait_on_read = true; + if (gpmc_cfg->flags & GPMC_WRITE_MON) + smc91x_settings.wait_on_write = true; + if (gpmc_cfg->wait_pin) + smc91x_settings.wait_pin = gpmc_cfg->wait_pin; + ret = gpmc_cs_program_settings(gpmc_cfg->cs, &smc91x_settings); + if (ret < 0) + goto free1; + if (gpmc_cfg->retime) { ret = gpmc_cfg->retime(); if (ret != 0) diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 410e1bac7815..ed946df5ad8a 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_mtd.h> #include <linux/of_device.h> #include <linux/mtd/nand.h> @@ -91,9 +92,7 @@ #define GPMC_CS_SIZE 0x30 #define GPMC_BCH_SIZE 0x10 -#define GPMC_MEM_START 0x00000000 #define GPMC_MEM_END 0x3FFFFFFF -#define BOOT_ROM_SPACE 0x100000 /* 1MB */ #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ #define GPMC_SECTION_SHIFT 28 /* 128 MB */ @@ -107,6 +106,9 @@ #define GPMC_HAS_WR_ACCESS 0x1 #define GPMC_HAS_WR_DATA_MUX_BUS 0x2 +#define GPMC_HAS_MUX_AAD 0x4 + +#define GPMC_NR_WAITPINS 4 /* XXX: Only NAND irq has been considered,currently these are the only ones used */ @@ -153,6 +155,7 @@ static struct resource gpmc_cs_mem[GPMC_CS_NUM]; static DEFINE_SPINLOCK(gpmc_mem_lock); /* Define chip-selects as reserved by default until probe completes */ static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1); +static unsigned int gpmc_nr_waitpins; static struct device *gpmc_dev; static int gpmc_irq; static resource_size_t phys_base, mem_size; @@ -181,7 +184,7 @@ void gpmc_cs_write_reg(int cs, int idx, u32 val) __raw_writel(val, reg_addr); } -u32 gpmc_cs_read_reg(int cs, int idx) +static u32 gpmc_cs_read_reg(int cs, int idx) { void __iomem *reg_addr; @@ -190,7 +193,7 @@ u32 gpmc_cs_read_reg(int cs, int idx) } /* TODO: Add support for gpmc_fck to clock framework and use it */ -unsigned long gpmc_get_fclk_period(void) +static unsigned long gpmc_get_fclk_period(void) { unsigned long rate = clk_get_rate(gpmc_l3_clk); @@ -205,7 +208,7 @@ unsigned long gpmc_get_fclk_period(void) return rate; } -unsigned int gpmc_ns_to_ticks(unsigned int time_ns) +static unsigned int gpmc_ns_to_ticks(unsigned int time_ns) { unsigned long tick_ps; @@ -215,7 +218,7 @@ unsigned int gpmc_ns_to_ticks(unsigned int time_ns) return (time_ns * 1000 + tick_ps - 1) / tick_ps; } -unsigned int gpmc_ps_to_ticks(unsigned int time_ps) +static unsigned int gpmc_ps_to_ticks(unsigned int time_ps) { unsigned long tick_ps; @@ -230,13 +233,6 @@ unsigned int gpmc_ticks_to_ns(unsigned int ticks) return ticks * gpmc_get_fclk_period() / 1000; } -unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) -{ - unsigned long ticks = gpmc_ns_to_ticks(time_ns); - - return ticks * gpmc_get_fclk_period() / 1000; -} - static unsigned int gpmc_ticks_to_ps(unsigned int ticks) { return ticks * gpmc_get_fclk_period(); @@ -405,11 +401,18 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) return 0; } -static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) +static int gpmc_cs_enable_mem(int cs, u32 base, u32 size) { u32 l; u32 mask; + /* + * Ensure that base address is aligned on a + * boundary equal to or greater than size. + */ + if (base & (size - 1)) + return -EINVAL; + mask = (1 << GPMC_SECTION_SHIFT) - size; l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); l &= ~0x3f; @@ -418,6 +421,8 @@ static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8; l |= GPMC_CONFIG7_CSVALID; gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); + + return 0; } static void gpmc_cs_disable_mem(int cs) @@ -448,22 +453,14 @@ static int gpmc_cs_mem_enabled(int cs) return l & GPMC_CONFIG7_CSVALID; } -int gpmc_cs_set_reserved(int cs, int reserved) +static void gpmc_cs_set_reserved(int cs, int reserved) { - if (cs > GPMC_CS_NUM) - return -ENODEV; - gpmc_cs_map &= ~(1 << cs); gpmc_cs_map |= (reserved ? 1 : 0) << cs; - - return 0; } -int gpmc_cs_reserved(int cs) +static bool gpmc_cs_reserved(int cs) { - if (cs > GPMC_CS_NUM) - return -ENODEV; - return gpmc_cs_map & (1 << cs); } @@ -510,6 +507,39 @@ static int gpmc_cs_delete_mem(int cs) return r; } +/** + * gpmc_cs_remap - remaps a chip-select physical base address + * @cs: chip-select to remap + * @base: physical base address to re-map chip-select to + * + * Re-maps a chip-select to a new physical base address specified by + * "base". Returns 0 on success and appropriate negative error code + * on failure. + */ +static int gpmc_cs_remap(int cs, u32 base) +{ + int ret; + u32 old_base, size; + + if (cs > GPMC_CS_NUM) + return -ENODEV; + gpmc_cs_get_memconf(cs, &old_base, &size); + if (base == old_base) + return 0; + gpmc_cs_disable_mem(cs); + ret = gpmc_cs_delete_mem(cs); + if (ret < 0) + return ret; + ret = gpmc_cs_insert_mem(cs, base, size); + if (ret < 0) + return ret; + ret = gpmc_cs_enable_mem(cs, base, size); + if (ret < 0) + return ret; + + return 0; +} + int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) { struct resource *res = &gpmc_cs_mem[cs]; @@ -535,7 +565,12 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) if (r < 0) goto out; - gpmc_cs_enable_mem(cs, res->start, resource_size(res)); + r = gpmc_cs_enable_mem(cs, res->start, resource_size(res)); + if (r < 0) { + release_resource(res); + goto out; + } + *base = res->start; gpmc_cs_set_reserved(cs, 1); out: @@ -561,16 +596,14 @@ void gpmc_cs_free(int cs) EXPORT_SYMBOL(gpmc_cs_free); /** - * gpmc_cs_configure - write request to configure gpmc - * @cs: chip select number + * gpmc_configure - write request to configure gpmc * @cmd: command type * @wval: value to write * @return status of the operation */ -int gpmc_cs_configure(int cs, int cmd, int wval) +int gpmc_configure(int cmd, int wval) { - int err = 0; - u32 regval = 0; + u32 regval; switch (cmd) { case GPMC_ENABLE_IRQ: @@ -590,43 +623,14 @@ int gpmc_cs_configure(int cs, int cmd, int wval) gpmc_write_reg(GPMC_CONFIG, regval); break; - case GPMC_CONFIG_RDY_BSY: - regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); - if (wval) - regval |= WR_RD_PIN_MONITORING; - else - regval &= ~WR_RD_PIN_MONITORING; - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval); - break; - - case GPMC_CONFIG_DEV_SIZE: - regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); - - /* clear 2 target bits */ - regval &= ~GPMC_CONFIG1_DEVICESIZE(3); - - /* set the proper value */ - regval |= GPMC_CONFIG1_DEVICESIZE(wval); - - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval); - break; - - case GPMC_CONFIG_DEV_TYPE: - regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); - regval |= GPMC_CONFIG1_DEVICETYPE(wval); - if (wval == GPMC_DEVICETYPE_NOR) - regval |= GPMC_CONFIG1_MUXADDDATA; - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval); - break; - default: - printk(KERN_ERR "gpmc_configure_cs: Not supported\n"); - err = -EINVAL; + pr_err("%s: command not supported\n", __func__); + return -EINVAL; } - return err; + return 0; } -EXPORT_SYMBOL(gpmc_cs_configure); +EXPORT_SYMBOL(gpmc_configure); void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs) { @@ -716,7 +720,7 @@ static int gpmc_setup_irq(void) return -EINVAL; gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0); - if (IS_ERR_VALUE(gpmc_irq_start)) { + if (gpmc_irq_start < 0) { pr_err("irq_alloc_descs failed\n"); return gpmc_irq_start; } @@ -781,16 +785,16 @@ static void gpmc_mem_exit(void) } -static int gpmc_mem_init(void) +static void gpmc_mem_init(void) { - int cs, rc; - unsigned long boot_rom_space = 0; + int cs; - /* never allocate the first page, to facilitate bug detection; - * even if we didn't boot from ROM. + /* + * The first 1MB of GPMC address space is typically mapped to + * the internal ROM. Never allocate the first page, to + * facilitate bug detection; even if we didn't boot from ROM. */ - boot_rom_space = BOOT_ROM_SPACE; - gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space; + gpmc_mem_root.start = SZ_1M; gpmc_mem_root.end = GPMC_MEM_END; /* Reserve all regions that has been set up by bootloader */ @@ -800,16 +804,12 @@ static int gpmc_mem_init(void) if (!gpmc_cs_mem_enabled(cs)) continue; gpmc_cs_get_memconf(cs, &base, &size); - rc = gpmc_cs_insert_mem(cs, base, size); - if (IS_ERR_VALUE(rc)) { - while (--cs >= 0) - if (gpmc_cs_mem_enabled(cs)) - gpmc_cs_delete_mem(cs); - return rc; + if (gpmc_cs_insert_mem(cs, base, size)) { + pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n", + __func__, cs, base, base + size); + gpmc_cs_disable_mem(cs); } } - - return 0; } static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk) @@ -825,9 +825,9 @@ static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk) /* XXX: can the cycles be avoided ? */ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool mux) { - bool mux = dev_t->mux; u32 temp; /* adv_rd_off */ @@ -880,9 +880,9 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t, } static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool mux) { - bool mux = dev_t->mux; u32 temp; /* adv_wr_off */ @@ -942,9 +942,9 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t, } static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool mux) { - bool mux = dev_t->mux; u32 temp; /* adv_rd_off */ @@ -982,9 +982,9 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t, } static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool mux) { - bool mux = dev_t->mux; u32 temp; /* adv_wr_off */ @@ -1054,7 +1054,8 @@ static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t, } static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool sync) { u32 temp; @@ -1068,7 +1069,7 @@ static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t, gpmc_t->cs_on + dev_t->t_ce_avd); gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp); - if (dev_t->sync_write || dev_t->sync_read) + if (sync) gpmc_calc_sync_common_timings(gpmc_t, dev_t); return 0; @@ -1103,21 +1104,29 @@ static void gpmc_convert_ps_to_ns(struct gpmc_timings *t) } int gpmc_calc_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_settings *gpmc_s, + struct gpmc_device_timings *dev_t) { + bool mux = false, sync = false; + + if (gpmc_s) { + mux = gpmc_s->mux_add_data ? true : false; + sync = (gpmc_s->sync_read || gpmc_s->sync_write); + } + memset(gpmc_t, 0, sizeof(*gpmc_t)); - gpmc_calc_common_timings(gpmc_t, dev_t); + gpmc_calc_common_timings(gpmc_t, dev_t, sync); - if (dev_t->sync_read) - gpmc_calc_sync_read_timings(gpmc_t, dev_t); + if (gpmc_s && gpmc_s->sync_read) + gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux); else - gpmc_calc_async_read_timings(gpmc_t, dev_t); + gpmc_calc_async_read_timings(gpmc_t, dev_t, mux); - if (dev_t->sync_write) - gpmc_calc_sync_write_timings(gpmc_t, dev_t); + if (gpmc_s && gpmc_s->sync_write) + gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux); else - gpmc_calc_async_write_timings(gpmc_t, dev_t); + gpmc_calc_async_write_timings(gpmc_t, dev_t, mux); /* TODO: remove, see function definition */ gpmc_convert_ps_to_ns(gpmc_t); @@ -1125,6 +1134,90 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t, return 0; } +/** + * gpmc_cs_program_settings - programs non-timing related settings + * @cs: GPMC chip-select to program + * @p: pointer to GPMC settings structure + * + * Programs non-timing related settings for a GPMC chip-select, such as + * bus-width, burst configuration, etc. Function should be called once + * for each chip-select that is being used and must be called before + * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1 + * register will be initialised to zero by this function. Returns 0 on + * success and appropriate negative error code on failure. + */ +int gpmc_cs_program_settings(int cs, struct gpmc_settings *p) +{ + u32 config1; + + if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) { + pr_err("%s: invalid width %d!", __func__, p->device_width); + return -EINVAL; + } + + /* Address-data multiplexing not supported for NAND devices */ + if (p->device_nand && p->mux_add_data) { + pr_err("%s: invalid configuration!\n", __func__); + return -EINVAL; + } + + if ((p->mux_add_data > GPMC_MUX_AD) || + ((p->mux_add_data == GPMC_MUX_AAD) && + !(gpmc_capability & GPMC_HAS_MUX_AAD))) { + pr_err("%s: invalid multiplex configuration!\n", __func__); + return -EINVAL; + } + + /* Page/burst mode supports lengths of 4, 8 and 16 bytes */ + if (p->burst_read || p->burst_write) { + switch (p->burst_len) { + case GPMC_BURST_4: + case GPMC_BURST_8: + case GPMC_BURST_16: + break; + default: + pr_err("%s: invalid page/burst-length (%d)\n", + __func__, p->burst_len); + return -EINVAL; + } + } + + if ((p->wait_on_read || p->wait_on_write) && + (p->wait_pin > gpmc_nr_waitpins)) { + pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin); + return -EINVAL; + } + + config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1)); + + if (p->sync_read) + config1 |= GPMC_CONFIG1_READTYPE_SYNC; + if (p->sync_write) + config1 |= GPMC_CONFIG1_WRITETYPE_SYNC; + if (p->wait_on_read) + config1 |= GPMC_CONFIG1_WAIT_READ_MON; + if (p->wait_on_write) + config1 |= GPMC_CONFIG1_WAIT_WRITE_MON; + if (p->wait_on_read || p->wait_on_write) + config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin); + if (p->device_nand) + config1 |= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND); + if (p->mux_add_data) + config1 |= GPMC_CONFIG1_MUXTYPE(p->mux_add_data); + if (p->burst_read) + config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP; + if (p->burst_write) + config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP; + if (p->burst_read || p->burst_write) { + config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3); + config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0; + } + + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1); + + return 0; +} + #ifdef CONFIG_OF static struct of_device_id gpmc_dt_ids[] = { { .compatible = "ti,omap2420-gpmc" }, @@ -1136,70 +1229,110 @@ static struct of_device_id gpmc_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, gpmc_dt_ids); +/** + * gpmc_read_settings_dt - read gpmc settings from device-tree + * @np: pointer to device-tree node for a gpmc child device + * @p: pointer to gpmc settings structure + * + * Reads the GPMC settings for a GPMC child device from device-tree and + * stores them in the GPMC settings structure passed. The GPMC settings + * structure is initialised to zero by this function and so any + * previously stored settings will be cleared. + */ +void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p) +{ + memset(p, 0, sizeof(struct gpmc_settings)); + + p->sync_read = of_property_read_bool(np, "gpmc,sync-read"); + p->sync_write = of_property_read_bool(np, "gpmc,sync-write"); + p->device_nand = of_property_read_bool(np, "gpmc,device-nand"); + of_property_read_u32(np, "gpmc,device-width", &p->device_width); + of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data); + + if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) { + p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap"); + p->burst_read = of_property_read_bool(np, "gpmc,burst-read"); + p->burst_write = of_property_read_bool(np, "gpmc,burst-write"); + if (!p->burst_read && !p->burst_write) + pr_warn("%s: page/burst-length set but not used!\n", + __func__); + } + + if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) { + p->wait_on_read = of_property_read_bool(np, + "gpmc,wait-on-read"); + p->wait_on_write = of_property_read_bool(np, + "gpmc,wait-on-write"); + if (!p->wait_on_read && !p->wait_on_write) + pr_warn("%s: read/write wait monitoring not enabled!\n", + __func__); + } +} + static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, struct gpmc_timings *gpmc_t) { - u32 val; + struct gpmc_bool_timings *p; + + if (!np || !gpmc_t) + return; memset(gpmc_t, 0, sizeof(*gpmc_t)); /* minimum clock period for syncronous mode */ - if (!of_property_read_u32(np, "gpmc,sync-clk", &val)) - gpmc_t->sync_clk = val; + of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk); /* chip select timtings */ - if (!of_property_read_u32(np, "gpmc,cs-on", &val)) - gpmc_t->cs_on = val; - - if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val)) - gpmc_t->cs_rd_off = val; - - if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val)) - gpmc_t->cs_wr_off = val; + of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on); + of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off); + of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off); /* ADV signal timings */ - if (!of_property_read_u32(np, "gpmc,adv-on", &val)) - gpmc_t->adv_on = val; - - if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val)) - gpmc_t->adv_rd_off = val; - - if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val)) - gpmc_t->adv_wr_off = val; + of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on); + of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off); + of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off); /* WE signal timings */ - if (!of_property_read_u32(np, "gpmc,we-on", &val)) - gpmc_t->we_on = val; - - if (!of_property_read_u32(np, "gpmc,we-off", &val)) - gpmc_t->we_off = val; + of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on); + of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off); /* OE signal timings */ - if (!of_property_read_u32(np, "gpmc,oe-on", &val)) - gpmc_t->oe_on = val; - - if (!of_property_read_u32(np, "gpmc,oe-off", &val)) - gpmc_t->oe_off = val; + of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on); + of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off); /* access and cycle timings */ - if (!of_property_read_u32(np, "gpmc,page-burst-access", &val)) - gpmc_t->page_burst_access = val; - - if (!of_property_read_u32(np, "gpmc,access", &val)) - gpmc_t->access = val; - - if (!of_property_read_u32(np, "gpmc,rd-cycle", &val)) - gpmc_t->rd_cycle = val; - - if (!of_property_read_u32(np, "gpmc,wr-cycle", &val)) - gpmc_t->wr_cycle = val; - - /* only for OMAP3430 */ - if (!of_property_read_u32(np, "gpmc,wr-access", &val)) - gpmc_t->wr_access = val; - - if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val)) - gpmc_t->wr_data_mux_bus = val; + of_property_read_u32(np, "gpmc,page-burst-access-ns", + &gpmc_t->page_burst_access); + of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access); + of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle); + of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle); + of_property_read_u32(np, "gpmc,bus-turnaround-ns", + &gpmc_t->bus_turnaround); + of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns", + &gpmc_t->cycle2cycle_delay); + of_property_read_u32(np, "gpmc,wait-monitoring-ns", + &gpmc_t->wait_monitoring); + of_property_read_u32(np, "gpmc,clk-activation-ns", + &gpmc_t->clk_activation); + + /* only applicable to OMAP3+ */ + of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access); + of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns", + &gpmc_t->wr_data_mux_bus); + + /* bool timing parameters */ + p = &gpmc_t->bool_timings; + + p->cycle2cyclediffcsen = + of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen"); + p->cycle2cyclesamecsen = + of_property_read_bool(np, "gpmc,cycle2cycle-samecsen"); + p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay"); + p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay"); + p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay"); + p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay"); + p->time_para_granularity = + of_property_read_bool(np, "gpmc,time-para-granularity"); } #ifdef CONFIG_MTD_NAND @@ -1295,6 +1428,81 @@ static int gpmc_probe_onenand_child(struct platform_device *pdev, } #endif +/** + * gpmc_probe_generic_child - configures the gpmc for a child device + * @pdev: pointer to gpmc platform device + * @child: pointer to device-tree node for child device + * + * Allocates and configures a GPMC chip-select for a child device. + * Returns 0 on success and appropriate negative error code on failure. + */ +static int gpmc_probe_generic_child(struct platform_device *pdev, + struct device_node *child) +{ + struct gpmc_settings gpmc_s; + struct gpmc_timings gpmc_t; + struct resource res; + unsigned long base; + int ret, cs; + + if (of_property_read_u32(child, "reg", &cs) < 0) { + dev_err(&pdev->dev, "%s has no 'reg' property\n", + child->full_name); + return -ENODEV; + } + + if (of_address_to_resource(child, 0, &res) < 0) { + dev_err(&pdev->dev, "%s has malformed 'reg' property\n", + child->full_name); + return -ENODEV; + } + + ret = gpmc_cs_request(cs, resource_size(&res), &base); + if (ret < 0) { + dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs); + return ret; + } + + /* + * FIXME: gpmc_cs_request() will map the CS to an arbitary + * location in the gpmc address space. When booting with + * device-tree we want the NOR flash to be mapped to the + * location specified in the device-tree blob. So remap the + * CS to this location. Once DT migration is complete should + * just make gpmc_cs_request() map a specific address. + */ + ret = gpmc_cs_remap(cs, res.start); + if (ret < 0) { + dev_err(&pdev->dev, "cannot remap GPMC CS %d to 0x%x\n", + cs, res.start); + goto err; + } + + gpmc_read_settings_dt(child, &gpmc_s); + + ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width); + if (ret < 0) + goto err; + + ret = gpmc_cs_program_settings(cs, &gpmc_s); + if (ret < 0) + goto err; + + gpmc_read_timings_dt(child, &gpmc_t); + gpmc_cs_set_timings(cs, &gpmc_t); + + if (of_platform_device_create(child, NULL, &pdev->dev)) + return 0; + + dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name); + ret = -ENODEV; + +err: + gpmc_cs_free(cs); + + return ret; +} + static int gpmc_probe_dt(struct platform_device *pdev) { int ret; @@ -1305,6 +1513,13 @@ static int gpmc_probe_dt(struct platform_device *pdev) if (!of_id) return 0; + ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins", + &gpmc_nr_waitpins); + if (ret < 0) { + pr_err("%s: number of wait pins not found!\n", __func__); + return ret; + } + for_each_node_by_name(child, "nand") { ret = gpmc_probe_nand_child(pdev, child); if (ret < 0) { @@ -1320,6 +1535,23 @@ static int gpmc_probe_dt(struct platform_device *pdev) return ret; } } + + for_each_node_by_name(child, "nor") { + ret = gpmc_probe_generic_child(pdev, child); + if (ret < 0) { + of_node_put(child); + return ret; + } + } + + for_each_node_by_name(child, "ethernet") { + ret = gpmc_probe_generic_child(pdev, child); + if (ret < 0) { + of_node_put(child); + return ret; + } + } + return 0; } #else @@ -1364,25 +1596,37 @@ static int gpmc_probe(struct platform_device *pdev) gpmc_dev = &pdev->dev; l = gpmc_read_reg(GPMC_REVISION); + + /* + * FIXME: Once device-tree migration is complete the below flags + * should be populated based upon the device-tree compatible + * string. For now just use the IP revision. OMAP3+ devices have + * the wr_access and wr_data_mux_bus register fields. OMAP4+ + * devices support the addr-addr-data multiplex protocol. + * + * GPMC IP revisions: + * - OMAP24xx = 2.0 + * - OMAP3xxx = 5.0 + * - OMAP44xx/54xx/AM335x = 6.0 + */ if (GPMC_REVISION_MAJOR(l) > 0x4) gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS; + if (GPMC_REVISION_MAJOR(l) > 0x5) + gpmc_capability |= GPMC_HAS_MUX_AAD; dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l), GPMC_REVISION_MINOR(l)); - rc = gpmc_mem_init(); - if (IS_ERR_VALUE(rc)) { - clk_disable_unprepare(gpmc_l3_clk); - clk_put(gpmc_l3_clk); - dev_err(gpmc_dev, "failed to reserve memory\n"); - return rc; - } + gpmc_mem_init(); - if (IS_ERR_VALUE(gpmc_setup_irq())) + if (gpmc_setup_irq() < 0) dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); /* Now the GPMC is initialised, unreserve the chip-selects */ gpmc_cs_map = 0; + if (!pdev->dev.of_node) + gpmc_nr_waitpins = GPMC_NR_WAITPINS; + rc = gpmc_probe_dt(pdev); if (rc < 0) { clk_disable_unprepare(gpmc_l3_clk); diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h index fe0a844d5007..707f6d58edd5 100644 --- a/arch/arm/mach-omap2/gpmc.h +++ b/arch/arm/mach-omap2/gpmc.h @@ -58,7 +58,7 @@ #define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1) #define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10) #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0) -#define GPMC_CONFIG1_MUXADDDATA (1 << 9) +#define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8) #define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4) #define GPMC_CONFIG1_FCLK_DIV(val) (val & 3) #define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1)) @@ -73,6 +73,13 @@ #define GPMC_IRQ_FIFOEVENTENABLE 0x01 #define GPMC_IRQ_COUNT_EVENT 0x02 +#define GPMC_BURST_4 4 /* 4 word burst */ +#define GPMC_BURST_8 8 /* 8 word burst */ +#define GPMC_BURST_16 16 /* 16 word burst */ +#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */ +#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */ +#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */ +#define GPMC_MUX_AD 2 /* Addr-Data multiplex */ /* bool type time settings */ struct gpmc_bool_timings { @@ -178,10 +185,6 @@ struct gpmc_device_timings { u8 cyc_wpl; /* write deassertion time in cycles */ u32 cyc_iaa; /* initial access time in cycles */ - bool mux; /* address & data muxed */ - bool sync_write;/* synchronous write */ - bool sync_read; /* synchronous read */ - /* extra delays */ bool ce_xdelay; bool avd_xdelay; @@ -189,28 +192,40 @@ struct gpmc_device_timings { bool we_xdelay; }; +struct gpmc_settings { + bool burst_wrap; /* enables wrap bursting */ + bool burst_read; /* enables read page/burst mode */ + bool burst_write; /* enables write page/burst mode */ + bool device_nand; /* device is NAND */ + bool sync_read; /* enables synchronous reads */ + bool sync_write; /* enables synchronous writes */ + bool wait_on_read; /* monitor wait on reads */ + bool wait_on_write; /* monitor wait on writes */ + u32 burst_len; /* page/burst length */ + u32 device_width; /* device bus width (8 or 16 bit) */ + u32 mux_add_data; /* multiplex address & data */ + u32 wait_pin; /* wait-pin to be used */ +}; + extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t); + struct gpmc_settings *gpmc_s, + struct gpmc_device_timings *dev_t); extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs); extern int gpmc_get_client_irq(unsigned irq_config); -extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns); -extern unsigned int gpmc_ps_to_ticks(unsigned int time_ps); extern unsigned int gpmc_ticks_to_ns(unsigned int ticks); -extern unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns); -extern unsigned long gpmc_get_fclk_period(void); extern void gpmc_cs_write_reg(int cs, int idx, u32 val); -extern u32 gpmc_cs_read_reg(int cs, int idx); extern int gpmc_calc_divider(unsigned int sync_clk); extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t); +extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p); extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base); extern void gpmc_cs_free(int cs); -extern int gpmc_cs_set_reserved(int cs, int reserved); -extern int gpmc_cs_reserved(int cs); extern void omap3_gpmc_save_context(void); extern void omap3_gpmc_restore_context(void); -extern int gpmc_cs_configure(int cs, int cmd, int wval); +extern int gpmc_configure(int cmd, int wval); +extern void gpmc_read_settings_dt(struct device_node *np, + struct gpmc_settings *p); #endif diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 8a68f1ec66b9..ff0bc9e51aa7 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -529,22 +529,28 @@ void __init omap5xxx_check_revision(void) case 0xb942: switch (rev) { case 0: - default: omap_revision = OMAP5430_REV_ES1_0; + break; + case 1: + default: + omap_revision = OMAP5430_REV_ES2_0; } break; case 0xb998: switch (rev) { case 0: - default: omap_revision = OMAP5432_REV_ES1_0; + break; + case 1: + default: + omap_revision = OMAP5432_REV_ES2_0; } break; default: /* Unknown default to latest silicon rev as default*/ - omap_revision = OMAP5430_REV_ES1_0; + omap_revision = OMAP5430_REV_ES2_0; } pr_info("OMAP%04x ES%d.0\n", diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 2c3fdd65387b..2bef5a7e6af8 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -271,6 +271,14 @@ static struct map_desc omap54xx_io_desc[] __initdata = { .length = L4_PER_54XX_SIZE, .type = MT_DEVICE, }, +#ifdef CONFIG_OMAP4_ERRATA_I688 + { + .virtual = OMAP4_SRAM_VA, + .pfn = __phys_to_pfn(OMAP4_SRAM_PA), + .length = PAGE_SIZE, + .type = MT_MEMORY_SO, + }, +#endif }; #endif @@ -323,6 +331,7 @@ void __init omap4_map_io(void) void __init omap5_map_io(void) { iotable_init(omap54xx_io_desc, ARRAY_SIZE(omap54xx_io_desc)); + omap_barriers_init(); } #endif /* diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 708bb115a27f..2aeb928efdfd 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -240,15 +240,21 @@ void __iomem *omap4_get_sar_ram_base(void) */ static int __init omap4_sar_ram_init(void) { + unsigned long sar_base; + /* * To avoid code running on other OMAPs in * multi-omap builds */ - if (!cpu_is_omap44xx()) + if (cpu_is_omap44xx()) + sar_base = OMAP44XX_SAR_RAM_BASE; + else if (soc_is_omap54xx()) + sar_base = OMAP54XX_SAR_RAM_BASE; + else return -ENOMEM; /* Static mapping, never released */ - sar_ram_base = ioremap(OMAP44XX_SAR_RAM_BASE, SZ_16K); + sar_ram_base = ioremap(sar_base, SZ_16K); if (WARN_ON(!sar_ram_base)) return -ENOMEM; diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h index e170fe803b04..937417523b8e 100644 --- a/arch/arm/mach-omap2/omap4-sar-layout.h +++ b/arch/arm/mach-omap2/omap4-sar-layout.h @@ -48,13 +48,13 @@ #define SAR_BACKUP_STATUS_WAKEUPGEN 0x10 /* WakeUpGen save restore offset from OMAP54XX_SAR_RAM_BASE */ -#define OMAP5_WAKEUPGENENB_OFFSET_CPU0 (SAR_BANK3_OFFSET + 0x8d4) -#define OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU0 (SAR_BANK3_OFFSET + 0x8e8) -#define OMAP5_WAKEUPGENENB_OFFSET_CPU1 (SAR_BANK3_OFFSET + 0x8fc) -#define OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU1 (SAR_BANK3_OFFSET + 0x910) -#define OMAP5_AUXCOREBOOT0_OFFSET (SAR_BANK3_OFFSET + 0x924) -#define OMAP5_AUXCOREBOOT1_OFFSET (SAR_BANK3_OFFSET + 0x928) -#define OMAP5_AMBA_IF_MODE_OFFSET (SAR_BANK3_OFFSET + 0x92c) +#define OMAP5_WAKEUPGENENB_OFFSET_CPU0 (SAR_BANK3_OFFSET + 0x9dc) +#define OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU0 (SAR_BANK3_OFFSET + 0x9f0) +#define OMAP5_WAKEUPGENENB_OFFSET_CPU1 (SAR_BANK3_OFFSET + 0xa04) +#define OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU1 (SAR_BANK3_OFFSET + 0xa18) +#define OMAP5_AUXCOREBOOT0_OFFSET (SAR_BANK3_OFFSET + 0xa2c) +#define OMAP5_AUXCOREBOOT1_OFFSET (SAR_BANK3_OFFSET + 0x930) +#define OMAP5_AMBA_IF_MODE_OFFSET (SAR_BANK3_OFFSET + 0xa34) #define OMAP5_SAR_BACKUP_STATUS_OFFSET (SAR_BANK3_OFFSET + 0x800) #endif diff --git a/arch/arm/mach-omap2/omap54xx.h b/arch/arm/mach-omap2/omap54xx.h index a2582bb3cab3..a086ba15868b 100644 --- a/arch/arm/mach-omap2/omap54xx.h +++ b/arch/arm/mach-omap2/omap54xx.h @@ -28,5 +28,6 @@ #define OMAP54XX_PRCM_MPU_BASE 0x48243000 #define OMAP54XX_SCM_BASE 0x4a002000 #define OMAP54XX_CTRL_BASE 0x4a002800 +#define OMAP54XX_SAR_RAM_BASE 0x4ae26000 #endif /* __ASM_SOC_OMAP555554XX_H */ diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index 381be7ac0c17..eeea4fa28fbc 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -131,7 +131,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev) int oh_cnt, i, ret = 0; oh_cnt = of_property_count_strings(node, "ti,hwmods"); - if (!oh_cnt || IS_ERR_VALUE(oh_cnt)) { + if (oh_cnt <= 0) { dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n"); return -ENODEV; } @@ -815,20 +815,17 @@ struct device *omap_device_get_by_hwmod_name(const char *oh_name) } oh = omap_hwmod_lookup(oh_name); - if (IS_ERR_OR_NULL(oh)) { + if (!oh) { WARN(1, "%s: no hwmod for %s\n", __func__, oh_name); - return ERR_PTR(oh ? PTR_ERR(oh) : -ENODEV); + return ERR_PTR(-ENODEV); } - if (IS_ERR_OR_NULL(oh->od)) { + if (!oh->od) { WARN(1, "%s: no omap_device for %s\n", __func__, oh_name); - return ERR_PTR(oh->od ? PTR_ERR(oh->od) : -ENODEV); + return ERR_PTR(-ENODEV); } - if (IS_ERR_OR_NULL(oh->od->pdev)) - return ERR_PTR(oh->od->pdev ? PTR_ERR(oh->od->pdev) : -ENODEV); - return &oh->od->pdev->dev; } diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index c2c798c08c2b..2520d46c8508 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -610,8 +610,6 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) /* XXX test pwrdm_get_wken for this hwmod's subsystem */ - oh->_int_flags |= _HWMOD_WAKEUP_ENABLED; - return 0; } @@ -645,8 +643,6 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) /* XXX test pwrdm_get_wken for this hwmod's subsystem */ - oh->_int_flags &= ~_HWMOD_WAKEUP_ENABLED; - return 0; } @@ -1663,7 +1659,7 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) return -ENOSYS; ret = _lookup_hardreset(oh, name, &ohri); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; if (oh->clkdm) { @@ -2413,7 +2409,7 @@ static int __init _init(struct omap_hwmod *oh, void *data) _init_mpu_rt_base(oh, NULL); r = _init_clocks(oh, NULL); - if (IS_ERR_VALUE(r)) { + if (r < 0) { WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name); return -EINVAL; } diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index d43d9b608eda..28f4dea0512e 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -477,15 +477,13 @@ struct omap_hwmod_omap4_prcm { * These are for internal use only and are managed by the omap_hwmod code. * * _HWMOD_NO_MPU_PORT: no path exists for the MPU to write to this module - * _HWMOD_WAKEUP_ENABLED: set when the omap_hwmod code has enabled ENAWAKEUP * _HWMOD_SYSCONFIG_LOADED: set when the OCP_SYSCONFIG value has been cached * _HWMOD_SKIP_ENABLE: set if hwmod enabled during init (HWMOD_INIT_NO_IDLE) - * causes the first call to _enable() to only update the pinmux */ #define _HWMOD_NO_MPU_PORT (1 << 0) -#define _HWMOD_WAKEUP_ENABLED (1 << 1) -#define _HWMOD_SYSCONFIG_LOADED (1 << 2) -#define _HWMOD_SKIP_ENABLE (1 << 3) +#define _HWMOD_SYSCONFIG_LOADED (1 << 1) +#define _HWMOD_SKIP_ENABLE (1 << 2) /* * omap_hwmod._state definitions diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c index 26eee4a556ad..31bea1ce3de1 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c @@ -28,6 +28,7 @@ #include "prm-regbits-33xx.h" #include "i2c.h" #include "mmc.h" +#include "wd_timer.h" /* * IP blocks @@ -2087,8 +2088,21 @@ static struct omap_hwmod am33xx_uart6_hwmod = { }; /* 'wd_timer' class */ +static struct omap_hwmod_class_sysconfig wdt_sysc = { + .rev_offs = 0x0, + .sysc_offs = 0x10, + .syss_offs = 0x14, + .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_SIDLEMODE | + SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + SIDLE_SMART_WKUP), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + static struct omap_hwmod_class am33xx_wd_timer_hwmod_class = { .name = "wd_timer", + .sysc = &wdt_sysc, + .pre_shutdown = &omap2_wd_timer_disable, }; /* @@ -2099,6 +2113,7 @@ static struct omap_hwmod am33xx_wd_timer1_hwmod = { .name = "wd_timer2", .class = &am33xx_wd_timer_hwmod_class, .clkdm_name = "l4_wkup_clkdm", + .flags = HWMOD_SWSUP_SIDLE, .main_clk = "wdt1_fck", .prcm = { .omap4 = { diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 1edd000a8143..0b339861d751 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -217,7 +217,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) return 0; d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir); - if (!(IS_ERR_OR_NULL(d))) + if (d) (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, (void *)pwrdm, &pwrdm_suspend_fops); @@ -261,8 +261,8 @@ static int __init pm_dbg_init(void) return 0; d = debugfs_create_dir("pm_debug", NULL); - if (IS_ERR_OR_NULL(d)) - return PTR_ERR(d); + if (!d) + return -EINVAL; (void) debugfs_create_file("count", S_IRUGO, d, (void *)DEBUG_FILE_COUNTERS, &debug_fops); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 8e61d80bf6b3..86babd740d41 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -52,7 +52,6 @@ enum { #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); @@ -233,10 +232,7 @@ static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm, { u8 sleep_switch; - if (curr_pwrst < 0) { - WARN_ON(1); - sleep_switch = ERROR_SWITCH; - } else if (curr_pwrst < PWRDM_POWER_ON) { + if (curr_pwrst < PWRDM_POWER_ON) { if (curr_pwrst > pwrst && pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && arch_pwrdm->pwrdm_set_lowpwrstchange) { @@ -1091,7 +1087,8 @@ int pwrdm_post_transition(struct powerdomain *pwrdm) */ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) { - u8 curr_pwrst, next_pwrst, sleep_switch; + u8 next_pwrst, sleep_switch; + int curr_pwrst; int ret = 0; bool hwsup = false; @@ -1107,16 +1104,17 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) pwrdm_lock(pwrdm); curr_pwrst = pwrdm_read_pwrst(pwrdm); + if (curr_pwrst < 0) { + ret = -EINVAL; + goto osps_out; + } + 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) @@ -1182,7 +1180,7 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm) { int i; - if (IS_ERR_OR_NULL(pwrdm)) { + if (!pwrdm) { pr_debug("powerdomain: %s: invalid powerdomain pointer\n", __func__); return 1; diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index d35f98aabf7a..415c7e0c9393 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -81,13 +81,13 @@ static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = { /* Read a register in a CM/PRM instance in the PRM module */ u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) { - return __raw_readl(OMAP44XX_PRM_REGADDR(inst, reg)); + return __raw_readl(prm_base + inst + reg); } /* Write into a register in a CM/PRM instance in the PRM module */ void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) { - __raw_writel(val, OMAP44XX_PRM_REGADDR(inst, reg)); + __raw_writel(val, prm_base + inst + reg); } /* Read-modify-write a register in a PRM module. Caller must lock */ @@ -650,7 +650,7 @@ static struct prm_ll_data omap44xx_prm_ll_data = { int __init omap44xx_prm_init(void) { - if (!cpu_is_omap44xx()) + if (!cpu_is_omap44xx() && !soc_is_omap54xx()) return 0; return prm_register(&omap44xx_prm_ll_data); diff --git a/arch/arm/mach-omap2/soc.h b/arch/arm/mach-omap2/soc.h index c62116bbc760..18fdeeb3a44a 100644 --- a/arch/arm/mach-omap2/soc.h +++ b/arch/arm/mach-omap2/soc.h @@ -413,7 +413,9 @@ IS_OMAP_TYPE(3430, 0x3430) #define OMAP54XX_CLASS 0x54000054 #define OMAP5430_REV_ES1_0 (OMAP54XX_CLASS | (0x30 << 16) | (0x10 << 8)) +#define OMAP5430_REV_ES2_0 (OMAP54XX_CLASS | (0x30 << 16) | (0x20 << 8)) #define OMAP5432_REV_ES1_0 (OMAP54XX_CLASS | (0x32 << 16) | (0x10 << 8)) +#define OMAP5432_REV_ES2_0 (OMAP54XX_CLASS | (0x32 << 16) | (0x20 << 8)) void omap2xxx_check_revision(void); void omap3xxx_check_revision(void); diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 2bdd4cf17a8f..f12aa6c15da4 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -57,15 +57,6 @@ #include "common.h" #include "powerdomain.h" -/* Parent clocks, eventually these will come from the clock framework */ - -#define OMAP2_MPU_SOURCE "sys_ck" -#define OMAP3_MPU_SOURCE OMAP2_MPU_SOURCE -#define OMAP4_MPU_SOURCE "sys_clkin_ck" -#define OMAP2_32K_SOURCE "func_32k_ck" -#define OMAP3_32K_SOURCE "omap_32k_fck" -#define OMAP4_32K_SOURCE "sys_32k_ck" - #define REALTIME_COUNTER_BASE 0x48243200 #define INCREMENTER_NUMERATOR_OFFSET 0x10 #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 @@ -129,7 +120,6 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, } static struct clock_event_device clockevent_gpt = { - .name = "gp_timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .rating = 300, .set_next_event = omap2_gp_timer_set_next_event, @@ -170,6 +160,12 @@ static struct device_node * __init omap_get_timer_dt(struct of_device_id *match, if (property && !of_get_property(np, property, NULL)) continue; + if (!property && (of_get_property(np, "ti,timer-alwon", NULL) || + of_get_property(np, "ti,timer-dsp", NULL) || + of_get_property(np, "ti,timer-pwm", NULL) || + of_get_property(np, "ti,timer-secure", NULL))) + continue; + of_add_property(np, &device_disabled); return np; } @@ -214,16 +210,17 @@ static u32 __init omap_dm_timer_get_errata(void) } static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, - int gptimer_id, - const char *fck_source, - const char *property, - int posted) + const char *fck_source, + const char *property, + const char **timer_name, + int posted) { char name[10]; /* 10 = sizeof("gptXX_Xck0") */ const char *oh_name; struct device_node *np; struct omap_hwmod *oh; struct resource irq, mem; + struct clk *src; int r = 0; if (of_have_populated_dt()) { @@ -243,10 +240,10 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, of_node_put(np); } else { - if (omap_dm_timer_reserve_systimer(gptimer_id)) + if (omap_dm_timer_reserve_systimer(timer->id)) return -ENODEV; - sprintf(name, "timer%d", gptimer_id); + sprintf(name, "timer%d", timer->id); oh_name = name; } @@ -254,6 +251,8 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, if (!oh) return -ENODEV; + *timer_name = oh->name; + if (!of_have_populated_dt()) { r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq); @@ -276,24 +275,24 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, /* After the dmtimer is using hwmod these clocks won't be needed */ timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); if (IS_ERR(timer->fclk)) - return -ENODEV; + return PTR_ERR(timer->fclk); - /* FIXME: Need to remove hard-coded test on timer ID */ - if (gptimer_id != 12) { - struct clk *src; - - src = clk_get(NULL, fck_source); - if (IS_ERR(src)) { - r = -EINVAL; - } else { - r = clk_set_parent(timer->fclk, src); - if (IS_ERR_VALUE(r)) - pr_warn("%s: %s cannot set source\n", - __func__, oh->name); + src = clk_get(NULL, fck_source); + if (IS_ERR(src)) + return PTR_ERR(src); + + if (clk_get_parent(timer->fclk) != src) { + r = clk_set_parent(timer->fclk, src); + if (r < 0) { + pr_warn("%s: %s cannot set source\n", __func__, + oh->name); clk_put(src); + return r; } } + clk_put(src); + omap_hwmod_setup_one(oh_name); omap_hwmod_enable(oh); __omap_dm_timer_init_regs(timer); @@ -317,6 +316,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, { int res; + clkev.id = gptimer_id; clkev.errata = omap_dm_timer_get_errata(); /* @@ -326,8 +326,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, */ __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767); - res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property, - OMAP_TIMER_POSTED); + res = omap_dm_timer_init_one(&clkev, fck_source, property, + &clockevent_gpt.name, OMAP_TIMER_POSTED); BUG_ON(res); omap2_gp_timer_irq.dev_id = &clkev; @@ -341,8 +341,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, 3, /* Timer internal resynch latency */ 0xffffffff); - pr_info("OMAP clockevent source: GPTIMER%d at %lu Hz\n", - gptimer_id, clkev.rate); + pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name, + clkev.rate); } /* Clocksource code */ @@ -359,7 +359,6 @@ static cycle_t clocksource_read_cycles(struct clocksource *cs) } static struct clocksource clocksource_gpt = { - .name = "gp_timer", .rating = 300, .read = clocksource_read_cycles, .mask = CLOCKSOURCE_MASK(32), @@ -442,13 +441,16 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void) } static void __init omap2_gptimer_clocksource_init(int gptimer_id, - const char *fck_source) + const char *fck_source, + const char *property) { int res; + clksrc.id = gptimer_id; clksrc.errata = omap_dm_timer_get_errata(); - res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL, + res = omap_dm_timer_init_one(&clksrc, fck_source, property, + &clocksource_gpt.name, OMAP_TIMER_NONPOSTED); BUG_ON(res); @@ -461,8 +463,8 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id, pr_err("Could not register clocksource %s\n", clocksource_gpt.name); else - pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n", - gptimer_id, clksrc.rate); + pr_info("OMAP clocksource: %s at %lu Hz\n", + clocksource_gpt.name, clksrc.rate); } #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER @@ -487,7 +489,7 @@ static void __init realtime_counter_init(void) pr_err("%s: ioremap failed\n", __func__); return; } - sys_clk = clk_get(NULL, "sys_clkin_ck"); + sys_clk = clk_get(NULL, "sys_clkin"); if (IS_ERR(sys_clk)) { pr_err("%s: failed to get system clock handle\n", __func__); iounmap(base); @@ -544,49 +546,52 @@ static inline void __init realtime_counter_init(void) #endif #define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ - clksrc_nr, clksrc_src) \ + clksrc_nr, clksrc_src, clksrc_prop) \ void __init omap##name##_gptimer_timer_init(void) \ { \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ - omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src); \ + omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ + clksrc_prop); \ } #define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ - clksrc_nr, clksrc_src) \ + clksrc_nr, clksrc_src, clksrc_prop) \ void __init omap##name##_sync32k_timer_init(void) \ { \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ /* Enable the use of clocksource="gp_timer" kernel parameter */ \ if (use_gptimer_clksrc) \ - omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src);\ + omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ + clksrc_prop); \ else \ omap2_sync32k_clocksource_init(); \ } #ifdef CONFIG_ARCH_OMAP2 -OMAP_SYS_32K_TIMER_INIT(2, 1, OMAP2_32K_SOURCE, "ti,timer-alwon", - 2, OMAP2_MPU_SOURCE); +OMAP_SYS_32K_TIMER_INIT(2, 1, "timer_32k_ck", "ti,timer-alwon", + 2, "timer_sys_ck", NULL); #endif /* CONFIG_ARCH_OMAP2 */ #ifdef CONFIG_ARCH_OMAP3 -OMAP_SYS_32K_TIMER_INIT(3, 1, OMAP3_32K_SOURCE, "ti,timer-alwon", - 2, OMAP3_MPU_SOURCE); -OMAP_SYS_32K_TIMER_INIT(3_secure, 12, OMAP3_32K_SOURCE, "ti,timer-secure", - 2, OMAP3_MPU_SOURCE); -OMAP_SYS_GP_TIMER_INIT(3_gp, 1, OMAP3_MPU_SOURCE, "ti,timer-alwon", - 2, OMAP3_MPU_SOURCE); +OMAP_SYS_32K_TIMER_INIT(3, 1, "timer_32k_ck", "ti,timer-alwon", + 2, "timer_sys_ck", NULL); +OMAP_SYS_32K_TIMER_INIT(3_secure, 12, "secure_32k_fck", "ti,timer-secure", + 2, "timer_sys_ck", NULL); #endif /* CONFIG_ARCH_OMAP3 */ -#ifdef CONFIG_SOC_AM33XX -OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon", - 2, OMAP4_MPU_SOURCE); -#endif /* CONFIG_SOC_AM33XX */ +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) +OMAP_SYS_GP_TIMER_INIT(3, 2, "timer_sys_ck", NULL, + 1, "timer_sys_ck", "ti,timer-alwon"); +#endif + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) +static OMAP_SYS_32K_TIMER_INIT(4, 1, "timer_32k_ck", "ti,timer-alwon", + 2, "sys_clkin_ck", NULL); +#endif #ifdef CONFIG_ARCH_OMAP4 -OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon", - 2, OMAP4_MPU_SOURCE); #ifdef CONFIG_LOCAL_TIMERS static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); void __init omap4_local_timer_init(void) @@ -597,7 +602,7 @@ void __init omap4_local_timer_init(void) int err; if (of_have_populated_dt()) { - twd_local_timer_of_register(); + clocksource_of_init(); return; } @@ -615,13 +620,11 @@ void __init omap4_local_timer_init(void) #endif /* CONFIG_ARCH_OMAP4 */ #ifdef CONFIG_SOC_OMAP5 -OMAP_SYS_32K_TIMER_INIT(5, 1, OMAP4_32K_SOURCE, "ti,timer-alwon", - 2, OMAP4_MPU_SOURCE); void __init omap5_realtime_timer_init(void) { int err; - omap5_sync32k_timer_init(); + omap4_sync32k_timer_init(); realtime_counter_init(); err = arch_timer_of_register(); diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 5706bdccf45e..aa27d7f5cbb7 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -22,8 +22,12 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/dma-mapping.h> - -#include <asm/io.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/string.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/usb/phy.h> #include "soc.h" #include "omap_device.h" @@ -526,3 +530,155 @@ void __init usbhs_init(struct usbhs_omap_platform_data *pdata) } #endif + +/* Template for PHY regulators */ +static struct fixed_voltage_config hsusb_reg_config = { + /* .supply_name filled later */ + .microvolts = 3300000, + .gpio = -1, /* updated later */ + .startup_delay = 70000, /* 70msec */ + .enable_high = 1, /* updated later */ + .enabled_at_boot = 0, /* keep in RESET */ + /* .init_data filled later */ +}; + +static const char *nop_name = "nop_usb_xceiv"; /* NOP PHY driver */ +static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */ + +/** + * usbhs_add_regulator - Add a gpio based fixed voltage regulator device + * @name: name for the regulator + * @dev_id: device id of the device this regulator supplies power to + * @dev_supply: supply name that the device expects + * @gpio: GPIO number + * @polarity: 1 - Active high, 0 - Active low + */ +static int usbhs_add_regulator(char *name, char *dev_id, char *dev_supply, + int gpio, int polarity) +{ + struct regulator_consumer_supply *supplies; + struct regulator_init_data *reg_data; + struct fixed_voltage_config *config; + struct platform_device *pdev; + int ret; + + supplies = kzalloc(sizeof(*supplies), GFP_KERNEL); + if (!supplies) + return -ENOMEM; + + supplies->supply = dev_supply; + supplies->dev_name = dev_id; + + reg_data = kzalloc(sizeof(*reg_data), GFP_KERNEL); + if (!reg_data) + return -ENOMEM; + + reg_data->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS; + reg_data->consumer_supplies = supplies; + reg_data->num_consumer_supplies = 1; + + config = kmemdup(&hsusb_reg_config, sizeof(hsusb_reg_config), + GFP_KERNEL); + if (!config) + return -ENOMEM; + + config->supply_name = name; + config->gpio = gpio; + config->enable_high = polarity; + config->init_data = reg_data; + + /* create a regulator device */ + pdev = kzalloc(sizeof(*pdev), GFP_KERNEL); + if (!pdev) + return -ENOMEM; + + pdev->id = PLATFORM_DEVID_AUTO; + pdev->name = reg_name; + pdev->dev.platform_data = config; + + ret = platform_device_register(pdev); + if (ret) + pr_err("%s: Failed registering regulator %s for %s\n", + __func__, name, dev_id); + + return ret; +} + +int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) +{ + char *rail_name; + int i, len; + struct platform_device *pdev; + char *phy_id; + + /* the phy_id will be something like "nop_usb_xceiv.1" */ + len = strlen(nop_name) + 3; /* 3 -> ".1" and NULL terminator */ + + for (i = 0; i < num_phys; i++) { + + if (!phy->port) { + pr_err("%s: Invalid port 0. Must start from 1\n", + __func__); + continue; + } + + /* do we need a NOP PHY device ? */ + if (!gpio_is_valid(phy->reset_gpio) && + !gpio_is_valid(phy->vcc_gpio)) + continue; + + /* create a NOP PHY device */ + pdev = kzalloc(sizeof(*pdev), GFP_KERNEL); + if (!pdev) + return -ENOMEM; + + pdev->id = phy->port; + pdev->name = nop_name; + pdev->dev.platform_data = phy->platform_data; + + phy_id = kmalloc(len, GFP_KERNEL); + if (!phy_id) + return -ENOMEM; + + scnprintf(phy_id, len, "nop_usb_xceiv.%d\n", + pdev->id); + + if (platform_device_register(pdev)) { + pr_err("%s: Failed to register device %s\n", + __func__, phy_id); + continue; + } + + usb_bind_phy("ehci-omap.0", phy->port - 1, phy_id); + + /* Do we need RESET regulator ? */ + if (gpio_is_valid(phy->reset_gpio)) { + + rail_name = kmalloc(13, GFP_KERNEL); + if (!rail_name) + return -ENOMEM; + + scnprintf(rail_name, 13, "hsusb%d_reset", phy->port); + + usbhs_add_regulator(rail_name, phy_id, "reset", + phy->reset_gpio, 1); + } + + /* Do we need VCC regulator ? */ + if (gpio_is_valid(phy->vcc_gpio)) { + + rail_name = kmalloc(13, GFP_KERNEL); + if (!rail_name) + return -ENOMEM; + + scnprintf(rail_name, 13, "hsusb%d_vcc", phy->port); + + usbhs_add_regulator(rail_name, phy_id, "vcc", + phy->vcc_gpio, phy->vcc_polarity); + } + + phy++; + } + + return 0; +} diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c index c5a3c6f9504e..e832bc7b8e2d 100644 --- a/arch/arm/mach-omap2/usb-tusb6010.c +++ b/arch/arm/mach-omap2/usb-tusb6010.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ +#include <linux/err.h> #include <linux/string.h> #include <linux/types.h> #include <linux/errno.h> @@ -26,6 +27,24 @@ static u8 async_cs, sync_cs; static unsigned refclk_psec; +static struct gpmc_settings tusb_async = { + .wait_on_read = true, + .wait_on_write = true, + .device_width = GPMC_DEVWIDTH_16BIT, + .mux_add_data = GPMC_MUX_AD, +}; + +static struct gpmc_settings tusb_sync = { + .burst_read = true, + .burst_write = true, + .sync_read = true, + .sync_write = true, + .wait_on_read = true, + .wait_on_write = true, + .burst_len = GPMC_BURST_16, + .device_width = GPMC_DEVWIDTH_16BIT, + .mux_add_data = GPMC_MUX_AD, +}; /* NOTE: timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */ @@ -37,8 +56,6 @@ static int tusb_set_async_mode(unsigned sysclk_ps) memset(&dev_t, 0, sizeof(dev_t)); - dev_t.mux = true; - dev_t.t_ceasu = 8 * 1000; dev_t.t_avdasu = t_acsnh_advnh - 7000; dev_t.t_ce_avd = 1000; @@ -52,7 +69,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps) dev_t.t_wpl = 300; dev_t.cyc_aavdh_we = 1; - gpmc_calc_timings(&t, &dev_t); + gpmc_calc_timings(&t, &tusb_async, &dev_t); return gpmc_cs_set_timings(async_cs, &t); } @@ -65,10 +82,6 @@ static int tusb_set_sync_mode(unsigned sysclk_ps) memset(&dev_t, 0, sizeof(dev_t)); - dev_t.mux = true; - dev_t.sync_read = true; - dev_t.sync_write = true; - dev_t.clk = 11100; dev_t.t_bacc = 1000; dev_t.t_ces = 1000; @@ -84,7 +97,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps) dev_t.cyc_wpl = 6; dev_t.t_ce_rdyz = 7000; - gpmc_calc_timings(&t, &dev_t); + gpmc_calc_timings(&t, &tusb_sync, &dev_t); return gpmc_cs_set_timings(sync_cs, &t); } @@ -165,18 +178,12 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data, return status; } tusb_resources[0].end = tusb_resources[0].start + 0x9ff; + tusb_async.wait_pin = waitpin; async_cs = async; - gpmc_cs_write_reg(async, GPMC_CS_CONFIG1, - GPMC_CONFIG1_PAGE_LEN(2) - | GPMC_CONFIG1_WAIT_READ_MON - | GPMC_CONFIG1_WAIT_WRITE_MON - | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin) - | GPMC_CONFIG1_READTYPE_ASYNC - | GPMC_CONFIG1_WRITETYPE_ASYNC - | GPMC_CONFIG1_DEVICESIZE_16 - | GPMC_CONFIG1_DEVICETYPE_NOR - | GPMC_CONFIG1_MUXADDDATA); + status = gpmc_cs_program_settings(async_cs, &tusb_async); + if (status < 0) + return status; /* SYNC region, primarily for DMA */ status = gpmc_cs_request(sync, SZ_16M, (unsigned long *) @@ -186,21 +193,12 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data, return status; } tusb_resources[1].end = tusb_resources[1].start + 0x9ff; + tusb_sync.wait_pin = waitpin; sync_cs = sync; - gpmc_cs_write_reg(sync, GPMC_CS_CONFIG1, - GPMC_CONFIG1_READMULTIPLE_SUPP - | GPMC_CONFIG1_READTYPE_SYNC - | GPMC_CONFIG1_WRITEMULTIPLE_SUPP - | GPMC_CONFIG1_WRITETYPE_SYNC - | GPMC_CONFIG1_PAGE_LEN(2) - | GPMC_CONFIG1_WAIT_READ_MON - | GPMC_CONFIG1_WAIT_WRITE_MON - | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin) - | GPMC_CONFIG1_DEVICESIZE_16 - | GPMC_CONFIG1_DEVICETYPE_NOR - | GPMC_CONFIG1_MUXADDDATA - /* fclk divider gets set later */ - ); + + status = gpmc_cs_program_settings(sync_cs, &tusb_sync); + if (status < 0) + return status; /* IRQ */ status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq"); diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h index 3319f5cf47a3..e7261ebcf7b0 100644 --- a/arch/arm/mach-omap2/usb.h +++ b/arch/arm/mach-omap2/usb.h @@ -53,8 +53,17 @@ #define USBPHY_OTGSESSEND_EN (1 << 20) #define USBPHY_DATA_POLARITY (1 << 23) +struct usbhs_phy_data { + int port; /* 1 indexed port number */ + int reset_gpio; + int vcc_gpio; + bool vcc_polarity; /* 1 active high, 0 active low */ + void *platform_data; +}; + extern void usb_musb_init(struct omap_musb_board_data *board_data); extern void usbhs_init(struct usbhs_omap_platform_data *pdata); +extern int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys); extern void am35x_musb_reset(void); extern void am35x_musb_phy_power(u8 on); diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig index 37f513d1588e..0a8663c5f2ba 100644 --- a/arch/arm/mach-s3c24xx/Kconfig +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -30,6 +30,7 @@ config CPU_S3C2410 select S3C2410_CLOCK select S3C2410_CPUFREQ if CPU_FREQ_S3C24XX select S3C2410_PM if PM + select SAMSUNG_HRT help Support for S3C2410 and S3C2410A family from the S3C24XX line of Samsung Mobile CPUs. @@ -41,6 +42,7 @@ config CPU_S3C2412 select CPU_LLSERIAL_S3C2440 select S3C2412_DMA if S3C24XX_DMA select S3C2412_PM if PM + select SAMSUNG_HRT help Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line @@ -53,6 +55,7 @@ config CPU_S3C2416 select S3C2443_COMMON select S3C2443_DMA if S3C24XX_DMA select SAMSUNG_CLKSRC + select SAMSUNG_HRT help Support for the S3C2416 SoC from the S3C24XX line @@ -63,6 +66,7 @@ config CPU_S3C2440 select S3C2410_CLOCK select S3C2410_PM if PM select S3C2440_DMA if S3C24XX_DMA + select SAMSUNG_HRT help Support for S3C2440 Samsung Mobile CPU based systems. @@ -72,6 +76,7 @@ config CPU_S3C2442 select CPU_LLSERIAL_S3C2440 select S3C2410_CLOCK select S3C2410_PM if PM + select SAMSUNG_HRT help Support for S3C2442 Samsung Mobile CPU based systems. @@ -87,6 +92,7 @@ config CPU_S3C2443 select S3C2443_COMMON select S3C2443_DMA if S3C24XX_DMA select SAMSUNG_CLKSRC + select SAMSUNG_HRT help Support for the S3C2443 SoC from the S3C24XX line @@ -401,6 +407,7 @@ config S3C2412_DMA config S3C2412_PM bool select S3C2412_PM_SLEEP + select SAMSUNG_WAKEMASK help Internal config node to apply S3C2412 power management diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile index af53d27d5c36..6f46ecfc8396 100644 --- a/arch/arm/mach-s3c24xx/Makefile +++ b/arch/arm/mach-s3c24xx/Makefile @@ -14,7 +14,7 @@ obj- := # core -obj-y += common.o irq.o +obj-y += common.o obj-$(CONFIG_CPU_S3C2410) += s3c2410.o obj-$(CONFIG_S3C2410_CPUFREQ) += cpufreq-s3c2410.o @@ -22,7 +22,7 @@ obj-$(CONFIG_S3C2410_DMA) += dma-s3c2410.o obj-$(CONFIG_S3C2410_PLL) += pll-s3c2410.o obj-$(CONFIG_S3C2410_PM) += pm-s3c2410.o sleep-s3c2410.o -obj-$(CONFIG_CPU_S3C2412) += s3c2412.o irq-s3c2412.o clock-s3c2412.o +obj-$(CONFIG_CPU_S3C2412) += s3c2412.o clock-s3c2412.o obj-$(CONFIG_S3C2412_CPUFREQ) += cpufreq-s3c2412.o obj-$(CONFIG_S3C2412_DMA) += dma-s3c2412.o obj-$(CONFIG_S3C2412_PM) += pm-s3c2412.o @@ -31,9 +31,9 @@ obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o obj-$(CONFIG_CPU_S3C2416) += s3c2416.o clock-s3c2416.o obj-$(CONFIG_S3C2416_PM) += pm-s3c2416.o -obj-$(CONFIG_CPU_S3C2440) += s3c2440.o irq-s3c2440.o clock-s3c2440.o +obj-$(CONFIG_CPU_S3C2440) += s3c2440.o clock-s3c2440.o obj-$(CONFIG_CPU_S3C2442) += s3c2442.o -obj-$(CONFIG_CPU_S3C244X) += s3c244x.o irq-s3c244x.o clock-s3c244x.o +obj-$(CONFIG_CPU_S3C244X) += s3c244x.o clock-s3c244x.o obj-$(CONFIG_S3C2440_CPUFREQ) += cpufreq-s3c2440.o obj-$(CONFIG_S3C2440_DMA) += dma-s3c2440.o obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o diff --git a/arch/arm/mach-s3c24xx/bast-irq.c b/arch/arm/mach-s3c24xx/bast-irq.c index c0daa9590b4c..cb1b791954de 100644 --- a/arch/arm/mach-s3c24xx/bast-irq.c +++ b/arch/arm/mach-s3c24xx/bast-irq.c @@ -34,8 +34,6 @@ #include <mach/hardware.h> #include <mach/regs-irq.h> -#include <plat/irq.h> - #include "bast.h" #define irqdbf(x...) diff --git a/arch/arm/mach-s3c24xx/clock-s3c2410.c b/arch/arm/mach-s3c24xx/clock-s3c2410.c index 641266f3d152..34fffdf6fc1d 100644 --- a/arch/arm/mach-s3c24xx/clock-s3c2410.c +++ b/arch/arm/mach-s3c24xx/clock-s3c2410.c @@ -40,7 +40,6 @@ #include <mach/regs-clock.h> #include <mach/regs-gpio.h> -#include <plat/s3c2410.h> #include <plat/clock.h> #include <plat/cpu.h> diff --git a/arch/arm/mach-s3c24xx/clock-s3c2412.c b/arch/arm/mach-s3c24xx/clock-s3c2412.c index d10b695a9066..2cc017da88fe 100644 --- a/arch/arm/mach-s3c24xx/clock-s3c2412.c +++ b/arch/arm/mach-s3c24xx/clock-s3c2412.c @@ -41,7 +41,6 @@ #include <mach/regs-clock.h> #include <mach/regs-gpio.h> -#include <plat/s3c2412.h> #include <plat/clock.h> #include <plat/cpu.h> diff --git a/arch/arm/mach-s3c24xx/clock-s3c2416.c b/arch/arm/mach-s3c24xx/clock-s3c2416.c index 14a81c2317a4..036056cea57c 100644 --- a/arch/arm/mach-s3c24xx/clock-s3c2416.c +++ b/arch/arm/mach-s3c24xx/clock-s3c2416.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/clk.h> -#include <plat/s3c2416.h> #include <plat/clock.h> #include <plat/clock-clksrc.h> #include <plat/cpu.h> diff --git a/arch/arm/mach-s3c24xx/clock-s3c2443.c b/arch/arm/mach-s3c24xx/clock-s3c2443.c index bdaba59b42dc..0a53051b0787 100644 --- a/arch/arm/mach-s3c24xx/clock-s3c2443.c +++ b/arch/arm/mach-s3c24xx/clock-s3c2443.c @@ -41,7 +41,6 @@ #include <plat/cpu-freq.h> -#include <plat/s3c2443.h> #include <plat/clock.h> #include <plat/clock-clksrc.h> #include <plat/cpu.h> diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c index 3b2cf6db3634..404444dd3840 100644 --- a/arch/arm/mach-s3c24xx/common-smdk.c +++ b/arch/arm/mach-s3c24xx/common-smdk.c @@ -41,11 +41,12 @@ #include <linux/platform_data/mtd-nand-s3c2410.h> -#include <plat/common-smdk.h> #include <plat/gpio-cfg.h> #include <plat/devs.h> #include <plat/pm.h> +#include "common-smdk.h" + /* LED devices */ static struct s3c24xx_led_platdata smdk_pdata_led4 = { diff --git a/arch/arm/plat-samsung/include/plat/common-smdk.h b/arch/arm/mach-s3c24xx/common-smdk.h index ba028f1ed30b..98f733e1cb42 100644 --- a/arch/arm/plat-samsung/include/plat/common-smdk.h +++ b/arch/arm/mach-s3c24xx/common-smdk.h @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-samsung/include/plat/common-smdk.h - * +/* * Copyright (c) 2006 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c index 6bcf87f65f9e..d97533d21ac4 100644 --- a/arch/arm/mach-s3c24xx/common.c +++ b/arch/arm/mach-s3c24xx/common.c @@ -47,14 +47,11 @@ #include <plat/cpu.h> #include <plat/devs.h> #include <plat/clock.h> -#include <plat/s3c2410.h> -#include <plat/s3c2412.h> -#include <plat/s3c2416.h> -#include <plat/s3c244x.h> -#include <plat/s3c2443.h> #include <plat/cpu-freq.h> #include <plat/pll.h> +#include "common.h" + /* table of supported CPUs */ static const char name_s3c2410[] = "S3C2410"; diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h index ed6276fcaa3b..307c3714be55 100644 --- a/arch/arm/mach-s3c24xx/common.h +++ b/arch/arm/mach-s3c24xx/common.h @@ -12,8 +12,98 @@ #ifndef __ARCH_ARM_MACH_S3C24XX_COMMON_H #define __ARCH_ARM_MACH_S3C24XX_COMMON_H __FILE__ -void s3c2410_restart(char mode, const char *cmd); -void s3c244x_restart(char mode, const char *cmd); +struct s3c2410_uartcfg; + +#ifdef CONFIG_CPU_S3C2410 +extern int s3c2410_init(void); +extern int s3c2410a_init(void); +extern void s3c2410_map_io(void); +extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c2410_init_clocks(int xtal); +extern void s3c2410_restart(char mode, const char *cmd); +extern void s3c2410_init_irq(void); +#else +#define s3c2410_init_clocks NULL +#define s3c2410_init_uarts NULL +#define s3c2410_map_io NULL +#define s3c2410_init NULL +#define s3c2410a_init NULL +#endif + +#ifdef CONFIG_CPU_S3C2412 +extern int s3c2412_init(void); +extern void s3c2412_map_io(void); +extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c2412_init_clocks(int xtal); +extern int s3c2412_baseclk_add(void); +extern void s3c2412_restart(char mode, const char *cmd); +extern void s3c2412_init_irq(void); +#else +#define s3c2412_init_clocks NULL +#define s3c2412_init_uarts NULL +#define s3c2412_map_io NULL +#define s3c2412_init NULL +#endif + +#ifdef CONFIG_CPU_S3C2416 +extern int s3c2416_init(void); +extern void s3c2416_map_io(void); +extern void s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c2416_init_clocks(int xtal); +extern int s3c2416_baseclk_add(void); +extern void s3c2416_restart(char mode, const char *cmd); +extern void s3c2416_init_irq(void); + +extern struct syscore_ops s3c2416_irq_syscore_ops; +#else +#define s3c2416_init_clocks NULL +#define s3c2416_init_uarts NULL +#define s3c2416_map_io NULL +#define s3c2416_init NULL +#endif + +#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) +extern void s3c244x_map_io(void); +extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c244x_init_clocks(int xtal); +extern void s3c244x_restart(char mode, const char *cmd); +#else +#define s3c244x_init_clocks NULL +#define s3c244x_init_uarts NULL +#endif + +#ifdef CONFIG_CPU_S3C2440 +extern int s3c2440_init(void); +extern void s3c2440_map_io(void); +extern void s3c2440_init_irq(void); +#else +#define s3c2440_init NULL +#define s3c2440_map_io NULL +#endif + +#ifdef CONFIG_CPU_S3C2442 +extern int s3c2442_init(void); +extern void s3c2442_map_io(void); +extern void s3c2442_init_irq(void); +#else +#define s3c2442_init NULL +#define s3c2442_map_io NULL +#endif + +#ifdef CONFIG_CPU_S3C2443 +extern int s3c2443_init(void); +extern void s3c2443_map_io(void); +extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c2443_init_clocks(int xtal); +extern int s3c2443_baseclk_add(void); +extern void s3c2443_restart(char mode, const char *cmd); +extern void s3c2443_init_irq(void); +#else +#define s3c2443_init_clocks NULL +#define s3c2443_init_uarts NULL +#define s3c2443_map_io NULL +#define s3c2443_init NULL +#endif extern struct syscore_ops s3c24xx_irq_syscore_ops; diff --git a/arch/arm/mach-s3c24xx/dma-s3c2410.c b/arch/arm/mach-s3c24xx/dma-s3c2410.c index 25d085adc93c..a6c94b820954 100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2410.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2410.c @@ -28,7 +28,6 @@ #include <plat/regs-ac97.h> #include <plat/regs-dma.h> #include <mach/regs-lcd.h> -#include <mach/regs-sdi.h> #include <plat/regs-iis.h> #include <plat/regs-spi.h> diff --git a/arch/arm/mach-s3c24xx/dma-s3c2412.c b/arch/arm/mach-s3c24xx/dma-s3c2412.c index d2408ba372cb..c0e8c3f5057e 100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2412.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2412.c @@ -28,7 +28,6 @@ #include <plat/regs-ac97.h> #include <plat/regs-dma.h> #include <mach/regs-lcd.h> -#include <mach/regs-sdi.h> #include <plat/regs-iis.h> #include <plat/regs-spi.h> diff --git a/arch/arm/mach-s3c24xx/dma-s3c2440.c b/arch/arm/mach-s3c24xx/dma-s3c2440.c index 0b86e74d104f..1c08eccd9425 100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2440.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2440.c @@ -28,7 +28,6 @@ #include <plat/regs-ac97.h> #include <plat/regs-dma.h> #include <mach/regs-lcd.h> -#include <mach/regs-sdi.h> #include <plat/regs-iis.h> #include <plat/regs-spi.h> diff --git a/arch/arm/mach-s3c24xx/dma-s3c2443.c b/arch/arm/mach-s3c24xx/dma-s3c2443.c index 05536254a3f8..000e4c69fce9 100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2443.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2443.c @@ -28,7 +28,6 @@ #include <plat/regs-ac97.h> #include <plat/regs-dma.h> #include <mach/regs-lcd.h> -#include <mach/regs-sdi.h> #include <plat/regs-iis.h> #include <plat/regs-spi.h> diff --git a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S deleted file mode 100644 index 6a21beeba1da..000000000000 --- a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S +++ /dev/null @@ -1,70 +0,0 @@ -/* - * arch/arm/mach-s3c2410/include/mach/entry-macro.S - * - * Low-level IRQ helper macros for S3C2410-based platforms - * - * 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. -*/ - -/* We have a problem that the INTOFFSET register does not always - * show one interrupt. Occasionally we get two interrupts through - * the prioritiser, and this causes the INTOFFSET register to show - * what looks like the logical-or of the two interrupt numbers. - * - * Thanks to Klaus, Shannon, et al for helping to debug this problem -*/ - -#define INTPND (0x10) -#define INTOFFSET (0x14) - -#include <mach/hardware.h> -#include <asm/irq.h> - - .macro get_irqnr_preamble, base, tmp - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - - mov \base, #S3C24XX_VA_IRQ - - @@ try the interrupt offset register, since it is there - - ldr \irqstat, [\base, #INTPND ] - teq \irqstat, #0 - beq 1002f - ldr \irqnr, [\base, #INTOFFSET ] - mov \tmp, #1 - tst \irqstat, \tmp, lsl \irqnr - bne 1001f - - @@ the number specified is not a valid irq, so try - @@ and work it out for ourselves - - mov \irqnr, #0 @@ start here - - @@ work out which irq (if any) we got - - movs \tmp, \irqstat, lsl#16 - addeq \irqnr, \irqnr, #16 - moveq \irqstat, \irqstat, lsr#16 - tst \irqstat, #0xff - addeq \irqnr, \irqnr, #8 - moveq \irqstat, \irqstat, lsr#8 - tst \irqstat, #0xf - addeq \irqnr, \irqnr, #4 - moveq \irqstat, \irqstat, lsr#4 - tst \irqstat, #0x3 - addeq \irqnr, \irqnr, #2 - moveq \irqstat, \irqstat, lsr#2 - tst \irqstat, #0x1 - addeq \irqnr, \irqnr, #1 - - @@ we have the value -1001: - adds \irqnr, \irqnr, #IRQ_EINT0 -1002: - @@ exit here, Z flag unset if IRQ - - .endm diff --git a/arch/arm/mach-s3c24xx/include/mach/irqs.h b/arch/arm/mach-s3c24xx/include/mach/irqs.h index b7a9f4d469e8..43cada8019b4 100644 --- a/arch/arm/mach-s3c24xx/include/mach/irqs.h +++ b/arch/arm/mach-s3c24xx/include/mach/irqs.h @@ -59,49 +59,53 @@ #define IRQ_ADCPARENT S3C2410_IRQ(31) /* interrupts generated from the external interrupts sources */ -#define IRQ_EINT4 S3C2410_IRQ(32) /* 48 */ -#define IRQ_EINT5 S3C2410_IRQ(33) -#define IRQ_EINT6 S3C2410_IRQ(34) -#define IRQ_EINT7 S3C2410_IRQ(35) -#define IRQ_EINT8 S3C2410_IRQ(36) -#define IRQ_EINT9 S3C2410_IRQ(37) -#define IRQ_EINT10 S3C2410_IRQ(38) -#define IRQ_EINT11 S3C2410_IRQ(39) -#define IRQ_EINT12 S3C2410_IRQ(40) -#define IRQ_EINT13 S3C2410_IRQ(41) -#define IRQ_EINT14 S3C2410_IRQ(42) -#define IRQ_EINT15 S3C2410_IRQ(43) -#define IRQ_EINT16 S3C2410_IRQ(44) -#define IRQ_EINT17 S3C2410_IRQ(45) -#define IRQ_EINT18 S3C2410_IRQ(46) -#define IRQ_EINT19 S3C2410_IRQ(47) -#define IRQ_EINT20 S3C2410_IRQ(48) /* 64 */ -#define IRQ_EINT21 S3C2410_IRQ(49) -#define IRQ_EINT22 S3C2410_IRQ(50) -#define IRQ_EINT23 S3C2410_IRQ(51) +#define IRQ_EINT0_2412 S3C2410_IRQ(32) +#define IRQ_EINT1_2412 S3C2410_IRQ(33) +#define IRQ_EINT2_2412 S3C2410_IRQ(34) +#define IRQ_EINT3_2412 S3C2410_IRQ(35) +#define IRQ_EINT4 S3C2410_IRQ(36) /* 52 */ +#define IRQ_EINT5 S3C2410_IRQ(37) +#define IRQ_EINT6 S3C2410_IRQ(38) +#define IRQ_EINT7 S3C2410_IRQ(39) +#define IRQ_EINT8 S3C2410_IRQ(40) +#define IRQ_EINT9 S3C2410_IRQ(41) +#define IRQ_EINT10 S3C2410_IRQ(42) +#define IRQ_EINT11 S3C2410_IRQ(43) +#define IRQ_EINT12 S3C2410_IRQ(44) +#define IRQ_EINT13 S3C2410_IRQ(45) +#define IRQ_EINT14 S3C2410_IRQ(46) +#define IRQ_EINT15 S3C2410_IRQ(47) +#define IRQ_EINT16 S3C2410_IRQ(48) +#define IRQ_EINT17 S3C2410_IRQ(49) +#define IRQ_EINT18 S3C2410_IRQ(50) +#define IRQ_EINT19 S3C2410_IRQ(51) +#define IRQ_EINT20 S3C2410_IRQ(52) /* 68 */ +#define IRQ_EINT21 S3C2410_IRQ(53) +#define IRQ_EINT22 S3C2410_IRQ(54) +#define IRQ_EINT23 S3C2410_IRQ(55) #define IRQ_EINT_BIT(x) ((x) - IRQ_EINT4 + 4) #define IRQ_EINT(x) (((x) >= 4) ? (IRQ_EINT4 + (x) - 4) : (IRQ_EINT0 + (x))) -#define IRQ_LCD_FIFO S3C2410_IRQ(52) -#define IRQ_LCD_FRAME S3C2410_IRQ(53) +#define IRQ_LCD_FIFO S3C2410_IRQ(56) +#define IRQ_LCD_FRAME S3C2410_IRQ(57) /* IRQs for the interal UARTs, and ADC * these need to be ordered in number of appearance in the * SUBSRC mask register */ -#define S3C2410_IRQSUB(x) S3C2410_IRQ((x)+54) +#define S3C2410_IRQSUB(x) S3C2410_IRQ((x)+58) -#define IRQ_S3CUART_RX0 S3C2410_IRQSUB(0) /* 70 */ +#define IRQ_S3CUART_RX0 S3C2410_IRQSUB(0) /* 74 */ #define IRQ_S3CUART_TX0 S3C2410_IRQSUB(1) #define IRQ_S3CUART_ERR0 S3C2410_IRQSUB(2) -#define IRQ_S3CUART_RX1 S3C2410_IRQSUB(3) /* 73 */ +#define IRQ_S3CUART_RX1 S3C2410_IRQSUB(3) /* 77 */ #define IRQ_S3CUART_TX1 S3C2410_IRQSUB(4) #define IRQ_S3CUART_ERR1 S3C2410_IRQSUB(5) -#define IRQ_S3CUART_RX2 S3C2410_IRQSUB(6) /* 76 */ +#define IRQ_S3CUART_RX2 S3C2410_IRQSUB(6) /* 80 */ #define IRQ_S3CUART_TX2 S3C2410_IRQSUB(7) #define IRQ_S3CUART_ERR2 S3C2410_IRQSUB(8) @@ -136,7 +140,7 @@ /* second interrupt-register of s3c2416/s3c2450 */ -#define S3C2416_IRQ(x) S3C2410_IRQ((x) + 54 + 29) +#define S3C2416_IRQ(x) S3C2410_IRQ((x) + 58 + 29) #define IRQ_S3C2416_2D S3C2416_IRQ(0) #define IRQ_S3C2416_IIC1 S3C2416_IRQ(1) #define IRQ_S3C2416_RESERVED2 S3C2416_IRQ(2) diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-sdi.h b/arch/arm/mach-s3c24xx/include/mach/regs-sdi.h deleted file mode 100644 index cbf2d8884e30..000000000000 --- a/arch/arm/mach-s3c24xx/include/mach/regs-sdi.h +++ /dev/null @@ -1,127 +0,0 @@ -/* arch/arm/mach-s3c2410/include/mach/regs-sdi.h - * - * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> - * http://www.simtec.co.uk/products/SWLINUX/ - * - * 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. - * - * S3C2410 MMC/SDIO register definitions -*/ - -#ifndef __ASM_ARM_REGS_SDI -#define __ASM_ARM_REGS_SDI "regs-sdi.h" - -#define S3C2410_SDICON (0x00) -#define S3C2410_SDIPRE (0x04) -#define S3C2410_SDICMDARG (0x08) -#define S3C2410_SDICMDCON (0x0C) -#define S3C2410_SDICMDSTAT (0x10) -#define S3C2410_SDIRSP0 (0x14) -#define S3C2410_SDIRSP1 (0x18) -#define S3C2410_SDIRSP2 (0x1C) -#define S3C2410_SDIRSP3 (0x20) -#define S3C2410_SDITIMER (0x24) -#define S3C2410_SDIBSIZE (0x28) -#define S3C2410_SDIDCON (0x2C) -#define S3C2410_SDIDCNT (0x30) -#define S3C2410_SDIDSTA (0x34) -#define S3C2410_SDIFSTA (0x38) - -#define S3C2410_SDIDATA (0x3C) -#define S3C2410_SDIIMSK (0x40) - -#define S3C2440_SDIDATA (0x40) -#define S3C2440_SDIIMSK (0x3C) - -#define S3C2440_SDICON_SDRESET (1<<8) -#define S3C2440_SDICON_MMCCLOCK (1<<5) -#define S3C2410_SDICON_BYTEORDER (1<<4) -#define S3C2410_SDICON_SDIOIRQ (1<<3) -#define S3C2410_SDICON_RWAITEN (1<<2) -#define S3C2410_SDICON_FIFORESET (1<<1) -#define S3C2410_SDICON_CLOCKTYPE (1<<0) - -#define S3C2410_SDICMDCON_ABORT (1<<12) -#define S3C2410_SDICMDCON_WITHDATA (1<<11) -#define S3C2410_SDICMDCON_LONGRSP (1<<10) -#define S3C2410_SDICMDCON_WAITRSP (1<<9) -#define S3C2410_SDICMDCON_CMDSTART (1<<8) -#define S3C2410_SDICMDCON_SENDERHOST (1<<6) -#define S3C2410_SDICMDCON_INDEX (0x3f) - -#define S3C2410_SDICMDSTAT_CRCFAIL (1<<12) -#define S3C2410_SDICMDSTAT_CMDSENT (1<<11) -#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1<<10) -#define S3C2410_SDICMDSTAT_RSPFIN (1<<9) -#define S3C2410_SDICMDSTAT_XFERING (1<<8) -#define S3C2410_SDICMDSTAT_INDEX (0xff) - -#define S3C2440_SDIDCON_DS_BYTE (0<<22) -#define S3C2440_SDIDCON_DS_HALFWORD (1<<22) -#define S3C2440_SDIDCON_DS_WORD (2<<22) -#define S3C2410_SDIDCON_IRQPERIOD (1<<21) -#define S3C2410_SDIDCON_TXAFTERRESP (1<<20) -#define S3C2410_SDIDCON_RXAFTERCMD (1<<19) -#define S3C2410_SDIDCON_BUSYAFTERCMD (1<<18) -#define S3C2410_SDIDCON_BLOCKMODE (1<<17) -#define S3C2410_SDIDCON_WIDEBUS (1<<16) -#define S3C2410_SDIDCON_DMAEN (1<<15) -#define S3C2410_SDIDCON_STOP (1<<14) -#define S3C2440_SDIDCON_DATSTART (1<<14) -#define S3C2410_SDIDCON_DATMODE (3<<12) -#define S3C2410_SDIDCON_BLKNUM (0x7ff) - -/* constants for S3C2410_SDIDCON_DATMODE */ -#define S3C2410_SDIDCON_XFER_READY (0<<12) -#define S3C2410_SDIDCON_XFER_CHKSTART (1<<12) -#define S3C2410_SDIDCON_XFER_RXSTART (2<<12) -#define S3C2410_SDIDCON_XFER_TXSTART (3<<12) - -#define S3C2410_SDIDCON_BLKNUM_MASK (0xFFF) -#define S3C2410_SDIDCNT_BLKNUM_SHIFT (12) - -#define S3C2410_SDIDSTA_RDYWAITREQ (1<<10) -#define S3C2410_SDIDSTA_SDIOIRQDETECT (1<<9) -#define S3C2410_SDIDSTA_FIFOFAIL (1<<8) /* reserved on 2440 */ -#define S3C2410_SDIDSTA_CRCFAIL (1<<7) -#define S3C2410_SDIDSTA_RXCRCFAIL (1<<6) -#define S3C2410_SDIDSTA_DATATIMEOUT (1<<5) -#define S3C2410_SDIDSTA_XFERFINISH (1<<4) -#define S3C2410_SDIDSTA_BUSYFINISH (1<<3) -#define S3C2410_SDIDSTA_SBITERR (1<<2) /* reserved on 2410a/2440 */ -#define S3C2410_SDIDSTA_TXDATAON (1<<1) -#define S3C2410_SDIDSTA_RXDATAON (1<<0) - -#define S3C2440_SDIFSTA_FIFORESET (1<<16) -#define S3C2440_SDIFSTA_FIFOFAIL (3<<14) /* 3 is correct (2 bits) */ -#define S3C2410_SDIFSTA_TFDET (1<<13) -#define S3C2410_SDIFSTA_RFDET (1<<12) -#define S3C2410_SDIFSTA_TFHALF (1<<11) -#define S3C2410_SDIFSTA_TFEMPTY (1<<10) -#define S3C2410_SDIFSTA_RFLAST (1<<9) -#define S3C2410_SDIFSTA_RFFULL (1<<8) -#define S3C2410_SDIFSTA_RFHALF (1<<7) -#define S3C2410_SDIFSTA_COUNTMASK (0x7f) - -#define S3C2410_SDIIMSK_RESPONSECRC (1<<17) -#define S3C2410_SDIIMSK_CMDSENT (1<<16) -#define S3C2410_SDIIMSK_CMDTIMEOUT (1<<15) -#define S3C2410_SDIIMSK_RESPONSEND (1<<14) -#define S3C2410_SDIIMSK_READWAIT (1<<13) -#define S3C2410_SDIIMSK_SDIOIRQ (1<<12) -#define S3C2410_SDIIMSK_FIFOFAIL (1<<11) -#define S3C2410_SDIIMSK_CRCSTATUS (1<<10) -#define S3C2410_SDIIMSK_DATACRC (1<<9) -#define S3C2410_SDIIMSK_DATATIMEOUT (1<<8) -#define S3C2410_SDIIMSK_DATAFINISH (1<<7) -#define S3C2410_SDIIMSK_BUSYFINISH (1<<6) -#define S3C2410_SDIIMSK_SBITERR (1<<5) /* reserved 2440/2410a */ -#define S3C2410_SDIIMSK_TXFIFOHALF (1<<4) -#define S3C2410_SDIIMSK_TXFIFOEMPTY (1<<3) -#define S3C2410_SDIIMSK_RXFIFOLAST (1<<2) -#define S3C2410_SDIIMSK_RXFIFOFULL (1<<1) -#define S3C2410_SDIIMSK_RXFIFOHALF (1<<0) - -#endif /* __ASM_ARM_REGS_SDI */ diff --git a/arch/arm/mach-s3c24xx/irq-pm.c b/arch/arm/mach-s3c24xx/irq-pm.c index e1199599873e..b91341ef2b2e 100644 --- a/arch/arm/mach-s3c24xx/irq-pm.c +++ b/arch/arm/mach-s3c24xx/irq-pm.c @@ -16,10 +16,15 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/syscore_ops.h> +#include <linux/io.h> #include <plat/cpu.h> #include <plat/pm.h> -#include <plat/irq.h> +#include <plat/map-base.h> +#include <plat/map-s3c.h> + +#include <mach/regs-irq.h> +#include <mach/regs-gpio.h> #include <asm/irq.h> diff --git a/arch/arm/mach-s3c24xx/irq-s3c2412.c b/arch/arm/mach-s3c24xx/irq-s3c2412.c deleted file mode 100644 index 67d763178d3f..000000000000 --- a/arch/arm/mach-s3c24xx/irq-s3c2412.c +++ /dev/null @@ -1,215 +0,0 @@ -/* linux/arch/arm/mach-s3c2412/irq.c - * - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * 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/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/irq.h> - -#include <asm/mach/irq.h> - -#include <mach/regs-irq.h> -#include <mach/regs-gpio.h> - -#include <plat/cpu.h> -#include <plat/irq.h> -#include <plat/pm.h> - -#include "s3c2412-power.h" - -#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1) -#define INTMSK_SUB(start, end) (INTMSK(start, end) << ((start - S3C2410_IRQSUB(0)))) - -/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by - * having them turn up in both the INT* and the EINT* registers. Whilst - * both show the status, they both now need to be acked when the IRQs - * go off. -*/ - -static void -s3c2412_irq_mask(struct irq_data *data) -{ - unsigned long bitval = 1UL << (data->irq - IRQ_EINT0); - unsigned long mask; - - mask = __raw_readl(S3C2410_INTMSK); - __raw_writel(mask | bitval, S3C2410_INTMSK); - - mask = __raw_readl(S3C2412_EINTMASK); - __raw_writel(mask | bitval, S3C2412_EINTMASK); -} - -static inline void -s3c2412_irq_ack(struct irq_data *data) -{ - unsigned long bitval = 1UL << (data->irq - IRQ_EINT0); - - __raw_writel(bitval, S3C2412_EINTPEND); - __raw_writel(bitval, S3C2410_SRCPND); - __raw_writel(bitval, S3C2410_INTPND); -} - -static inline void -s3c2412_irq_maskack(struct irq_data *data) -{ - unsigned long bitval = 1UL << (data->irq - IRQ_EINT0); - unsigned long mask; - - mask = __raw_readl(S3C2410_INTMSK); - __raw_writel(mask|bitval, S3C2410_INTMSK); - - mask = __raw_readl(S3C2412_EINTMASK); - __raw_writel(mask | bitval, S3C2412_EINTMASK); - - __raw_writel(bitval, S3C2412_EINTPEND); - __raw_writel(bitval, S3C2410_SRCPND); - __raw_writel(bitval, S3C2410_INTPND); -} - -static void -s3c2412_irq_unmask(struct irq_data *data) -{ - unsigned long bitval = 1UL << (data->irq - IRQ_EINT0); - unsigned long mask; - - mask = __raw_readl(S3C2412_EINTMASK); - __raw_writel(mask & ~bitval, S3C2412_EINTMASK); - - mask = __raw_readl(S3C2410_INTMSK); - __raw_writel(mask & ~bitval, S3C2410_INTMSK); -} - -static struct irq_chip s3c2412_irq_eint0t4 = { - .irq_ack = s3c2412_irq_ack, - .irq_mask = s3c2412_irq_mask, - .irq_unmask = s3c2412_irq_unmask, - .irq_set_wake = s3c_irq_wake, - .irq_set_type = s3c_irqext_type, -}; - -#define INTBIT(x) (1 << ((x) - S3C2410_IRQSUB(0))) - -/* CF and SDI sub interrupts */ - -static void s3c2412_irq_demux_cfsdi(unsigned int irq, struct irq_desc *desc) -{ - unsigned int subsrc, submsk; - - subsrc = __raw_readl(S3C2410_SUBSRCPND); - submsk = __raw_readl(S3C2410_INTSUBMSK); - - subsrc &= ~submsk; - - if (subsrc & INTBIT(IRQ_S3C2412_SDI)) - generic_handle_irq(IRQ_S3C2412_SDI); - - if (subsrc & INTBIT(IRQ_S3C2412_CF)) - generic_handle_irq(IRQ_S3C2412_CF); -} - -#define INTMSK_CFSDI (1UL << (IRQ_S3C2412_CFSDI - IRQ_EINT0)) -#define SUBMSK_CFSDI INTMSK_SUB(IRQ_S3C2412_SDI, IRQ_S3C2412_CF) - -static void s3c2412_irq_cfsdi_mask(struct irq_data *data) -{ - s3c_irqsub_mask(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI); -} - -static void s3c2412_irq_cfsdi_unmask(struct irq_data *data) -{ - s3c_irqsub_unmask(data->irq, INTMSK_CFSDI); -} - -static void s3c2412_irq_cfsdi_ack(struct irq_data *data) -{ - s3c_irqsub_maskack(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI); -} - -static struct irq_chip s3c2412_irq_cfsdi = { - .name = "s3c2412-cfsdi", - .irq_ack = s3c2412_irq_cfsdi_ack, - .irq_mask = s3c2412_irq_cfsdi_mask, - .irq_unmask = s3c2412_irq_cfsdi_unmask, -}; - -static int s3c2412_irq_rtc_wake(struct irq_data *data, unsigned int state) -{ - unsigned long pwrcfg; - - pwrcfg = __raw_readl(S3C2412_PWRCFG); - if (state) - pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ; - else - pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ; - __raw_writel(pwrcfg, S3C2412_PWRCFG); - - return s3c_irq_chip.irq_set_wake(data, state); -} - -static struct irq_chip s3c2412_irq_rtc_chip; - -static int s3c2412_irq_add(struct device *dev, struct subsys_interface *sif) -{ - unsigned int irqno; - - for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { - irq_set_chip_and_handler(irqno, &s3c2412_irq_eint0t4, - handle_edge_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - /* add demux support for CF/SDI */ - - irq_set_chained_handler(IRQ_S3C2412_CFSDI, s3c2412_irq_demux_cfsdi); - - for (irqno = IRQ_S3C2412_SDI; irqno <= IRQ_S3C2412_CF; irqno++) { - irq_set_chip_and_handler(irqno, &s3c2412_irq_cfsdi, - handle_level_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - /* change RTC IRQ's set wake method */ - - s3c2412_irq_rtc_chip = s3c_irq_chip; - s3c2412_irq_rtc_chip.irq_set_wake = s3c2412_irq_rtc_wake; - - irq_set_chip(IRQ_RTC, &s3c2412_irq_rtc_chip); - - return 0; -} - -static struct subsys_interface s3c2412_irq_interface = { - .name = "s3c2412_irq", - .subsys = &s3c2412_subsys, - .add_dev = s3c2412_irq_add, -}; - -static int s3c2412_irq_init(void) -{ - return subsys_interface_register(&s3c2412_irq_interface); -} - -arch_initcall(s3c2412_irq_init); diff --git a/arch/arm/mach-s3c24xx/irq-s3c2440.c b/arch/arm/mach-s3c24xx/irq-s3c2440.c deleted file mode 100644 index 4a18cde439cc..000000000000 --- a/arch/arm/mach-s3c24xx/irq-s3c2440.c +++ /dev/null @@ -1,128 +0,0 @@ -/* linux/arch/arm/mach-s3c2440/irq.c - * - * Copyright (c) 2003-2004 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * 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/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/irq.h> - -#include <asm/mach/irq.h> - -#include <mach/regs-irq.h> -#include <mach/regs-gpio.h> - -#include <plat/cpu.h> -#include <plat/pm.h> -#include <plat/irq.h> - -/* WDT/AC97 */ - -static void s3c_irq_demux_wdtac97(unsigned int irq, - struct irq_desc *desc) -{ - unsigned int subsrc, submsk; - - /* read the current pending interrupts, and the mask - * for what it is available */ - - subsrc = __raw_readl(S3C2410_SUBSRCPND); - submsk = __raw_readl(S3C2410_INTSUBMSK); - - subsrc &= ~submsk; - subsrc >>= 13; - subsrc &= 3; - - if (subsrc != 0) { - if (subsrc & 1) { - generic_handle_irq(IRQ_S3C2440_WDT); - } - if (subsrc & 2) { - generic_handle_irq(IRQ_S3C2440_AC97); - } - } -} - - -#define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0)) - -static void -s3c_irq_wdtac97_mask(struct irq_data *data) -{ - s3c_irqsub_mask(data->irq, INTMSK_WDT, 3 << 13); -} - -static void -s3c_irq_wdtac97_unmask(struct irq_data *data) -{ - s3c_irqsub_unmask(data->irq, INTMSK_WDT); -} - -static void -s3c_irq_wdtac97_ack(struct irq_data *data) -{ - s3c_irqsub_maskack(data->irq, INTMSK_WDT, 3 << 13); -} - -static struct irq_chip s3c_irq_wdtac97 = { - .irq_mask = s3c_irq_wdtac97_mask, - .irq_unmask = s3c_irq_wdtac97_unmask, - .irq_ack = s3c_irq_wdtac97_ack, -}; - -static int s3c2440_irq_add(struct device *dev, struct subsys_interface *sif) -{ - unsigned int irqno; - - printk("S3C2440: IRQ Support\n"); - - /* add new chained handler for wdt, ac7 */ - - irq_set_chip_and_handler(IRQ_WDT, &s3c_irq_level_chip, - handle_level_irq); - irq_set_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97); - - for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) { - irq_set_chip_and_handler(irqno, &s3c_irq_wdtac97, - handle_level_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - return 0; -} - -static struct subsys_interface s3c2440_irq_interface = { - .name = "s3c2440_irq", - .subsys = &s3c2440_subsys, - .add_dev = s3c2440_irq_add, -}; - -static int s3c2440_irq_init(void) -{ - return subsys_interface_register(&s3c2440_irq_interface); -} - -arch_initcall(s3c2440_irq_init); - diff --git a/arch/arm/mach-s3c24xx/irq-s3c244x.c b/arch/arm/mach-s3c24xx/irq-s3c244x.c deleted file mode 100644 index 5fe8e58d3afd..000000000000 --- a/arch/arm/mach-s3c24xx/irq-s3c244x.c +++ /dev/null @@ -1,142 +0,0 @@ -/* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c - * - * Copyright (c) 2003-2004 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * 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/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/irq.h> - -#include <asm/mach/irq.h> - -#include <mach/regs-irq.h> -#include <mach/regs-gpio.h> - -#include <plat/cpu.h> -#include <plat/pm.h> -#include <plat/irq.h> - -/* camera irq */ - -static void s3c_irq_demux_cam(unsigned int irq, - struct irq_desc *desc) -{ - unsigned int subsrc, submsk; - - /* read the current pending interrupts, and the mask - * for what it is available */ - - subsrc = __raw_readl(S3C2410_SUBSRCPND); - submsk = __raw_readl(S3C2410_INTSUBMSK); - - subsrc &= ~submsk; - subsrc >>= 11; - subsrc &= 3; - - if (subsrc != 0) { - if (subsrc & 1) { - generic_handle_irq(IRQ_S3C2440_CAM_C); - } - if (subsrc & 2) { - generic_handle_irq(IRQ_S3C2440_CAM_P); - } - } -} - -#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) - -static void -s3c_irq_cam_mask(struct irq_data *data) -{ - s3c_irqsub_mask(data->irq, INTMSK_CAM, 3 << 11); -} - -static void -s3c_irq_cam_unmask(struct irq_data *data) -{ - s3c_irqsub_unmask(data->irq, INTMSK_CAM); -} - -static void -s3c_irq_cam_ack(struct irq_data *data) -{ - s3c_irqsub_maskack(data->irq, INTMSK_CAM, 3 << 11); -} - -static struct irq_chip s3c_irq_cam = { - .irq_mask = s3c_irq_cam_mask, - .irq_unmask = s3c_irq_cam_unmask, - .irq_ack = s3c_irq_cam_ack, -}; - -static int s3c244x_irq_add(struct device *dev, struct subsys_interface *sif) -{ - unsigned int irqno; - - irq_set_chip_and_handler(IRQ_NFCON, &s3c_irq_level_chip, - handle_level_irq); - set_irq_flags(IRQ_NFCON, IRQF_VALID); - - /* add chained handler for camera */ - - irq_set_chip_and_handler(IRQ_CAM, &s3c_irq_level_chip, - handle_level_irq); - irq_set_chained_handler(IRQ_CAM, s3c_irq_demux_cam); - - for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) { - irq_set_chip_and_handler(irqno, &s3c_irq_cam, - handle_level_irq); - set_irq_flags(irqno, IRQF_VALID); - } - - return 0; -} - -static struct subsys_interface s3c2440_irq_interface = { - .name = "s3c2440_irq", - .subsys = &s3c2440_subsys, - .add_dev = s3c244x_irq_add, -}; - -static int s3c2440_irq_init(void) -{ - return subsys_interface_register(&s3c2440_irq_interface); -} - -arch_initcall(s3c2440_irq_init); - -static struct subsys_interface s3c2442_irq_interface = { - .name = "s3c2442_irq", - .subsys = &s3c2442_subsys, - .add_dev = s3c244x_irq_add, -}; - - -static int s3c2442_irq_init(void) -{ - return subsys_interface_register(&s3c2442_irq_interface); -} - -arch_initcall(s3c2442_irq_init); diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c index 0e0279e79150..e27b5c91b3db 100644 --- a/arch/arm/mach-s3c24xx/mach-amlm5900.c +++ b/arch/arm/mach-s3c24xx/mach-amlm5900.c @@ -63,6 +63,8 @@ #include <linux/mtd/map.h> #include <linux/mtd/physmap.h> +#include <plat/samsung-time.h> + #include "common.h" static struct resource amlm5900_nor_resource = @@ -160,6 +162,7 @@ static void __init amlm5900_map_io(void) s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } #ifdef CONFIG_FB_S3C2410 @@ -235,8 +238,8 @@ static void __init amlm5900_init(void) MACHINE_START(AML_M5900, "AML_M5900") .atag_offset = 0x100, .map_io = amlm5900_map_io, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2410_init_irq, .init_machine = amlm5900_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c index bb595f15ce36..c1fb6c37867f 100644 --- a/arch/arm/mach-s3c24xx/mach-anubis.c +++ b/arch/arm/mach-s3c24xx/mach-anubis.c @@ -49,6 +49,7 @@ #include <plat/devs.h> #include <plat/cpu.h> #include <linux/platform_data/asoc-s3c24xx_simtec.h> +#include <plat/samsung-time.h> #include "anubis.h" #include "common.h" @@ -410,6 +411,7 @@ static void __init anubis_map_io(void) s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); /* check for the newer revision boards with large page nand */ @@ -443,7 +445,7 @@ MACHINE_START(ANUBIS, "Simtec-Anubis") .atag_offset = 0x100, .map_io = anubis_map_io, .init_machine = anubis_init, - .init_irq = s3c24xx_init_irq, - .init_time = s3c24xx_timer_init, + .init_irq = s3c2440_init_irq, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c index b4bc60c78ebb..6dfeeb7ef469 100644 --- a/arch/arm/mach-s3c24xx/mach-at2440evb.c +++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c @@ -48,6 +48,7 @@ #include <plat/devs.h> #include <plat/cpu.h> #include <linux/platform_data/mmc-s3cmci.h> +#include <plat/samsung-time.h> #include "common.h" @@ -192,6 +193,7 @@ static void __init at2440evb_map_io(void) s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc)); s3c24xx_init_clocks(16934400); s3c24xx_init_uarts(at2440evb_uartcfgs, ARRAY_SIZE(at2440evb_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init at2440evb_init(void) @@ -209,7 +211,7 @@ MACHINE_START(AT2440EVB, "AT2440EVB") .atag_offset = 0x100, .map_io = at2440evb_map_io, .init_machine = at2440evb_init, - .init_irq = s3c24xx_init_irq, - .init_time = s3c24xx_timer_init, + .init_irq = s3c2440_init_irq, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c index ca6618081041..22d6ae926d91 100644 --- a/arch/arm/mach-s3c24xx/mach-bast.c +++ b/arch/arm/mach-s3c24xx/mach-bast.c @@ -55,6 +55,7 @@ #include <plat/devs.h> #include <plat/gpio-cfg.h> #include <plat/regs-serial.h> +#include <plat/samsung-time.h> #include "bast.h" #include "common.h" @@ -576,6 +577,7 @@ static void __init bast_map_io(void) s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init bast_init(void) @@ -603,8 +605,8 @@ MACHINE_START(BAST, "Simtec-BAST") /* Maintainer: Ben Dooks <ben@simtec.co.uk> */ .atag_offset = 0x100, .map_io = bast_map_io, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2410_init_irq, .init_machine = bast_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c index a25e8c5a7b4c..13d8d073675a 100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -81,6 +81,7 @@ #include <plat/gpio-cfg.h> #include <plat/pm.h> #include <plat/regs-serial.h> +#include <plat/samsung-time.h> #include "common.h" #include "gta02.h" @@ -501,6 +502,7 @@ static void __init gta02_map_io(void) s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } @@ -587,8 +589,8 @@ MACHINE_START(NEO1973_GTA02, "GTA02") /* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */ .atag_offset = 0x100, .map_io = gta02_map_io, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2442_init_irq, .init_machine = gta02_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c index 79bc0830d740..af4334d6b4d5 100644 --- a/arch/arm/mach-s3c24xx/mach-h1940.c +++ b/arch/arm/mach-s3c24xx/mach-h1940.c @@ -62,7 +62,7 @@ #include <plat/pll.h> #include <plat/pm.h> #include <plat/regs-serial.h> - +#include <plat/samsung-time.h> #include "common.h" #include "h1940.h" @@ -646,6 +646,7 @@ static void __init h1940_map_io(void) s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); /* setup PM */ @@ -666,11 +667,6 @@ static void __init h1940_reserve(void) memblock_reserve(0x30081000, 0x1000); } -static void __init h1940_init_irq(void) -{ - s3c24xx_init_irq(); -} - static void __init h1940_init(void) { u32 tmp; @@ -739,8 +735,8 @@ MACHINE_START(H1940, "IPAQ-H1940") .atag_offset = 0x100, .map_io = h1940_map_io, .reserve = h1940_reserve, - .init_irq = h1940_init_irq, + .init_irq = s3c2410_init_irq, .init_machine = h1940_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c index 54e83c1f780c..a45fcd8ccf79 100644 --- a/arch/arm/mach-s3c24xx/mach-jive.c +++ b/arch/arm/mach-s3c24xx/mach-jive.c @@ -46,14 +46,15 @@ #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> -#include <plat/s3c2412.h> #include <plat/gpio-cfg.h> #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> #include <plat/pm.h> #include <linux/platform_data/usb-s3c2410_udc.h> +#include <plat/samsung-time.h> +#include "common.h" #include "s3c2412-power.h" static struct map_desc jive_iodesc[] __initdata = { @@ -506,6 +507,7 @@ static void __init jive_map_io(void) s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(jive_uartcfgs, ARRAY_SIZE(jive_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void jive_power_off(void) @@ -658,9 +660,9 @@ MACHINE_START(JIVE, "JIVE") /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ .atag_offset = 0x100, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2412_init_irq, .map_io = jive_map_io, .init_machine = jive_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2412_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c index 2865e5919f2c..a83db46320bc 100644 --- a/arch/arm/mach-s3c24xx/mach-mini2440.c +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -56,6 +56,7 @@ #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> +#include <plat/samsung-time.h> #include <sound/s3c24xx_uda134x.h> @@ -525,6 +526,7 @@ static void __init mini2440_map_io(void) s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } /* @@ -686,7 +688,7 @@ MACHINE_START(MINI2440, "MINI2440") .atag_offset = 0x100, .map_io = mini2440_map_io, .init_machine = mini2440_init, - .init_irq = s3c24xx_init_irq, - .init_time = s3c24xx_timer_init, + .init_irq = s3c2440_init_irq, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-n30.c b/arch/arm/mach-s3c24xx/mach-n30.c index d9d04b240295..2cb46c37c920 100644 --- a/arch/arm/mach-s3c24xx/mach-n30.c +++ b/arch/arm/mach-s3c24xx/mach-n30.c @@ -48,8 +48,8 @@ #include <plat/cpu.h> #include <plat/devs.h> #include <linux/platform_data/mmc-s3cmci.h> -#include <plat/s3c2410.h> #include <linux/platform_data/usb-s3c2410_udc.h> +#include <plat/samsung-time.h> #include "common.h" @@ -536,6 +536,7 @@ static void __init n30_map_io(void) n30_hwinit(); s3c24xx_init_clocks(0); s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } /* GPB3 is the line that controls the pull-up for the USB D+ line */ @@ -589,9 +590,9 @@ MACHINE_START(N30, "Acer-N30") Ben Dooks <ben-linux@fluff.org> */ .atag_offset = 0x100, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .init_machine = n30_init, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2410_init_irq, .map_io = n30_map_io, .restart = s3c2410_restart, MACHINE_END @@ -600,9 +601,9 @@ MACHINE_START(N35, "Acer-N35") /* Maintainer: Christer Weinigel <christer@weinigel.se> */ .atag_offset = 0x100, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .init_machine = n30_init, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2410_init_irq, .map_io = n30_map_io, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c index a454e2461860..01f4354206f9 100644 --- a/arch/arm/mach-s3c24xx/mach-nexcoder.c +++ b/arch/arm/mach-s3c24xx/mach-nexcoder.c @@ -41,11 +41,10 @@ #include <linux/platform_data/i2c-s3c2410.h> #include <plat/gpio-cfg.h> -#include <plat/s3c2410.h> -#include <plat/s3c244x.h> #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> +#include <plat/samsung-time.h> #include "common.h" @@ -137,6 +136,7 @@ static void __init nexcoder_map_io(void) s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); nexcoder_sensorboard_init(); } @@ -152,7 +152,7 @@ MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440") .atag_offset = 0x100, .map_io = nexcoder_map_io, .init_machine = nexcoder_init, - .init_irq = s3c24xx_init_irq, - .init_time = s3c24xx_timer_init, + .init_irq = s3c2440_init_irq, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c index ae2cbdf3e3ca..58d6fbe5bf1f 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris.c +++ b/arch/arm/mach-s3c24xx/mach-osiris.c @@ -45,6 +45,7 @@ #include <plat/devs.h> #include <plat/gpio-cfg.h> #include <plat/regs-serial.h> +#include <plat/samsung-time.h> #include <mach/hardware.h> #include <mach/regs-gpio.h> @@ -384,6 +385,7 @@ static void __init osiris_map_io(void) s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); /* check for the newer revision boards with large page nand */ @@ -424,8 +426,8 @@ MACHINE_START(OSIRIS, "Simtec-OSIRIS") /* Maintainer: Ben Dooks <ben@simtec.co.uk> */ .atag_offset = 0x100, .map_io = osiris_map_io, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2440_init_irq, .init_machine = osiris_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c index 40a47d6c6a85..7e16b0740ec1 100644 --- a/arch/arm/mach-s3c24xx/mach-otom.c +++ b/arch/arm/mach-s3c24xx/mach-otom.c @@ -33,7 +33,7 @@ #include <plat/cpu.h> #include <plat/devs.h> #include <plat/regs-serial.h> -#include <plat/s3c2410.h> +#include <plat/samsung-time.h> #include "common.h" #include "otom.h" @@ -102,6 +102,7 @@ static void __init otom11_map_io(void) s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init otom11_init(void) @@ -115,7 +116,7 @@ MACHINE_START(OTOM, "Nex Vision - Otom 1.1") .atag_offset = 0x100, .map_io = otom11_map_io, .init_machine = otom11_init, - .init_irq = s3c24xx_init_irq, - .init_time = s3c24xx_timer_init, + .init_irq = s3c2410_init_irq, + .init_time = samsung_timer_init, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c index 56175f0941b1..f8feaeadb55a 100644 --- a/arch/arm/mach-s3c24xx/mach-qt2410.c +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c @@ -55,13 +55,14 @@ #include <linux/platform_data/usb-s3c2410_udc.h> #include <linux/platform_data/i2c-s3c2410.h> -#include <plat/common-smdk.h> #include <plat/gpio-cfg.h> #include <plat/devs.h> #include <plat/cpu.h> #include <plat/pm.h> +#include <plat/samsung-time.h> #include "common.h" +#include "common-smdk.h" static struct map_desc qt2410_iodesc[] __initdata = { { 0xe0000000, __phys_to_pfn(S3C2410_CS3+0x01000000), SZ_1M, MT_DEVICE } @@ -304,6 +305,7 @@ static void __init qt2410_map_io(void) s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc)); s3c24xx_init_clocks(12*1000*1000); s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init qt2410_machine_init(void) @@ -341,8 +343,8 @@ static void __init qt2410_machine_init(void) MACHINE_START(QT2410, "QT2410") .atag_offset = 0x100, .map_io = qt2410_map_io, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2410_init_irq, .init_machine = qt2410_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c index 1f9ba2ae5288..e4d67a33ebee 100644 --- a/arch/arm/mach-s3c24xx/mach-rx1950.c +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -58,6 +58,7 @@ #include <plat/pm.h> #include <plat/regs-iic.h> #include <plat/regs-serial.h> +#include <plat/samsung-time.h> #include "common.h" #include "h1940.h" @@ -741,6 +742,7 @@ static void __init rx1950_map_io(void) s3c24xx_init_io(rx1950_iodesc, ARRAY_SIZE(rx1950_iodesc)); s3c24xx_init_clocks(16934000); s3c24xx_init_uarts(rx1950_uartcfgs, ARRAY_SIZE(rx1950_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); /* setup PM */ @@ -811,8 +813,8 @@ MACHINE_START(RX1950, "HP iPAQ RX1950") .atag_offset = 0x100, .map_io = rx1950_map_io, .reserve = rx1950_reserve, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2442_init_irq, .init_machine = rx1950_init_machine, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c index f20418a2fb1b..3bc6231d0a1f 100644 --- a/arch/arm/mach-s3c24xx/mach-rx3715.c +++ b/arch/arm/mach-s3c24xx/mach-rx3715.c @@ -49,6 +49,7 @@ #include <plat/devs.h> #include <plat/pm.h> #include <plat/regs-serial.h> +#include <plat/samsung-time.h> #include "common.h" #include "h1940.h" @@ -179,6 +180,7 @@ static void __init rx3715_map_io(void) s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc)); s3c24xx_init_clocks(16934000); s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } /* H1940 and RX3715 need to reserve this for suspend */ @@ -188,11 +190,6 @@ static void __init rx3715_reserve(void) memblock_reserve(0x30081000, 0x1000); } -static void __init rx3715_init_irq(void) -{ - s3c24xx_init_irq(); -} - static void __init rx3715_init_machine(void) { #ifdef CONFIG_PM_H1940 @@ -210,8 +207,8 @@ MACHINE_START(RX3715, "IPAQ-RX3715") .atag_offset = 0x100, .map_io = rx3715_map_io, .reserve = rx3715_reserve, - .init_irq = rx3715_init_irq, + .init_irq = s3c2440_init_irq, .init_machine = rx3715_init_machine, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2410.c b/arch/arm/mach-s3c24xx/mach-smdk2410.c index e184bfa9613a..a773789e4f38 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2410.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2410.c @@ -51,10 +51,10 @@ #include <plat/devs.h> #include <plat/cpu.h> - -#include <plat/common-smdk.h> +#include <plat/samsung-time.h> #include "common.h" +#include "common-smdk.h" static struct map_desc smdk2410_iodesc[] __initdata = { /* nothing here yet */ @@ -101,6 +101,7 @@ static void __init smdk2410_map_io(void) s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init smdk2410_init(void) @@ -115,8 +116,8 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc /* Maintainer: Jonas Dietsche */ .atag_offset = 0x100, .map_io = smdk2410_map_io, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2410_init_irq, .init_machine = smdk2410_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2413.c b/arch/arm/mach-s3c24xx/mach-smdk2413.c index 86d7847c9d45..8146e920f10d 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2413.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2413.c @@ -41,13 +41,13 @@ #include <linux/platform_data/i2c-s3c2410.h> #include <mach/fb.h> -#include <plat/s3c2410.h> -#include <plat/s3c2412.h> #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> +#include <plat/samsung-time.h> -#include <plat/common-smdk.h> +#include "common.h" +#include "common-smdk.h" static struct map_desc smdk2413_iodesc[] __initdata = { }; @@ -106,6 +106,7 @@ static void __init smdk2413_map_io(void) s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init smdk2413_machine_init(void) @@ -129,10 +130,10 @@ MACHINE_START(S3C2413, "S3C2413") .atag_offset = 0x100, .fixup = smdk2413_fixup, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2412_init_irq, .map_io = smdk2413_map_io, .init_machine = smdk2413_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2412_restart, MACHINE_END @@ -141,10 +142,10 @@ MACHINE_START(SMDK2412, "SMDK2412") .atag_offset = 0x100, .fixup = smdk2413_fixup, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2412_init_irq, .map_io = smdk2413_map_io, .init_machine = smdk2413_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2412_restart, MACHINE_END @@ -153,9 +154,9 @@ MACHINE_START(SMDK2413, "SMDK2413") .atag_offset = 0x100, .fixup = smdk2413_fixup, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2412_init_irq, .map_io = smdk2413_map_io, .init_machine = smdk2413_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2412_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c index ebb2e61f3d07..cb46847c66b4 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2416.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c @@ -42,7 +42,6 @@ #include <linux/platform_data/leds-s3c24xx.h> #include <linux/platform_data/i2c-s3c2410.h> -#include <plat/s3c2416.h> #include <plat/gpio-cfg.h> #include <plat/clock.h> #include <plat/devs.h> @@ -51,10 +50,12 @@ #include <plat/sdhci.h> #include <linux/platform_data/usb-s3c2410_udc.h> #include <linux/platform_data/s3c-hsudc.h> +#include <plat/samsung-time.h> #include <plat/fb.h> -#include <plat/common-smdk.h> +#include "common.h" +#include "common-smdk.h" static struct map_desc smdk2416_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */ @@ -221,6 +222,7 @@ static void __init smdk2416_map_io(void) s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init smdk2416_machine_init(void) @@ -253,6 +255,6 @@ MACHINE_START(SMDK2416, "SMDK2416") .init_irq = s3c2416_init_irq, .map_io = smdk2416_map_io, .init_machine = smdk2416_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2416_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2440.c b/arch/arm/mach-s3c24xx/mach-smdk2440.c index 08cc38c8a4ae..de2e5d39a847 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2440.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2440.c @@ -38,15 +38,13 @@ #include <mach/fb.h> #include <linux/platform_data/i2c-s3c2410.h> -#include <plat/s3c2410.h> -#include <plat/s3c244x.h> #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> - -#include <plat/common-smdk.h> +#include <plat/samsung-time.h> #include "common.h" +#include "common-smdk.h" static struct map_desc smdk2440_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */ @@ -163,6 +161,7 @@ static void __init smdk2440_map_io(void) s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); s3c24xx_init_clocks(16934400); s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init smdk2440_machine_init(void) @@ -178,9 +177,9 @@ MACHINE_START(S3C2440, "SMDK2440") /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ .atag_offset = 0x100, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2440_init_irq, .map_io = smdk2440_map_io, .init_machine = smdk2440_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c244x_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2443.c b/arch/arm/mach-s3c24xx/mach-smdk2443.c index fc65d74d3c73..9435c3bef18a 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2443.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2443.c @@ -38,13 +38,13 @@ #include <mach/fb.h> #include <linux/platform_data/i2c-s3c2410.h> -#include <plat/s3c2410.h> -#include <plat/s3c2443.h> #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> +#include <plat/samsung-time.h> -#include <plat/common-smdk.h> +#include "common.h" +#include "common-smdk.h" static struct map_desc smdk2443_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */ @@ -122,6 +122,7 @@ static void __init smdk2443_map_io(void) s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init smdk2443_machine_init(void) @@ -143,6 +144,6 @@ MACHINE_START(SMDK2443, "SMDK2443") .init_irq = s3c2443_init_irq, .map_io = smdk2443_map_io, .init_machine = smdk2443_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2443_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c index 24b3d79e7b2c..7fad8f055cab 100644 --- a/arch/arm/mach-s3c24xx/mach-tct_hammer.c +++ b/arch/arm/mach-s3c24xx/mach-tct_hammer.c @@ -53,6 +53,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/map.h> #include <linux/mtd/physmap.h> +#include <plat/samsung-time.h> #include "common.h" @@ -136,6 +137,7 @@ static void __init tct_hammer_map_io(void) s3c24xx_init_io(tct_hammer_iodesc, ARRAY_SIZE(tct_hammer_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(tct_hammer_uartcfgs, ARRAY_SIZE(tct_hammer_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init tct_hammer_init(void) @@ -147,8 +149,8 @@ static void __init tct_hammer_init(void) MACHINE_START(TCT_HAMMER, "TCT_HAMMER") .atag_offset = 0x100, .map_io = tct_hammer_map_io, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2410_init_irq, .init_machine = tct_hammer_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c index ec42d1e4e465..42e7187fed60 100644 --- a/arch/arm/mach-s3c24xx/mach-vr1000.c +++ b/arch/arm/mach-s3c24xx/mach-vr1000.c @@ -45,6 +45,7 @@ #include <plat/cpu.h> #include <plat/devs.h> #include <plat/regs-serial.h> +#include <plat/samsung-time.h> #include "bast.h" #include "common.h" @@ -332,6 +333,7 @@ static void __init vr1000_map_io(void) s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init vr1000_init(void) @@ -353,7 +355,7 @@ MACHINE_START(VR1000, "Thorcom-VR1000") .atag_offset = 0x100, .map_io = vr1000_map_io, .init_machine = vr1000_init, - .init_irq = s3c24xx_init_irq, - .init_time = s3c24xx_timer_init, + .init_irq = s3c2410_init_irq, + .init_time = samsung_timer_init, .restart = s3c2410_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c index 3e2bfddc9df1..b66588428ec9 100644 --- a/arch/arm/mach-s3c24xx/mach-vstms.c +++ b/arch/arm/mach-s3c24xx/mach-vstms.c @@ -41,12 +41,12 @@ #include <linux/platform_data/i2c-s3c2410.h> #include <linux/platform_data/mtd-nand-s3c2410.h> -#include <plat/s3c2410.h> -#include <plat/s3c2412.h> #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> +#include <plat/samsung-time.h> +#include "common.h" static struct map_desc vstms_iodesc[] __initdata = { }; @@ -143,6 +143,7 @@ static void __init vstms_map_io(void) s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init vstms_init(void) @@ -157,9 +158,9 @@ MACHINE_START(VSTMS, "VSTMS") .atag_offset = 0x100, .fixup = vstms_fixup, - .init_irq = s3c24xx_init_irq, + .init_irq = s3c2412_init_irq, .init_machine = vstms_init, .map_io = vstms_map_io, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c2412_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/pm-s3c2412.c b/arch/arm/mach-s3c24xx/pm-s3c2412.c index 668a78a8b195..d75f95e487ee 100644 --- a/arch/arm/mach-s3c24xx/pm-s3c2412.c +++ b/arch/arm/mach-s3c24xx/pm-s3c2412.c @@ -29,7 +29,7 @@ #include <plat/cpu.h> #include <plat/pm.h> -#include <plat/s3c2412.h> +#include <plat/wakeup-mask.h> #include "regs-dsc.h" #include "s3c2412-power.h" @@ -52,8 +52,15 @@ static int s3c2412_cpu_suspend(unsigned long arg) return 1; /* Aborting suspend */ } +/* mapping of interrupts to parts of the wakeup mask */ +static struct samsung_wakeup_mask wake_irqs[] = { + { .irq = IRQ_RTC, .bit = S3C2412_PWRCFG_RTC_MASKIRQ, }, +}; + static void s3c2412_pm_prepare(void) { + samsung_sync_wakemask(S3C2412_PWRCFG, + wake_irqs, ARRAY_SIZE(wake_irqs)); } static int s3c2412_pm_add(struct device *dev, struct subsys_interface *sif) diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c index 9ebef95da721..d850ea5adac2 100644 --- a/arch/arm/mach-s3c24xx/s3c2410.c +++ b/arch/arm/mach-s3c24xx/s3c2410.c @@ -37,7 +37,6 @@ #include <mach/regs-clock.h> #include <plat/regs-serial.h> -#include <plat/s3c2410.h> #include <plat/cpu.h> #include <plat/devs.h> #include <plat/clock.h> diff --git a/arch/arm/mach-s3c24xx/s3c2412.c b/arch/arm/mach-s3c24xx/s3c2412.c index 0d592159a5c3..0f864d4c97de 100644 --- a/arch/arm/mach-s3c24xx/s3c2412.c +++ b/arch/arm/mach-s3c24xx/s3c2412.c @@ -44,7 +44,6 @@ #include <plat/pm.h> #include <plat/regs-serial.h> #include <plat/regs-spi.h> -#include <plat/s3c2412.h> #include "common.h" #include "regs-dsc.h" diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c index e30476db0295..b9c5d382dafb 100644 --- a/arch/arm/mach-s3c24xx/s3c2416.c +++ b/arch/arm/mach-s3c24xx/s3c2416.c @@ -50,7 +50,6 @@ #include <plat/gpio-core.h> #include <plat/gpio-cfg.h> #include <plat/gpio-cfg-helpers.h> -#include <plat/s3c2416.h> #include <plat/devs.h> #include <plat/cpu.h> #include <plat/sdhci.h> diff --git a/arch/arm/mach-s3c24xx/s3c2440.c b/arch/arm/mach-s3c24xx/s3c2440.c index 559e394e8989..5f9d6569475d 100644 --- a/arch/arm/mach-s3c24xx/s3c2440.c +++ b/arch/arm/mach-s3c24xx/s3c2440.c @@ -33,7 +33,6 @@ #include <plat/devs.h> #include <plat/cpu.h> -#include <plat/s3c244x.h> #include <plat/pm.h> #include <plat/gpio-core.h> diff --git a/arch/arm/mach-s3c24xx/s3c2442.c b/arch/arm/mach-s3c24xx/s3c2442.c index f732826c2359..6819961f6b19 100644 --- a/arch/arm/mach-s3c24xx/s3c2442.c +++ b/arch/arm/mach-s3c24xx/s3c2442.c @@ -44,7 +44,6 @@ #include <plat/clock.h> #include <plat/cpu.h> -#include <plat/s3c244x.h> #include <plat/pm.h> #include <plat/gpio-core.h> diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c index 165b6a6b3daa..8328cd65bf3d 100644 --- a/arch/arm/mach-s3c24xx/s3c2443.c +++ b/arch/arm/mach-s3c24xx/s3c2443.c @@ -36,7 +36,6 @@ #include <plat/gpio-core.h> #include <plat/gpio-cfg.h> #include <plat/gpio-cfg-helpers.h> -#include <plat/s3c2443.h> #include <plat/devs.h> #include <plat/cpu.h> #include <plat/fb-core.h> diff --git a/arch/arm/mach-s3c24xx/s3c244x.c b/arch/arm/mach-s3c24xx/s3c244x.c index ad2671baa910..2a35edb67354 100644 --- a/arch/arm/mach-s3c24xx/s3c244x.c +++ b/arch/arm/mach-s3c24xx/s3c244x.c @@ -37,8 +37,6 @@ #include <plat/regs-serial.h> #include <mach/regs-gpio.h> -#include <plat/s3c2410.h> -#include <plat/s3c244x.h> #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 131c86284711..283cb77d4721 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -17,11 +17,13 @@ config PLAT_S3C64XX # Configuration options for the S3C6410 CPU config CPU_S3C6400 + select SAMSUNG_HRT bool help Enable S3C6400 CPU support config CPU_S3C6410 + select SAMSUNG_HRT bool help Enable S3C6410 CPU support diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c index 728eef3296b2..35e3f54574ef 100644 --- a/arch/arm/mach-s3c64xx/mach-anw6410.c +++ b/arch/arm/mach-s3c64xx/mach-anw6410.c @@ -49,6 +49,7 @@ #include <plat/devs.h> #include <plat/cpu.h> #include <mach/regs-gpio.h> +#include <plat/samsung-time.h> #include "common.h" #include "regs-modem.h" @@ -208,6 +209,7 @@ static void __init anw6410_map_io(void) s3c64xx_init_io(anw6410_iodesc, ARRAY_SIZE(anw6410_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(anw6410_uartcfgs, ARRAY_SIZE(anw6410_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); anw6410_lcd_mode_set(); } @@ -232,6 +234,6 @@ MACHINE_START(ANW6410, "A&W6410") .map_io = anw6410_map_io, .init_machine = anw6410_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 1acf02bace57..8ad88ace795a 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -64,6 +64,7 @@ #include <plat/adc.h> #include <linux/platform_data/i2c-s3c2410.h> #include <plat/pm.h> +#include <plat/samsung-time.h> #include "common.h" #include "crag6410.h" @@ -744,6 +745,7 @@ static void __init crag6410_map_io(void) s3c64xx_init_io(NULL, 0); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(crag6410_uartcfgs, ARRAY_SIZE(crag6410_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); /* LCD type and Bypass set by bootloader */ } @@ -868,6 +870,6 @@ MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410") .map_io = crag6410_map_io, .init_machine = crag6410_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c index 7212eb9cfeb9..5b7f357d8c22 100644 --- a/arch/arm/mach-s3c64xx/mach-hmt.c +++ b/arch/arm/mach-s3c64xx/mach-hmt.c @@ -41,6 +41,7 @@ #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> +#include <plat/samsung-time.h> #include "common.h" @@ -248,6 +249,7 @@ static void __init hmt_map_io(void) s3c64xx_init_io(hmt_iodesc, ARRAY_SIZE(hmt_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(hmt_uartcfgs, ARRAY_SIZE(hmt_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init hmt_machine_init(void) @@ -275,6 +277,6 @@ MACHINE_START(HMT, "Airgoo-HMT") .map_io = hmt_map_io, .init_machine = hmt_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c index 4b41fcdaa7b6..fc043e3ecdf8 100644 --- a/arch/arm/mach-s3c64xx/mach-mini6410.c +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c @@ -41,6 +41,7 @@ #include <video/platform_lcd.h> #include <video/samsung_fimd.h> +#include <plat/samsung-time.h> #include "common.h" #include "regs-modem.h" @@ -232,6 +233,7 @@ static void __init mini6410_map_io(void) s3c64xx_init_io(NULL, 0); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(mini6410_uartcfgs, ARRAY_SIZE(mini6410_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); /* set the LCD type */ tmp = __raw_readl(S3C64XX_SPCON); @@ -354,6 +356,6 @@ MACHINE_START(MINI6410, "MINI6410") .map_io = mini6410_map_io, .init_machine = mini6410_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-ncp.c b/arch/arm/mach-s3c64xx/mach-ncp.c index 8d3cedd995ff..7e2c3908f1f8 100644 --- a/arch/arm/mach-s3c64xx/mach-ncp.c +++ b/arch/arm/mach-s3c64xx/mach-ncp.c @@ -43,6 +43,7 @@ #include <plat/clock.h> #include <plat/devs.h> #include <plat/cpu.h> +#include <plat/samsung-time.h> #include "common.h" @@ -87,6 +88,7 @@ static void __init ncp_map_io(void) s3c64xx_init_io(ncp_iodesc, ARRAY_SIZE(ncp_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(ncp_uartcfgs, ARRAY_SIZE(ncp_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init ncp_machine_init(void) @@ -103,6 +105,6 @@ MACHINE_START(NCP, "NCP") .map_io = ncp_map_io, .init_machine = ncp_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index fa12bd21ad82..8bed37b3d5ac 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c @@ -42,6 +42,7 @@ #include <video/platform_lcd.h> #include <video/samsung_fimd.h> +#include <plat/samsung-time.h> #include "common.h" #include "regs-modem.h" @@ -211,6 +212,7 @@ static void __init real6410_map_io(void) s3c64xx_init_io(NULL, 0); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(real6410_uartcfgs, ARRAY_SIZE(real6410_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); /* set the LCD type */ tmp = __raw_readl(S3C64XX_SPCON); @@ -333,6 +335,6 @@ MACHINE_START(REAL6410, "REAL6410") .map_io = real6410_map_io, .init_machine = real6410_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c index fc3e9b32e26f..58ac99041274 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq.c +++ b/arch/arm/mach-s3c64xx/mach-smartq.c @@ -38,6 +38,7 @@ #include <linux/platform_data/touchscreen-s3c2410.h> #include <video/platform_lcd.h> +#include <plat/samsung-time.h> #include "common.h" #include "regs-modem.h" @@ -378,6 +379,7 @@ void __init smartq_map_io(void) s3c64xx_init_io(smartq_iodesc, ARRAY_SIZE(smartq_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smartq_uartcfgs, ARRAY_SIZE(smartq_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); smartq_lcd_mode_set(); } diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c index ca2afcfce573..8aca5daf3d05 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq5.c +++ b/arch/arm/mach-s3c64xx/mach-smartq5.c @@ -28,6 +28,7 @@ #include <plat/devs.h> #include <plat/fb.h> #include <plat/gpio-cfg.h> +#include <plat/samsung-time.h> #include "common.h" #include "mach-smartq.h" @@ -155,6 +156,6 @@ MACHINE_START(SMARTQ5, "SmartQ 5") .map_io = smartq_map_io, .init_machine = smartq5_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c index 37bb0c632a5e..a052e107c0b4 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq7.c +++ b/arch/arm/mach-s3c64xx/mach-smartq7.c @@ -28,6 +28,7 @@ #include <plat/devs.h> #include <plat/fb.h> #include <plat/gpio-cfg.h> +#include <plat/samsung-time.h> #include "common.h" #include "mach-smartq.h" @@ -171,6 +172,6 @@ MACHINE_START(SMARTQ7, "SmartQ 7") .map_io = smartq_map_io, .init_machine = smartq7_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smdk6400.c b/arch/arm/mach-s3c64xx/mach-smdk6400.c index a392869c8342..d70c0843aea2 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6400.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6400.c @@ -35,6 +35,7 @@ #include <plat/devs.h> #include <plat/cpu.h> #include <linux/platform_data/i2c-s3c2410.h> +#include <plat/samsung-time.h> #include "common.h" @@ -66,6 +67,7 @@ static void __init smdk6400_map_io(void) s3c64xx_init_io(smdk6400_iodesc, ARRAY_SIZE(smdk6400_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk6400_uartcfgs, ARRAY_SIZE(smdk6400_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static struct platform_device *smdk6400_devices[] __initdata = { @@ -92,6 +94,6 @@ MACHINE_START(SMDK6400, "SMDK6400") .map_io = smdk6400_map_io, .init_machine = smdk6400_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index ba7544e2d04d..bd3295a19ad7 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -69,6 +69,7 @@ #include <linux/platform_data/touchscreen-s3c2410.h> #include <plat/keypad.h> #include <plat/backlight.h> +#include <plat/samsung-time.h> #include "common.h" #include "regs-modem.h" @@ -634,6 +635,7 @@ static void __init smdk6410_map_io(void) s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk6410_uartcfgs, ARRAY_SIZE(smdk6410_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); /* set the LCD type */ @@ -702,6 +704,6 @@ MACHINE_START(SMDK6410, "SMDK6410") .map_io = smdk6410_map_io, .init_machine = smdk6410_machine_init, .init_late = s3c64xx_init_late, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig index e8742cb7ddd9..5a707bdb9ea0 100644 --- a/arch/arm/mach-s5p64x0/Kconfig +++ b/arch/arm/mach-s5p64x0/Kconfig @@ -9,16 +9,16 @@ if ARCH_S5P64X0 config CPU_S5P6440 bool - select S5P_HRT select S5P_SLEEP if PM select SAMSUNG_DMADEV + select SAMSUNG_HRT select SAMSUNG_WAKEMASK if PM help Enable S5P6440 CPU support config CPU_S5P6450 bool - select S5P_HRT + select SAMSUNG_HRT select S5P_SLEEP if PM select SAMSUNG_DMADEV select SAMSUNG_WAKEMASK if PM diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c index e23723a5a214..73f71a698a34 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6440.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c @@ -48,7 +48,7 @@ #include <plat/pll.h> #include <plat/adc.h> #include <linux/platform_data/touchscreen-s3c2410.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> #include <plat/backlight.h> #include <plat/fb.h> #include <plat/sdhci.h> @@ -229,7 +229,7 @@ static void __init smdk6440_map_io(void) s5p64x0_init_io(NULL, 0); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk6440_uartcfgs, ARRAY_SIZE(smdk6440_uartcfgs)); - s5p_set_timer_source(S5P_PWM3, S5P_PWM4); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void s5p6440_set_lcd_interface(void) @@ -273,6 +273,6 @@ MACHINE_START(SMDK6440, "SMDK6440") .init_irq = s5p6440_init_irq, .map_io = smdk6440_map_io, .init_machine = smdk6440_machine_init, - .init_time = s5p_timer_init, + .init_time = samsung_timer_init, .restart = s5p64x0_restart, MACHINE_END diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c index ca10963a959e..18303e12019f 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6450.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c @@ -48,7 +48,7 @@ #include <plat/pll.h> #include <plat/adc.h> #include <linux/platform_data/touchscreen-s3c2410.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> #include <plat/backlight.h> #include <plat/fb.h> #include <plat/sdhci.h> @@ -248,7 +248,7 @@ static void __init smdk6450_map_io(void) s5p64x0_init_io(NULL, 0); s3c24xx_init_clocks(19200000); s3c24xx_init_uarts(smdk6450_uartcfgs, ARRAY_SIZE(smdk6450_uartcfgs)); - s5p_set_timer_source(S5P_PWM3, S5P_PWM4); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void s5p6450_set_lcd_interface(void) @@ -292,6 +292,6 @@ MACHINE_START(SMDK6450, "SMDK6450") .init_irq = s5p6450_init_irq, .map_io = smdk6450_map_io, .init_machine = smdk6450_machine_init, - .init_time = s5p_timer_init, + .init_time = samsung_timer_init, .restart = s5p64x0_restart, MACHINE_END diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig index 15170be97a74..2f456a4533ba 100644 --- a/arch/arm/mach-s5pc100/Kconfig +++ b/arch/arm/mach-s5pc100/Kconfig @@ -11,6 +11,7 @@ config CPU_S5PC100 bool select S5P_EXT_INT select SAMSUNG_DMADEV + select SAMSUNG_HRT help Enable S5PC100 CPU support diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c index 185a19583898..8c880f76f274 100644 --- a/arch/arm/mach-s5pc100/mach-smdkc100.c +++ b/arch/arm/mach-s5pc100/mach-smdkc100.c @@ -51,6 +51,7 @@ #include <linux/platform_data/touchscreen-s3c2410.h> #include <linux/platform_data/asoc-s3c.h> #include <plat/backlight.h> +#include <plat/samsung-time.h> #include "common.h" @@ -221,6 +222,7 @@ static void __init smdkc100_map_io(void) s5pc100_init_io(NULL, 0); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdkc100_uartcfgs, ARRAY_SIZE(smdkc100_uartcfgs)); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init smdkc100_machine_init(void) @@ -255,6 +257,6 @@ MACHINE_START(SMDKC100, "SMDKC100") .init_irq = s5pc100_init_irq, .map_io = smdkc100_map_io, .init_machine = smdkc100_machine_init, - .init_time = s3c24xx_timer_init, + .init_time = samsung_timer_init, .restart = s5pc100_restart, MACHINE_END diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig index 92ad72f0ef98..0963283a7c5d 100644 --- a/arch/arm/mach-s5pv210/Kconfig +++ b/arch/arm/mach-s5pv210/Kconfig @@ -12,10 +12,10 @@ if ARCH_S5PV210 config CPU_S5PV210 bool select S5P_EXT_INT - select S5P_HRT select S5P_PM if PM select S5P_SLEEP if PM select SAMSUNG_DMADEV + select SAMSUNG_HRT help Enable S5PV210 CPU support diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c index 11900a8e88a3..ed2b85485b9d 100644 --- a/arch/arm/mach-s5pv210/mach-aquila.c +++ b/arch/arm/mach-s5pv210/mach-aquila.c @@ -38,7 +38,7 @@ #include <plat/fb.h> #include <plat/fimc-core.h> #include <plat/sdhci.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> #include "common.h" @@ -651,7 +651,7 @@ static void __init aquila_map_io(void) s5pv210_init_io(NULL, 0); s3c24xx_init_clocks(24000000); s3c24xx_init_uarts(aquila_uartcfgs, ARRAY_SIZE(aquila_uartcfgs)); - s5p_set_timer_source(S5P_PWM3, S5P_PWM4); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init aquila_machine_init(void) @@ -686,6 +686,6 @@ MACHINE_START(AQUILA, "Aquila") .init_irq = s5pv210_init_irq, .map_io = aquila_map_io, .init_machine = aquila_machine_init, - .init_time = s5p_timer_init, + .init_time = samsung_timer_init, .restart = s5pv210_restart, MACHINE_END diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c index e373de44a8b6..30b24ad84f49 100644 --- a/arch/arm/mach-s5pv210/mach-goni.c +++ b/arch/arm/mach-s5pv210/mach-goni.c @@ -47,7 +47,7 @@ #include <plat/keypad.h> #include <plat/sdhci.h> #include <plat/clock.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> #include <plat/mfc.h> #include <plat/camport.h> @@ -908,7 +908,7 @@ static void __init goni_map_io(void) s5pv210_init_io(NULL, 0); s3c24xx_init_clocks(clk_xusbxti.rate); s3c24xx_init_uarts(goni_uartcfgs, ARRAY_SIZE(goni_uartcfgs)); - s5p_set_timer_source(S5P_PWM3, S5P_PWM4); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init goni_reserve(void) @@ -973,7 +973,7 @@ MACHINE_START(GONI, "GONI") .init_irq = s5pv210_init_irq, .map_io = goni_map_io, .init_machine = goni_machine_init, - .init_time = s5p_timer_init, + .init_time = samsung_timer_init, .reserve = &goni_reserve, .restart = s5pv210_restart, MACHINE_END diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c index 28bd0248a3e2..7c0ed07a78a3 100644 --- a/arch/arm/mach-s5pv210/mach-smdkc110.c +++ b/arch/arm/mach-s5pv210/mach-smdkc110.c @@ -29,7 +29,7 @@ #include <linux/platform_data/ata-samsung_cf.h> #include <linux/platform_data/i2c-s3c2410.h> #include <plat/pm.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> #include <plat/mfc.h> #include "common.h" @@ -120,7 +120,7 @@ static void __init smdkc110_map_io(void) s5pv210_init_io(NULL, 0); s3c24xx_init_clocks(24000000); s3c24xx_init_uarts(smdkv210_uartcfgs, ARRAY_SIZE(smdkv210_uartcfgs)); - s5p_set_timer_source(S5P_PWM3, S5P_PWM4); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init smdkc110_reserve(void) @@ -153,7 +153,7 @@ MACHINE_START(SMDKC110, "SMDKC110") .init_irq = s5pv210_init_irq, .map_io = smdkc110_map_io, .init_machine = smdkc110_machine_init, - .init_time = s5p_timer_init, + .init_time = samsung_timer_init, .restart = s5pv210_restart, .reserve = &smdkc110_reserve, MACHINE_END diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index 3c73f36869bb..d50b6f124465 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -44,7 +44,7 @@ #include <plat/keypad.h> #include <plat/pm.h> #include <plat/fb.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> #include <plat/backlight.h> #include <plat/mfc.h> #include <plat/clock.h> @@ -285,7 +285,7 @@ static void __init smdkv210_map_io(void) s5pv210_init_io(NULL, 0); s3c24xx_init_clocks(clk_xusbxti.rate); s3c24xx_init_uarts(smdkv210_uartcfgs, ARRAY_SIZE(smdkv210_uartcfgs)); - s5p_set_timer_source(S5P_PWM2, S5P_PWM4); + samsung_set_timer_source(SAMSUNG_PWM2, SAMSUNG_PWM4); } static void __init smdkv210_reserve(void) @@ -329,7 +329,7 @@ MACHINE_START(SMDKV210, "SMDKV210") .init_irq = s5pv210_init_irq, .map_io = smdkv210_map_io, .init_machine = smdkv210_machine_init, - .init_time = s5p_timer_init, + .init_time = samsung_timer_init, .restart = s5pv210_restart, .reserve = &smdkv210_reserve, MACHINE_END diff --git a/arch/arm/mach-s5pv210/mach-torbreck.c b/arch/arm/mach-s5pv210/mach-torbreck.c index 2d4c5531819c..579afe89842a 100644 --- a/arch/arm/mach-s5pv210/mach-torbreck.c +++ b/arch/arm/mach-s5pv210/mach-torbreck.c @@ -26,7 +26,7 @@ #include <plat/devs.h> #include <plat/cpu.h> #include <linux/platform_data/i2c-s3c2410.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> #include "common.h" @@ -106,7 +106,7 @@ static void __init torbreck_map_io(void) s5pv210_init_io(NULL, 0); s3c24xx_init_clocks(24000000); s3c24xx_init_uarts(torbreck_uartcfgs, ARRAY_SIZE(torbreck_uartcfgs)); - s5p_set_timer_source(S5P_PWM3, S5P_PWM4); + samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); } static void __init torbreck_machine_init(void) @@ -130,6 +130,6 @@ MACHINE_START(TORBRECK, "TORBRECK") .init_irq = s5pv210_init_irq, .map_io = torbreck_map_io, .init_machine = torbreck_machine_init, - .init_time = s5p_timer_init, + .init_time = samsung_timer_init, .restart = s5pv210_restart, MACHINE_END diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 9255546e7bf6..75d413c004b6 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -16,6 +16,7 @@ config ARCH_SH73A0 select CPU_V7 select I2C select SH_CLK_CPG + select RENESAS_INTC_IRQPIN config ARCH_R8A7740 bool "R-Mobile A1 (R8A77400)" @@ -31,6 +32,7 @@ config ARCH_R8A7779 select SH_CLK_CPG select USB_ARCH_HAS_EHCI select USB_ARCH_HAS_OHCI + select RENESAS_INTC_IRQPIN config ARCH_EMEV2 bool "Emma Mobile EV2" diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index e1fac57514b9..b646ff4d742a 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -14,10 +14,9 @@ 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 headsmp-sh73a0.o -smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o -smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o +smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o headsmp-scu.o +smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o headsmp-scu.o +smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o headsmp-scu.o # IRQ objects obj-$(CONFIG_ARCH_SH7372) += entry-intc.o diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index 7f3a6b7e7b7c..d34d12ae496b 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -81,7 +81,7 @@ static struct resource smsc9221_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = intcs_evt2irq(0x260), /* IRQ3 */ + .start = irq_pin(3), /* IRQ3 */ .flags = IORESOURCE_IRQ, }, }; @@ -115,7 +115,7 @@ static struct resource usb_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = intcs_evt2irq(0x220), /* IRQ1 */ + .start = irq_pin(1), /* IRQ1 */ .flags = IORESOURCE_IRQ, }, }; @@ -138,7 +138,7 @@ struct usbhs_private { struct renesas_usbhs_platform_info info; }; -#define IRQ15 intcs_evt2irq(0x03e0) +#define IRQ15 irq_pin(15) #define USB_PHY_MODE (1 << 4) #define USB_PHY_INT_EN ((1 << 3) | (1 << 2)) #define USB_PHY_ON (1 << 1) @@ -563,25 +563,25 @@ static struct i2c_board_info i2c0_devices[] = { }, { I2C_BOARD_INFO("ak8975", 0x0c), - .irq = intcs_evt2irq(0x3380), /* IRQ28 */ + .irq = irq_pin(28), /* IRQ28 */ }, { I2C_BOARD_INFO("adxl34x", 0x1d), - .irq = intcs_evt2irq(0x3340), /* IRQ26 */ + .irq = irq_pin(26), /* IRQ26 */ }, }; static struct i2c_board_info i2c1_devices[] = { { I2C_BOARD_INFO("st1232-ts", 0x55), - .irq = intcs_evt2irq(0x300), /* IRQ8 */ + .irq = irq_pin(8), /* IRQ8 */ }, }; static struct i2c_board_info i2c3_devices[] = { { I2C_BOARD_INFO("pcf8575", 0x20), - .irq = intcs_evt2irq(0x3260), /* IRQ19 */ + .irq = irq_pin(19), /* IRQ19 */ .platform_data = &pcf8575_pdata, }, }; diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c index 19ce885a3b43..1feb9a2286a8 100644 --- a/arch/arm/mach-shmobile/clock-r8a7740.c +++ b/arch/arm/mach-shmobile/clock-r8a7740.c @@ -593,29 +593,42 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[MSTP128]), CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), + CLKDEV_DEV_ID("e6c80000.sci", &mstp_clks[MSTP200]), CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), + CLKDEV_DEV_ID("e6c70000.sci", &mstp_clks[MSTP201]), CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), + CLKDEV_DEV_ID("e6c60000.sci", &mstp_clks[MSTP202]), CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), + CLKDEV_DEV_ID("e6c50000.sci", &mstp_clks[MSTP203]), CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), + CLKDEV_DEV_ID("e6c40000.sci", &mstp_clks[MSTP204]), CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), + CLKDEV_DEV_ID("e6c30000.sci", &mstp_clks[MSTP206]), CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), + CLKDEV_DEV_ID("e6cb0000.sci", &mstp_clks[MSTP207]), CLKDEV_DEV_ID("sh-dma-engine.3", &mstp_clks[MSTP214]), CLKDEV_DEV_ID("sh-dma-engine.2", &mstp_clks[MSTP216]), CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP222]), + CLKDEV_DEV_ID("e6cd0000.sci", &mstp_clks[MSTP222]), CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP230]), + CLKDEV_DEV_ID("e6cc0000.sci", &mstp_clks[MSTP230]), CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP320]), CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), + CLKDEV_DEV_ID("e6850000.sdhi", &mstp_clks[MSTP314]), CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), + CLKDEV_DEV_ID("e6860000.sdhi", &mstp_clks[MSTP313]), CLKDEV_DEV_ID("sh_mmcif", &mstp_clks[MSTP312]), + CLKDEV_DEV_ID("e6bd0000.mmcif", &mstp_clks[MSTP312]), CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP309]), CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), + CLKDEV_DEV_ID("e6870000.sdhi", &mstp_clks[MSTP415]), /* ICK */ CLKDEV_ICK_ID("host", "renesas_usbhs", &mstp_clks[MSTP416]), diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index 1db36537255c..d9edeaf66007 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -87,7 +87,8 @@ static struct clk div4_clks[DIV4_NR] = { }; enum { MSTP323, MSTP322, MSTP321, MSTP320, - MSTP101, MSTP100, + MSTP115, + MSTP103, MSTP101, MSTP100, MSTP030, MSTP029, MSTP028, MSTP027, MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021, MSTP016, MSTP015, MSTP014, @@ -99,6 +100,8 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP322] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 22, 0), /* SDHI1 */ [MSTP321] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 21, 0), /* SDHI2 */ [MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 20, 0), /* SDHI3 */ + [MSTP115] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 15, 0), /* SATA */ + [MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_S], MSTPCR1, 3, 0), /* DU */ [MSTP101] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 1, 0), /* USB2 */ [MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 0, 0), /* USB0/1 */ [MSTP030] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 30, 0), /* I2C0 */ @@ -156,6 +159,8 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]), /* MSTP32 clocks */ + CLKDEV_DEV_ID("sata_rcar", &mstp_clks[MSTP115]), /* SATA */ + CLKDEV_DEV_ID("fc600000.sata", &mstp_clks[MSTP115]), /* SATA w/DT */ CLKDEV_DEV_ID("ehci-platform.1", &mstp_clks[MSTP101]), /* USB EHCI port2 */ CLKDEV_DEV_ID("ohci-platform.1", &mstp_clks[MSTP101]), /* USB OHCI port2 */ CLKDEV_DEV_ID("ehci-platform.0", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */ @@ -180,6 +185,7 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP322]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP321]), /* SDHI2 */ CLKDEV_DEV_ID("sh_mobile_sdhi.3", &mstp_clks[MSTP320]), /* SDHI3 */ + CLKDEV_DEV_ID("rcar-du.0", &mstp_clks[MSTP103]), /* DU */ }; void __init r8a7779_clock_init(void) diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index afa5423a0f93..71843dd39e16 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -265,12 +265,12 @@ enum { DIV4_I, DIV4_ZG, DIV4_M3, DIV4_B, DIV4_M1, DIV4_M2, static struct clk div4_clks[DIV4_NR] = { [DIV4_I] = DIV4(FRQCRA, 20, 0xdff, CLK_ENABLE_ON_INIT), - [DIV4_ZG] = DIV4(FRQCRA, 16, 0xd7f, CLK_ENABLE_ON_INIT), + [DIV4_ZG] = SH_CLK_DIV4(&pll0_clk, 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_Z] = SH_CLK_DIV4(&pll0_clk, 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), @@ -581,10 +581,13 @@ static struct clk_lookup lookups[] = { 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("ee100000.sdhi", &mstp_clks[MSTP314]), /* SDHI0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ + CLKDEV_DEV_ID("ee120000.sdhi", &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("ee140000.sdhi", &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 */ diff --git a/arch/arm/mach-shmobile/headsmp-sh73a0.S b/arch/arm/mach-shmobile/headsmp-scu.S index bec4c0d9b713..7d113f898e7f 100644 --- a/arch/arm/mach-shmobile/headsmp-sh73a0.S +++ b/arch/arm/mach-shmobile/headsmp-scu.S @@ -1,5 +1,5 @@ /* - * SMP support for SoC sh73a0 + * Shared SCU setup for mach-shmobile * * Copyright (C) 2012 Bastian Hecht * @@ -35,11 +35,12 @@ * the physical address as the MMU is still turned off. */ .align 12 -ENTRY(sh73a0_secondary_vector) +ENTRY(shmobile_secondary_vector_scu) 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 r1, 2f + ldr r1, [r1] @ 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) @@ -47,4 +48,10 @@ ENTRY(sh73a0_secondary_vector) ldr pc, 1f 1: .long shmobile_invalidate_start - PAGE_OFFSET + PLAT_PHYS_OFFSET -ENDPROC(sh73a0_secondary_vector) +2: .long shmobile_scu_base - PAGE_OFFSET + PLAT_PHYS_OFFSET +ENDPROC(shmobile_secondary_vector_scu) + + .text + .globl shmobile_scu_base +shmobile_scu_base: + .space 4 diff --git a/arch/arm/mach-shmobile/hotplug.c b/arch/arm/mach-shmobile/hotplug.c deleted file mode 100644 index a1524e3367b0..000000000000 --- a/arch/arm/mach-shmobile/hotplug.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SMP support for R-Mobile / SH-Mobile - * - * Copyright (C) 2010 Magnus Damm - * - * Based on realview, Copyright (C) 2002 ARM Ltd, 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 version 2 as - * published by the Free Software Foundation. - */ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/smp.h> -#include <linux/cpumask.h> -#include <linux/delay.h> -#include <linux/of.h> -#include <mach/common.h> -#include <mach/r8a7779.h> -#include <mach/emev2.h> -#include <asm/cacheflush.h> -#include <asm/mach-types.h> - -static cpumask_t dead_cpus; - -void shmobile_cpu_die(unsigned int cpu) -{ - /* hardware shutdown code running on the CPU that is being offlined */ - flush_cache_all(); - dsb(); - - /* notify platform_cpu_kill() that hardware shutdown is finished */ - cpumask_set_cpu(cpu, &dead_cpus); - - /* wait for SoC code in platform_cpu_kill() to shut off CPU core - * power. CPU bring up starts from the reset vector. - */ - while (1) { - /* - * here's the WFI - */ - asm(".word 0xe320f003\n" - : - : - : "memory", "cc"); - } -} - -int shmobile_cpu_disable(unsigned int cpu) -{ - cpumask_clear_cpu(cpu, &dead_cpus); - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - 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 e48606d8a2be..03f73def2fc6 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -8,6 +8,7 @@ extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz, struct twd_local_timer; extern void shmobile_setup_console(void); extern void shmobile_secondary_vector(void); +extern void shmobile_secondary_vector_scu(void); struct clk; extern int shmobile_clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); @@ -33,23 +34,23 @@ extern int sh7372_do_idle_sysc(unsigned long sleep_mode); extern struct clk sh7372_extal1_clk; extern struct clk sh7372_extal2_clk; +extern void sh73a0_init_delay(void); 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; extern struct clk sh73a0_extalr_clk; +extern void r8a7740_meram_workaround(void); extern void r8a7740_init_irq(void); extern void r8a7740_map_io(void); extern void r8a7740_add_early_devices(void); @@ -58,16 +59,18 @@ extern void r8a7740_clock_init(u8 md_ck); extern void r8a7740_pinmux_init(void); extern void r8a7740_pm_init(void); +extern void r8a7779_init_delay(void); extern void r8a7779_init_irq(void); +extern void r8a7779_init_irq_extpin(int irlm); +extern void r8a7779_init_irq_dt(void); extern void r8a7779_map_io(void); extern void r8a7779_earlytimer_init(void); extern void r8a7779_add_early_devices(void); extern void r8a7779_add_standard_devices(void); +extern void r8a7779_add_standard_devices_dt(void); extern void r8a7779_clock_init(void); extern void r8a7779_pinmux_init(void); extern void r8a7779_pm_init(void); -extern void r8a7740_meram_workaround(void); - extern void r8a7779_register_twd(void); #ifdef CONFIG_SUSPEND @@ -82,16 +85,7 @@ int shmobile_cpuidle_init(void); static inline int shmobile_cpuidle_init(void) { return 0; } #endif -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); -#else -static inline int shmobile_cpu_is_dead(unsigned int cpu) { return 1; } -#endif - +extern void __iomem *shmobile_scu_base; extern void shmobile_smp_init_cpus(unsigned int ncores); static inline void __init shmobile_init_late(void) diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h index 06a5da3c3050..b2074e2acb15 100644 --- a/arch/arm/mach-shmobile/include/mach/irqs.h +++ b/arch/arm/mach-shmobile/include/mach/irqs.h @@ -5,10 +5,15 @@ /* GIC */ #define gic_spi(nr) ((nr) + 32) +#define gic_iid(nr) (nr) /* ICCIAR / interrupt ID */ /* INTCS */ #define INTCS_VECT_BASE 0x3400 #define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect)) #define intcs_evt2irq(evt) evt2irq(INTCS_VECT_BASE + (evt)) +/* External IRQ pins */ +#define IRQPIN_BASE 2000 +#define irq_pin(nr) ((nr) + IRQPIN_BASE) + #endif /* __ASM_MACH_IRQS_H */ diff --git a/arch/arm/mach-shmobile/intc-r8a7779.c b/arch/arm/mach-shmobile/intc-r8a7779.c index 8807c27f71f9..b86dc8908724 100644 --- a/arch/arm/mach-shmobile/intc-r8a7779.c +++ b/arch/arm/mach-shmobile/intc-r8a7779.c @@ -19,12 +19,16 @@ */ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/irqchip/arm-gic.h> +#include <linux/platform_data/irq-renesas-intc-irqpin.h> +#include <linux/irqchip.h> #include <mach/common.h> #include <mach/intc.h> +#include <mach/irqs.h> #include <mach/r8a7779.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -38,18 +42,61 @@ #define INT2NTSR0 IOMEM(0xfe700060) #define INT2NTSR1 IOMEM(0xfe700064) +static struct renesas_intc_irqpin_config irqpin0_platform_data = { + .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */ + .sense_bitfield_width = 2, +}; + +static struct resource irqpin0_resources[] = { + DEFINE_RES_MEM(0xfe78001c, 4), /* ICR1 */ + DEFINE_RES_MEM(0xfe780010, 4), /* INTPRI */ + DEFINE_RES_MEM(0xfe780024, 4), /* INTREQ */ + DEFINE_RES_MEM(0xfe780044, 4), /* INTMSK0 */ + DEFINE_RES_MEM(0xfe780064, 4), /* INTMSKCLR0 */ + DEFINE_RES_IRQ(gic_spi(27)), /* IRQ0 */ + DEFINE_RES_IRQ(gic_spi(28)), /* IRQ1 */ + DEFINE_RES_IRQ(gic_spi(29)), /* IRQ2 */ + DEFINE_RES_IRQ(gic_spi(30)), /* IRQ3 */ +}; + +static struct platform_device irqpin0_device = { + .name = "renesas_intc_irqpin", + .id = 0, + .resource = irqpin0_resources, + .num_resources = ARRAY_SIZE(irqpin0_resources), + .dev = { + .platform_data = &irqpin0_platform_data, + }, +}; + +void __init r8a7779_init_irq_extpin(int irlm) +{ + void __iomem *icr0 = ioremap_nocache(0xfe780000, PAGE_SIZE); + unsigned long tmp; + + if (icr0) { + tmp = ioread32(icr0); + if (irlm) + tmp |= 1 << 23; /* IRQ0 -> IRQ3 as individual pins */ + else + tmp &= ~(1 << 23); /* IRL mode - not supported */ + tmp |= (1 << 21); /* LVLMODE = 1 */ + iowrite32(tmp, icr0); + iounmap(icr0); + + if (irlm) + platform_device_register(&irqpin0_device); + } else + pr_warn("r8a7779: unable to setup external irq pin mode\n"); +} + static int r8a7779_set_wake(struct irq_data *data, unsigned int on) { return 0; /* always allow wakeup */ } -void __init r8a7779_init_irq(void) +static void __init r8a7779_init_irq_common(void) { - void __iomem *gic_dist_base = IOMEM(0xf0001000); - void __iomem *gic_cpu_base = IOMEM(0xf0000100); - - /* use GIC to handle interrupts */ - gic_init(0, 29, gic_dist_base, gic_cpu_base); gic_arch_extn.irq_set_wake = r8a7779_set_wake; /* route all interrupts to ARM */ @@ -63,3 +110,22 @@ void __init r8a7779_init_irq(void) __raw_writel(0xbffffffc, INT2SMSKCR3); __raw_writel(0x003fee3f, INT2SMSKCR4); } + +void __init r8a7779_init_irq(void) +{ + void __iomem *gic_dist_base = IOMEM(0xf0001000); + void __iomem *gic_cpu_base = IOMEM(0xf0000100); + + /* use GIC to handle interrupts */ + gic_init(0, 29, gic_dist_base, gic_cpu_base); + + r8a7779_init_irq_common(); +} + +#ifdef CONFIG_OF +void __init r8a7779_init_irq_dt(void) +{ + irqchip_init(); + r8a7779_init_irq_common(); +} +#endif diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index 91faba666d46..19a26f4579b3 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -260,108 +260,6 @@ static int sh73a0_set_wake(struct irq_data *data, unsigned int on) return 0; /* always allow wakeup */ } -#define RELOC_BASE 0x1200 - -/* INTCA IRQ pins at INTCS + RELOC_BASE to make space for GIC+INTC handling */ -#define INTCS_VECT_RELOC(n, vect) INTCS_VECT((n), (vect) + RELOC_BASE) - -INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000, - INTCS_VECT_RELOC, "sh73a0-intca-irq-pins"); - -static int to_gic_irq(struct irq_data *data) -{ - unsigned int vect = irq2evt(data->irq) - INTCS_VECT_BASE; - - if (vect >= 0x3200) - vect -= 0x3000; - else - vect -= 0x0200; - - return gic_spi((vect >> 5) + 1); -} - -static int to_intca_reloc_irq(struct irq_data *data) -{ - return data->irq + (RELOC_BASE >> 5); -} - -#define irq_cb(cb, irq) irq_get_chip(irq)->cb(irq_get_irq_data(irq)) -#define irq_cbp(cb, irq, p...) irq_get_chip(irq)->cb(irq_get_irq_data(irq), p) - -static void intca_gic_enable(struct irq_data *data) -{ - irq_cb(irq_unmask, to_intca_reloc_irq(data)); - irq_cb(irq_unmask, to_gic_irq(data)); -} - -static void intca_gic_disable(struct irq_data *data) -{ - irq_cb(irq_mask, to_gic_irq(data)); - irq_cb(irq_mask, to_intca_reloc_irq(data)); -} - -static void intca_gic_mask_ack(struct irq_data *data) -{ - irq_cb(irq_mask, to_gic_irq(data)); - irq_cb(irq_mask_ack, to_intca_reloc_irq(data)); -} - -static void intca_gic_eoi(struct irq_data *data) -{ - irq_cb(irq_eoi, to_gic_irq(data)); -} - -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); -} - -#ifdef CONFIG_SMP -static int intca_gic_set_affinity(struct irq_data *data, - const struct cpumask *cpumask, - bool force) -{ - return irq_cbp(irq_set_affinity, to_gic_irq(data), cpumask, force); -} -#endif - -struct irq_chip intca_gic_irq_chip = { - .name = "INTCA-GIC", - .irq_mask = intca_gic_disable, - .irq_unmask = intca_gic_enable, - .irq_mask_ack = intca_gic_mask_ack, - .irq_eoi = intca_gic_eoi, - .irq_enable = intca_gic_enable, - .irq_disable = intca_gic_disable, - .irq_shutdown = intca_gic_disable, - .irq_set_type = intca_gic_set_type, - .irq_set_wake = sh73a0_set_wake, -#ifdef CONFIG_SMP - .irq_set_affinity = intca_gic_set_affinity, -#endif -}; - -static int to_intc_vect(int irq) -{ - unsigned int irq_pin = irq - gic_spi(1); - unsigned int offs; - - if (irq_pin < 16) - offs = 0x0200; - else - offs = 0x3000; - - return offs + (irq_pin << 5); -} - -static irqreturn_t sh73a0_irq_pin_demux(int irq, void *dev_id) -{ - generic_handle_irq(intcs_evt2irq(to_intc_vect(irq))); - return IRQ_HANDLED; -} - -static struct irqaction sh73a0_irq_pin_cascade[32]; - #define PINTER0_PHYS 0xe69000a0 #define PINTER1_PHYS 0xe69000a4 #define PINTER0_VIRT IOMEM(0xe69000a0) @@ -422,13 +320,11 @@ void __init sh73a0_init_irq(void) void __iomem *gic_dist_base = IOMEM(0xf0001000); void __iomem *gic_cpu_base = IOMEM(0xf0000100); void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); - int k, n; gic_init(0, 29, gic_dist_base, gic_cpu_base); gic_arch_extn.irq_set_wake = sh73a0_set_wake; register_intc_controller(&intcs_desc); - register_intc_controller(&intca_irq_pins_desc); register_intc_controller(&intc_pint0_desc); register_intc_controller(&intc_pint1_desc); @@ -438,19 +334,6 @@ void __init sh73a0_init_irq(void) sh73a0_intcs_cascade.dev_id = intevtsa; setup_irq(gic_spi(50), &sh73a0_intcs_cascade); - /* IRQ pins require special handling through INTCA and GIC */ - for (k = 0; k < 32; k++) { - sh73a0_irq_pin_cascade[k].name = "INTCA-GIC cascade"; - sh73a0_irq_pin_cascade[k].handler = sh73a0_irq_pin_demux; - setup_irq(gic_spi(1 + k), &sh73a0_irq_pin_cascade[k]); - - n = intcs_evt2irq(to_intc_vect(gic_spi(1 + k))); - WARN_ON(irq_alloc_desc_at(n, numa_node_id()) != n); - irq_set_chip_and_handler_name(n, &intca_gic_irq_chip, - handle_level_irq, "level"); - set_irq_flags(n, IRQF_VALID); /* yuck */ - } - /* PINT pins are sanely tied to the GIC as SPI */ sh73a0_pint0_cascade.name = "PINT0 cascade"; sh73a0_pint0_cascade.handler = sh73a0_pint0_demux; @@ -460,11 +343,3 @@ 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/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index 47662a581c0a..e4545c152722 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -404,7 +404,7 @@ void __init emev2_add_standard_devices(void) ARRAY_SIZE(emev2_late_devices)); } -void __init emev2_init_delay(void) +static void __init emev2_init_delay(void) { shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */ } @@ -439,7 +439,7 @@ static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = { { } }; -void __init emev2_add_standard_devices_dt(void) +static void __init emev2_add_standard_devices_dt(void) { of_platform_populate(NULL, of_default_bus_match_table, emev2_auxdata_lookup, NULL); diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index c54ff9b29fe5..042df35e71a0 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/input.h> @@ -28,6 +29,7 @@ #include <linux/serial_sci.h> #include <linux/sh_intc.h> #include <linux/sh_timer.h> +#include <linux/dma-mapping.h> #include <mach/hardware.h> #include <mach/irqs.h> #include <mach/r8a7779.h> @@ -91,7 +93,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 = SCIx_IRQ_MUXED(gic_spi(88)), + .irqs = SCIx_IRQ_MUXED(gic_iid(0x78)), }; static struct platform_device scif0_device = { @@ -108,7 +110,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 = SCIx_IRQ_MUXED(gic_spi(89)), + .irqs = SCIx_IRQ_MUXED(gic_iid(0x79)), }; static struct platform_device scif1_device = { @@ -125,7 +127,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 = SCIx_IRQ_MUXED(gic_spi(90)), + .irqs = SCIx_IRQ_MUXED(gic_iid(0x7a)), }; static struct platform_device scif2_device = { @@ -142,7 +144,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 = SCIx_IRQ_MUXED(gic_spi(91)), + .irqs = SCIx_IRQ_MUXED(gic_iid(0x7b)), }; static struct platform_device scif3_device = { @@ -159,7 +161,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 = SCIx_IRQ_MUXED(gic_spi(92)), + .irqs = SCIx_IRQ_MUXED(gic_iid(0x7c)), }; static struct platform_device scif4_device = { @@ -176,7 +178,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 = SCIx_IRQ_MUXED(gic_spi(93)), + .irqs = SCIx_IRQ_MUXED(gic_iid(0x7d)), }; static struct platform_device scif5_device = { @@ -203,7 +205,7 @@ static struct resource tmu00_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(32), + .start = gic_iid(0x40), .flags = IORESOURCE_IRQ, }, }; @@ -233,7 +235,7 @@ static struct resource tmu01_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(33), + .start = gic_iid(0x41), .flags = IORESOURCE_IRQ, }, }; @@ -255,7 +257,7 @@ static struct resource rcar_i2c0_res[] = { .end = 0xffc70fff, .flags = IORESOURCE_MEM, }, { - .start = gic_spi(79), + .start = gic_iid(0x6f), .flags = IORESOURCE_IRQ, }, }; @@ -273,7 +275,7 @@ static struct resource rcar_i2c1_res[] = { .end = 0xffc71fff, .flags = IORESOURCE_MEM, }, { - .start = gic_spi(82), + .start = gic_iid(0x72), .flags = IORESOURCE_IRQ, }, }; @@ -291,7 +293,7 @@ static struct resource rcar_i2c2_res[] = { .end = 0xffc72fff, .flags = IORESOURCE_MEM, }, { - .start = gic_spi(80), + .start = gic_iid(0x70), .flags = IORESOURCE_IRQ, }, }; @@ -309,7 +311,7 @@ static struct resource rcar_i2c3_res[] = { .end = 0xffc73fff, .flags = IORESOURCE_MEM, }, { - .start = gic_spi(81), + .start = gic_iid(0x71), .flags = IORESOURCE_IRQ, }, }; @@ -321,7 +323,31 @@ static struct platform_device i2c3_device = { .num_resources = ARRAY_SIZE(rcar_i2c3_res), }; -static struct platform_device *r8a7779_early_devices[] __initdata = { +static struct resource sata_resources[] = { + [0] = { + .name = "rcar-sata", + .start = 0xfc600000, + .end = 0xfc601fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_iid(0x84), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sata_device = { + .name = "sata_rcar", + .id = -1, + .resource = sata_resources, + .num_resources = ARRAY_SIZE(sata_resources), + .dev = { + .dma_mask = &sata_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct platform_device *r8a7779_devices_dt[] __initdata = { &scif0_device, &scif1_device, &scif2_device, @@ -330,13 +356,14 @@ static struct platform_device *r8a7779_early_devices[] __initdata = { &scif5_device, &tmu00_device, &tmu01_device, +}; + +static struct platform_device *r8a7779_late_devices[] __initdata = { &i2c0_device, &i2c1_device, &i2c2_device, &i2c3_device, -}; - -static struct platform_device *r8a7779_late_devices[] __initdata = { + &sata_device, }; void __init r8a7779_add_standard_devices(void) @@ -349,8 +376,8 @@ void __init r8a7779_add_standard_devices(void) r8a7779_init_pm_domains(); - platform_add_devices(r8a7779_early_devices, - ARRAY_SIZE(r8a7779_early_devices)); + platform_add_devices(r8a7779_devices_dt, + ARRAY_SIZE(r8a7779_devices_dt)); platform_add_devices(r8a7779_late_devices, ARRAY_SIZE(r8a7779_late_devices)); } @@ -367,8 +394,8 @@ void __init r8a7779_earlytimer_init(void) void __init r8a7779_add_early_devices(void) { - early_platform_add_devices(r8a7779_early_devices, - ARRAY_SIZE(r8a7779_early_devices)); + early_platform_add_devices(r8a7779_devices_dt, + ARRAY_SIZE(r8a7779_devices_dt)); /* Early serial console setup is not included here due to * memory map collisions. The SCIF serial ports in r8a7779 @@ -386,3 +413,40 @@ void __init r8a7779_add_early_devices(void) * command line in case of the marzen board. */ } + +#ifdef CONFIG_USE_OF +void __init r8a7779_init_delay(void) +{ + shmobile_setup_delay(1000, 2, 4); /* Cortex-A9 @ 1000MHz */ +} + +static const struct of_dev_auxdata r8a7779_auxdata_lookup[] __initconst = { + {}, +}; + +void __init r8a7779_add_standard_devices_dt(void) +{ + /* clocks are setup late during boot in the case of DT */ + r8a7779_clock_init(); + + platform_add_devices(r8a7779_devices_dt, + ARRAY_SIZE(r8a7779_devices_dt)); + of_platform_populate(NULL, of_default_bus_match_table, + r8a7779_auxdata_lookup, NULL); +} + +static const char *r8a7779_compat_dt[] __initdata = { + "renesas,r8a7779", + NULL, +}; + +DT_MACHINE_START(R8A7779_DT, "Generic R8A7779 (Flattened Device Tree)") + .map_io = r8a7779_map_io, + .init_early = r8a7779_init_delay, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = r8a7779_init_irq_dt, + .init_machine = r8a7779_add_standard_devices_dt, + .init_time = shmobile_timer_init, + .dt_compat = r8a7779_compat_dt, +MACHINE_END +#endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index bdab575f88bc..e8cd93a5c550 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/irqchip.h> #include <linux/platform_device.h> #include <linux/of_platform.h> #include <linux/delay.h> @@ -32,6 +33,7 @@ #include <linux/sh_intc.h> #include <linux/sh_timer.h> #include <linux/platform_data/sh_ipmmu.h> +#include <linux/platform_data/irq-renesas-intc-irqpin.h> #include <mach/dma-register.h> #include <mach/hardware.h> #include <mach/irqs.h> @@ -810,7 +812,128 @@ static struct platform_device ipmmu_device = { .num_resources = ARRAY_SIZE(ipmmu_resources), }; -static struct platform_device *sh73a0_early_devices_dt[] __initdata = { +static struct renesas_intc_irqpin_config irqpin0_platform_data = { + .irq_base = irq_pin(0), /* IRQ0 -> IRQ7 */ +}; + +static struct resource irqpin0_resources[] = { + DEFINE_RES_MEM(0xe6900000, 4), /* ICR1A */ + DEFINE_RES_MEM(0xe6900010, 4), /* INTPRI00A */ + DEFINE_RES_MEM(0xe6900020, 1), /* INTREQ00A */ + DEFINE_RES_MEM(0xe6900040, 1), /* INTMSK00A */ + DEFINE_RES_MEM(0xe6900060, 1), /* INTMSKCLR00A */ + DEFINE_RES_IRQ(gic_spi(1)), /* IRQ0 */ + DEFINE_RES_IRQ(gic_spi(2)), /* IRQ1 */ + DEFINE_RES_IRQ(gic_spi(3)), /* IRQ2 */ + DEFINE_RES_IRQ(gic_spi(4)), /* IRQ3 */ + DEFINE_RES_IRQ(gic_spi(5)), /* IRQ4 */ + DEFINE_RES_IRQ(gic_spi(6)), /* IRQ5 */ + DEFINE_RES_IRQ(gic_spi(7)), /* IRQ6 */ + DEFINE_RES_IRQ(gic_spi(8)), /* IRQ7 */ +}; + +static struct platform_device irqpin0_device = { + .name = "renesas_intc_irqpin", + .id = 0, + .resource = irqpin0_resources, + .num_resources = ARRAY_SIZE(irqpin0_resources), + .dev = { + .platform_data = &irqpin0_platform_data, + }, +}; + +static struct renesas_intc_irqpin_config irqpin1_platform_data = { + .irq_base = irq_pin(8), /* IRQ8 -> IRQ15 */ + .control_parent = true, /* Disable spurious IRQ10 */ +}; + +static struct resource irqpin1_resources[] = { + DEFINE_RES_MEM(0xe6900004, 4), /* ICR2A */ + DEFINE_RES_MEM(0xe6900014, 4), /* INTPRI10A */ + DEFINE_RES_MEM(0xe6900024, 1), /* INTREQ10A */ + DEFINE_RES_MEM(0xe6900044, 1), /* INTMSK10A */ + DEFINE_RES_MEM(0xe6900064, 1), /* INTMSKCLR10A */ + DEFINE_RES_IRQ(gic_spi(9)), /* IRQ8 */ + DEFINE_RES_IRQ(gic_spi(10)), /* IRQ9 */ + DEFINE_RES_IRQ(gic_spi(11)), /* IRQ10 */ + DEFINE_RES_IRQ(gic_spi(12)), /* IRQ11 */ + DEFINE_RES_IRQ(gic_spi(13)), /* IRQ12 */ + DEFINE_RES_IRQ(gic_spi(14)), /* IRQ13 */ + DEFINE_RES_IRQ(gic_spi(15)), /* IRQ14 */ + DEFINE_RES_IRQ(gic_spi(16)), /* IRQ15 */ +}; + +static struct platform_device irqpin1_device = { + .name = "renesas_intc_irqpin", + .id = 1, + .resource = irqpin1_resources, + .num_resources = ARRAY_SIZE(irqpin1_resources), + .dev = { + .platform_data = &irqpin1_platform_data, + }, +}; + +static struct renesas_intc_irqpin_config irqpin2_platform_data = { + .irq_base = irq_pin(16), /* IRQ16 -> IRQ23 */ +}; + +static struct resource irqpin2_resources[] = { + DEFINE_RES_MEM(0xe6900008, 4), /* ICR3A */ + DEFINE_RES_MEM(0xe6900018, 4), /* INTPRI20A */ + DEFINE_RES_MEM(0xe6900028, 1), /* INTREQ20A */ + DEFINE_RES_MEM(0xe6900048, 1), /* INTMSK20A */ + DEFINE_RES_MEM(0xe6900068, 1), /* INTMSKCLR20A */ + DEFINE_RES_IRQ(gic_spi(17)), /* IRQ16 */ + DEFINE_RES_IRQ(gic_spi(18)), /* IRQ17 */ + DEFINE_RES_IRQ(gic_spi(19)), /* IRQ18 */ + DEFINE_RES_IRQ(gic_spi(20)), /* IRQ19 */ + DEFINE_RES_IRQ(gic_spi(21)), /* IRQ20 */ + DEFINE_RES_IRQ(gic_spi(22)), /* IRQ21 */ + DEFINE_RES_IRQ(gic_spi(23)), /* IRQ22 */ + DEFINE_RES_IRQ(gic_spi(24)), /* IRQ23 */ +}; + +static struct platform_device irqpin2_device = { + .name = "renesas_intc_irqpin", + .id = 2, + .resource = irqpin2_resources, + .num_resources = ARRAY_SIZE(irqpin2_resources), + .dev = { + .platform_data = &irqpin2_platform_data, + }, +}; + +static struct renesas_intc_irqpin_config irqpin3_platform_data = { + .irq_base = irq_pin(24), /* IRQ24 -> IRQ31 */ +}; + +static struct resource irqpin3_resources[] = { + DEFINE_RES_MEM(0xe690000c, 4), /* ICR4A */ + DEFINE_RES_MEM(0xe690001c, 4), /* INTPRI30A */ + DEFINE_RES_MEM(0xe690002c, 1), /* INTREQ30A */ + DEFINE_RES_MEM(0xe690004c, 1), /* INTMSK30A */ + DEFINE_RES_MEM(0xe690006c, 1), /* INTMSKCLR30A */ + DEFINE_RES_IRQ(gic_spi(25)), /* IRQ24 */ + DEFINE_RES_IRQ(gic_spi(26)), /* IRQ25 */ + DEFINE_RES_IRQ(gic_spi(27)), /* IRQ26 */ + DEFINE_RES_IRQ(gic_spi(28)), /* IRQ27 */ + DEFINE_RES_IRQ(gic_spi(29)), /* IRQ28 */ + DEFINE_RES_IRQ(gic_spi(30)), /* IRQ29 */ + DEFINE_RES_IRQ(gic_spi(31)), /* IRQ30 */ + DEFINE_RES_IRQ(gic_spi(32)), /* IRQ31 */ +}; + +static struct platform_device irqpin3_device = { + .name = "renesas_intc_irqpin", + .id = 3, + .resource = irqpin3_resources, + .num_resources = ARRAY_SIZE(irqpin3_resources), + .dev = { + .platform_data = &irqpin3_platform_data, + }, +}; + +static struct platform_device *sh73a0_devices_dt[] __initdata = { &scif0_device, &scif1_device, &scif2_device, @@ -838,6 +961,10 @@ static struct platform_device *sh73a0_late_devices[] __initdata = { &dma0_device, &mpdma0_device, &pmu_device, + &irqpin0_device, + &irqpin1_device, + &irqpin2_device, + &irqpin3_device, }; #define SRCR2 IOMEM(0xe61580b0) @@ -847,8 +974,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_devices_dt, + ARRAY_SIZE(sh73a0_devices_dt)); platform_add_devices(sh73a0_early_devices, ARRAY_SIZE(sh73a0_early_devices)); platform_add_devices(sh73a0_late_devices, @@ -867,8 +994,8 @@ 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_devices_dt, + ARRAY_SIZE(sh73a0_devices_dt)); early_platform_add_devices(sh73a0_early_devices, ARRAY_SIZE(sh73a0_early_devices)); @@ -878,23 +1005,9 @@ void __init sh73a0_add_early_devices(void) #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) +void __init sh73a0_init_delay(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 = { @@ -906,8 +1019,8 @@ 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)); + platform_add_devices(sh73a0_devices_dt, + ARRAY_SIZE(sh73a0_devices_dt)); of_platform_populate(NULL, of_default_bus_match_table, sh73a0_auxdata_lookup, NULL); } @@ -918,10 +1031,11 @@ static const char *sh73a0_boards_compat_dt[] __initdata = { }; DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") + .smp = smp_ops(sh73a0_smp_ops), .map_io = sh73a0_map_io, - .init_early = sh73a0_add_early_devices_dt, + .init_early = sh73a0_init_delay, .nr_irqs = NR_IRQS_LEGACY, - .init_irq = sh73a0_init_irq_dt, + .init_irq = irqchip_init, .init_machine = sh73a0_add_standard_devices_dt, .init_time = shmobile_timer_init, .dt_compat = sh73a0_boards_compat_dt, diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c index 953eb1f9388d..8225c16b371b 100644 --- a/arch/arm/mach-shmobile/smp-emev2.c +++ b/arch/arm/mach-shmobile/smp-emev2.c @@ -28,63 +28,9 @@ #include <mach/emev2.h> #include <asm/smp_plat.h> #include <asm/smp_scu.h> -#include <asm/cacheflush.h> #define EMEV2_SCU_BASE 0x1e000000 -static DEFINE_SPINLOCK(scu_lock); -static void __iomem *scu_base; - -static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) -{ - unsigned long tmp; - - /* we assume this code is running on a different cpu - * than the one that is changing coherency setting */ - spin_lock(&scu_lock); - tmp = readl(scu_base + 8); - tmp &= ~clr; - tmp |= set; - writel(tmp, scu_base + 8); - spin_unlock(&scu_lock); - -} - -static unsigned int __init emev2_get_core_count(void) -{ - if (!scu_base) { - scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE); - emev2_clock_init(); /* need ioremapped SMU */ - } - - WARN_ON_ONCE(!scu_base); - - return scu_base ? scu_get_core_count(scu_base) : 1; -} - -static int emev2_platform_cpu_kill(unsigned int cpu) -{ - return 0; /* not supported yet */ -} - -static int __maybe_unused emev2_cpu_kill(unsigned int cpu) -{ - int k; - - /* this function is running on another CPU than the offline target, - * here we need wait for shutdown code in platform_cpu_die() to - * finish before asking SoC-specific code to power off the CPU core. - */ - for (k = 0; k < 1000; k++) { - if (shmobile_cpu_is_dead(cpu)) - return emev2_platform_cpu_kill(cpu); - mdelay(1); - } - - return 0; -} - - static void __cpuinit emev2_secondary_init(unsigned int cpu) { gic_secondary_init(0); @@ -92,31 +38,30 @@ static void __cpuinit emev2_secondary_init(unsigned int cpu) static int __cpuinit emev2_boot_secondary(unsigned int cpu, struct task_struct *idle) { - cpu = cpu_logical_map(cpu); - - /* enable cache coherency */ - modify_scu_cpu_psr(0, 3 << (cpu * 8)); - - /* Tell ROM loader about our vector (in headsmp.S) */ - emev2_set_boot_vector(__pa(shmobile_secondary_vector)); - - arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + arch_send_wakeup_ipi_mask(cpumask_of(cpu_logical_map(cpu))); return 0; } static void __init emev2_smp_prepare_cpus(unsigned int max_cpus) { - int cpu = cpu_logical_map(0); + scu_enable(shmobile_scu_base); - scu_enable(scu_base); + /* Tell ROM loader about our vector (in headsmp-scu.S) */ + emev2_set_boot_vector(__pa(shmobile_secondary_vector_scu)); - /* enable cache coherency on CPU0 */ - modify_scu_cpu_psr(0, 3 << (cpu * 8)); + /* enable cache coherency on booting CPU */ + scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL); } static void __init emev2_smp_init_cpus(void) { - unsigned int ncores = emev2_get_core_count(); + unsigned int ncores; + + /* setup EMEV2 specific SCU base */ + shmobile_scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE); + emev2_clock_init(); /* need ioremapped SMU */ + + ncores = shmobile_scu_base ? scu_get_core_count(shmobile_scu_base) : 1; shmobile_smp_init_cpus(ncores); } @@ -126,9 +71,4 @@ struct smp_operations emev2_smp_ops __initdata = { .smp_prepare_cpus = emev2_smp_prepare_cpus, .smp_secondary_init = emev2_secondary_init, .smp_boot_secondary = emev2_boot_secondary, -#ifdef CONFIG_HOTPLUG_CPU - .cpu_kill = emev2_cpu_kill, - .cpu_die = shmobile_cpu_die, - .cpu_disable = shmobile_cpu_disable, -#endif }; diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c index 3a4acf23edcf..ea4535a5c4e2 100644 --- a/arch/arm/mach-shmobile/smp-r8a7779.c +++ b/arch/arm/mach-shmobile/smp-r8a7779.c @@ -26,11 +26,13 @@ #include <linux/irqchip/arm-gic.h> #include <mach/common.h> #include <mach/r8a7779.h> +#include <asm/cacheflush.h> #include <asm/smp_plat.h> #include <asm/smp_scu.h> #include <asm/smp_twd.h> #define AVECR IOMEM(0xfe700040) +#define R8A7779_SCU_BASE 0xf0000000 static struct r8a7779_pm_ch r8a7779_ch_cpu1 = { .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */ @@ -56,44 +58,14 @@ static struct r8a7779_pm_ch *r8a7779_ch_cpu[4] = { [3] = &r8a7779_ch_cpu3, }; -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); - +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, R8A7779_SCU_BASE + 0x600, 29); void __init r8a7779_register_twd(void) { twd_local_timer_register(&twd_local_timer); } #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 r8a7779_get_core_count(void) -{ - void __iomem *scu_base = scu_base_addr(); - - return scu_get_core_count(scu_base); -} - static int r8a7779_platform_cpu_kill(unsigned int cpu) { struct r8a7779_pm_ch *ch = NULL; @@ -101,9 +73,6 @@ static int r8a7779_platform_cpu_kill(unsigned int cpu) cpu = cpu_logical_map(cpu); - /* disable cache coherency */ - modify_scu_cpu_psr(3 << (cpu * 8), 0); - if (cpu < ARRAY_SIZE(r8a7779_ch_cpu)) ch = r8a7779_ch_cpu[cpu]; @@ -113,25 +82,6 @@ static int r8a7779_platform_cpu_kill(unsigned int cpu) return ret ? ret : 1; } -static int __maybe_unused r8a7779_cpu_kill(unsigned int cpu) -{ - int k; - - /* this function is running on another CPU than the offline target, - * here we need wait for shutdown code in platform_cpu_die() to - * finish before asking SoC-specific code to power off the CPU core. - */ - for (k = 0; k < 1000; k++) { - if (shmobile_cpu_is_dead(cpu)) - return r8a7779_platform_cpu_kill(cpu); - - mdelay(1); - } - - return 0; -} - - static void __cpuinit r8a7779_secondary_init(unsigned int cpu) { gic_secondary_init(0); @@ -144,9 +94,6 @@ static int __cpuinit r8a7779_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 (cpu < ARRAY_SIZE(r8a7779_ch_cpu)) ch = r8a7779_ch_cpu[cpu]; @@ -158,15 +105,13 @@ static int __cpuinit r8a7779_boot_secondary(unsigned int cpu, struct task_struct static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus) { - int cpu = cpu_logical_map(0); + scu_enable(shmobile_scu_base); - scu_enable(scu_base_addr()); + /* Map the reset vector (in headsmp-scu.S) */ + __raw_writel(__pa(shmobile_secondary_vector_scu), AVECR); - /* Map the reset vector (in headsmp.S) */ - __raw_writel(__pa(shmobile_secondary_vector), AVECR); - - /* enable cache coherency on CPU0 */ - modify_scu_cpu_psr(0, 3 << (cpu * 8)); + /* enable cache coherency on booting CPU */ + scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL); r8a7779_pm_init(); @@ -178,10 +123,60 @@ static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus) static void __init r8a7779_smp_init_cpus(void) { - unsigned int ncores = r8a7779_get_core_count(); + /* setup r8a7779 specific SCU base */ + shmobile_scu_base = IOMEM(R8A7779_SCU_BASE); + + shmobile_smp_init_cpus(scu_get_core_count(shmobile_scu_base)); +} - shmobile_smp_init_cpus(ncores); +#ifdef CONFIG_HOTPLUG_CPU +static int r8a7779_scu_psr_core_disabled(int cpu) +{ + unsigned long mask = 3 << (cpu * 8); + + if ((__raw_readl(shmobile_scu_base + 8) & mask) == mask) + return 1; + + return 0; +} + +static int r8a7779_cpu_kill(unsigned int cpu) +{ + int k; + + /* this function is running on another CPU than the offline target, + * here we need wait for shutdown code in platform_cpu_die() to + * finish before asking SoC-specific code to power off the CPU core. + */ + for (k = 0; k < 1000; k++) { + if (r8a7779_scu_psr_core_disabled(cpu)) + return r8a7779_platform_cpu_kill(cpu); + + mdelay(1); + } + + return 0; +} + +static void r8a7779_cpu_die(unsigned int cpu) +{ + dsb(); + flush_cache_all(); + + /* disable cache coherency */ + scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF); + + /* Endless loop until power off from r8a7779_cpu_kill() */ + while (1) + cpu_do_idle(); +} + +static int r8a7779_cpu_disable(unsigned int cpu) +{ + /* only CPU1->3 have power domains, do not allow hotplug of CPU0 */ + return cpu == 0 ? -EPERM : 0; } +#endif /* CONFIG_HOTPLUG_CPU */ struct smp_operations r8a7779_smp_ops __initdata = { .smp_init_cpus = r8a7779_smp_init_cpus, @@ -190,7 +185,7 @@ struct smp_operations r8a7779_smp_ops __initdata = { .smp_boot_secondary = r8a7779_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU .cpu_kill = r8a7779_cpu_kill, - .cpu_die = shmobile_cpu_die, - .cpu_disable = shmobile_cpu_disable, + .cpu_die = r8a7779_cpu_die, + .cpu_disable = r8a7779_cpu_disable, #endif }; diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index acb46a94ccdf..5ae502b16437 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -39,26 +39,16 @@ #define PSTR_SHUTDOWN_MODE 3 -static void __iomem *scu_base_addr(void) -{ - return (void __iomem *)0xf0000000; -} +#define SH73A0_SCU_BASE 0xf0000000 #ifdef CONFIG_HAVE_ARM_TWD -static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29); +static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, SH73A0_SCU_BASE + 0x600, 29); void __init sh73a0_register_twd(void) { twd_local_timer_register(&twd_local_timer); } #endif -static unsigned int __init sh73a0_get_core_count(void) -{ - void __iomem *scu_base = scu_base_addr(); - - return scu_get_core_count(scu_base); -} - static void __cpuinit sh73a0_secondary_init(unsigned int cpu) { gic_secondary_init(0); @@ -78,21 +68,22 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus) { - scu_enable(scu_base_addr()); + scu_enable(shmobile_scu_base); - /* Map the reset vector (in headsmp-sh73a0.S) */ + /* Map the reset vector (in headsmp-scu.S) */ __raw_writel(0, APARMBAREA); /* 4k */ - __raw_writel(__pa(sh73a0_secondary_vector), SBAR); + __raw_writel(__pa(shmobile_secondary_vector_scu), SBAR); /* enable cache coherency on booting CPU */ - scu_power_mode(scu_base_addr(), SCU_PM_NORMAL); + scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL); } static void __init sh73a0_smp_init_cpus(void) { - unsigned int ncores = sh73a0_get_core_count(); + /* setup sh73a0 specific SCU base */ + shmobile_scu_base = IOMEM(SH73A0_SCU_BASE); - shmobile_smp_init_cpus(ncores); + shmobile_smp_init_cpus(scu_get_core_count(shmobile_scu_base)); } #ifdef CONFIG_HOTPLUG_CPU @@ -128,11 +119,16 @@ static void sh73a0_cpu_die(unsigned int cpu) 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); + scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF); /* Enter shutdown mode */ cpu_do_idle(); } + +static int sh73a0_cpu_disable(unsigned int cpu) +{ + return 0; /* CPU0 and CPU1 supported */ +} #endif /* CONFIG_HOTPLUG_CPU */ struct smp_operations sh73a0_smp_ops __initdata = { @@ -143,6 +139,6 @@ struct smp_operations sh73a0_smp_ops __initdata = { #ifdef CONFIG_HOTPLUG_CPU .cpu_kill = sh73a0_cpu_kill, .cpu_die = sh73a0_cpu_die, - .cpu_disable = shmobile_cpu_disable_any, + .cpu_disable = sh73a0_cpu_disable, #endif }; diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c index c7d2b4a8d8cc..25a10191b021 100644 --- a/arch/arm/mach-spear13xx/spear13xx.c +++ b/arch/arm/mach-spear13xx/spear13xx.c @@ -15,12 +15,12 @@ #include <linux/amba/pl022.h> #include <linux/clk.h> +#include <linux/clocksource.h> #include <linux/dw_dmac.h> #include <linux/err.h> #include <linux/of.h> #include <asm/hardware/cache-l2x0.h> #include <asm/mach/map.h> -#include <asm/smp_twd.h> #include <mach/dma.h> #include <mach/generic.h> #include <mach/spear.h> @@ -179,5 +179,5 @@ void __init spear13xx_timer_init(void) clk_put(pclk); spear_setup_of_timer(); - twd_local_timer_of_register(); + clocksource_of_init(); } diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index f6b46ae2b7f8..e40326d0e29f 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -10,6 +10,7 @@ obj-y += pm.o obj-y += reset.o obj-y += reset-handler.o obj-y += sleep.o +obj-y += tegra.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o @@ -27,9 +28,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o obj-$(CONFIG_TEGRA_PCI) += pcie.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o -obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o -obj-$(CONFIG_ARCH_TEGRA_114_SOC) += board-dt-tegra114.o +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_114_SOC) += cpuidle-tegra114.o endif diff --git a/arch/arm/mach-tegra/board-dt-tegra114.c b/arch/arm/mach-tegra/board-dt-tegra114.c deleted file mode 100644 index 085d63637b62..000000000000 --- a/arch/arm/mach-tegra/board-dt-tegra114.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c deleted file mode 100644 index bf68567e549d..000000000000 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * arch/arm/mach-tegra/board-dt-tegra30.c - * - * NVIDIA Tegra30 device tree board support - * - * Copyright (C) 2011 NVIDIA Corporation - * - * Derived from: - * - * arch/arm/mach-tegra/board-dt-tegra20.c - * - * Copyright (C) 2010 Secret Lab Technologies, Ltd. - * Copyright (C) 2010 Google, Inc. - * - * 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/clocksource.h> -#include <linux/kernel.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_fdt.h> -#include <linux/of_irq.h> -#include <linux/of_platform.h> - -#include <asm/mach/arch.h> - -#include "board.h" -#include "common.h" -#include "iomap.h" - -static void __init tegra30_dt_init(void) -{ - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -} - -static const char *tegra30_dt_board_compat[] = { - "nvidia,tegra30", - NULL -}; - -DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)") - .smp = smp_ops(tegra_smp_ops), - .map_io = tegra_map_common_io, - .init_early = tegra30_init_early, - .init_irq = tegra_dt_init_irq, - .init_time = clocksource_of_init, - .init_machine = tegra30_dt_init, - .init_late = tegra_init_late, - .restart = tegra_assert_system_reset, - .dt_compat = tegra30_dt_board_compat, -MACHINE_END diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c index 3cdc1bb8254c..035b240b9e15 100644 --- a/arch/arm/mach-tegra/board-harmony-pcie.c +++ b/arch/arm/mach-tegra/board-harmony-pcie.c @@ -56,13 +56,17 @@ int __init harmony_pcie_init(void) gpio_direction_output(en_vdd_1v05, 1); regulator = regulator_get(NULL, "vdd_ldo0,vddio_pex_clk"); - if (IS_ERR_OR_NULL(regulator)) { - pr_err("%s: regulator_get failed: %d\n", __func__, - (int)PTR_ERR(regulator)); + if (IS_ERR(regulator)) { + err = PTR_ERR(regulator); + pr_err("%s: regulator_get failed: %d\n", __func__, err); goto err_reg; } - regulator_enable(regulator); + err = regulator_enable(regulator); + if (err) { + pr_err("%s: regulator_enable failed: %d\n", __func__, err); + goto err_en; + } err = tegra_pcie_init(true, true); if (err) { @@ -74,6 +78,7 @@ int __init harmony_pcie_init(void) err_pcie: regulator_disable(regulator); +err_en: regulator_put(regulator); err_reg: gpio_free(en_vdd_1v05); diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index 86851c81a350..60431de585ca 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -26,9 +26,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_init_early(void); void __init tegra_map_common_io(void); void __init tegra_init_irq(void); void __init tegra_dt_init_irq(void); diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 5449a3f2977b..eb1f3c8c74cc 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -33,6 +33,7 @@ #include "common.h" #include "fuse.h" #include "iomap.h" +#include "irq.h" #include "pmc.h" #include "apbio.h" #include "sleep.h" @@ -61,8 +62,10 @@ u32 tegra_uart_config[4] = { void __init tegra_dt_init_irq(void) { tegra_clocks_init(); + tegra_pmc_init(); tegra_init_irq(); irqchip_init(); + tegra_legacy_irq_syscore_init(); } #endif @@ -94,40 +97,18 @@ static void __init tegra_init_cache(void) } -static void __init tegra_init_early(void) +void __init tegra_init_early(void) { tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); tegra_init_cache(); - tegra_pmc_init(); tegra_powergate_init(); + tegra_hotplug_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_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_init_suspend(); tegra_powergate_debugfs_init(); } diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 825ced4f7a40..8bbbdebed882 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -130,10 +130,6 @@ 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(); @@ -142,7 +138,7 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev, clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); - tegra_idle_lp2_last(cpu_on_time, cpu_off_time); + tegra_idle_lp2_last(); clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 8b50cf4ddd6f..c0931c8bb3e5 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -72,10 +72,6 @@ static bool tegra30_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; - /* All CPUs entering LP2 is not working. * Don't let CPU0 enter LP2 when any secondary CPU is online. */ @@ -86,7 +82,7 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); - tegra_idle_lp2_last(cpu_on_time, cpu_off_time); + tegra_idle_lp2_last(); clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); @@ -102,12 +98,8 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, smp_wmb(); - save_cpu_arch_register(); - cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); - restore_cpu_arch_register(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); return true; diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index f7db0782a6b6..e035cd284a6e 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -2,6 +2,7 @@ * arch/arm/mach-tegra/fuse.c * * Copyright (C) 2010 Google, Inc. + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross <ccross@android.com> @@ -137,6 +138,9 @@ void tegra_init_fuse(void) tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT; tegra_init_speedo_data = &tegra30_init_speedo_data; break; + case TEGRA114: + tegra_init_speedo_data = &tegra114_init_speedo_data; + break; default: pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id); tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index da78434678c7..aacc00d05980 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Google, Inc. + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross <ccross@android.com> @@ -66,4 +67,10 @@ void tegra30_init_speedo_data(void); static inline void tegra30_init_speedo_data(void) {} #endif +#ifdef CONFIG_ARCH_TEGRA_114_SOC +void tegra114_init_speedo_data(void); +#else +static inline void tegra114_init_speedo_data(void) {} +#endif + #endif diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index fd473f2b4c3d..045c16f2dd51 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S @@ -7,8 +7,5 @@ ENTRY(tegra_secondary_startup) bl v7_invalidate_l1 - /* Enable coresight */ - mov32 r0, 0xC5ACCE55 - mcr p14, 0, r0, c7, c12, 6 b secondary_startup ENDPROC(tegra_secondary_startup) diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index a599f6e36dea..8da9f78475da 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -1,8 +1,7 @@ /* - * * Copyright (C) 2002 ARM Ltd. * All Rights Reserved - * Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved. + * Copyright (c) 2010, 2012-2013, 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 version 2 as @@ -15,6 +14,7 @@ #include <asm/cacheflush.h> #include <asm/smp_plat.h> +#include "fuse.h" #include "sleep.h" static void (*tegra_hotplug_shutdown)(void); @@ -56,18 +56,13 @@ int tegra_cpu_disable(unsigned int cpu) return cpu == 0 ? -EPERM : 0; } -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -extern void tegra20_hotplug_shutdown(void); -void __init tegra20_hotplug_init(void) +void __init tegra_hotplug_init(void) { - tegra_hotplug_shutdown = tegra20_hotplug_shutdown; -} -#endif + if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) + return; -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -extern void tegra30_hotplug_shutdown(void); -void __init tegra30_hotplug_init(void) -{ - tegra_hotplug_shutdown = tegra30_hotplug_shutdown; + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) + tegra_hotplug_shutdown = tegra20_hotplug_shutdown; + if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) + tegra_hotplug_shutdown = tegra30_hotplug_shutdown; } -#endif diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 1952e82797cc..0de4eed1493d 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -4,7 +4,7 @@ * Author: * Colin Cross <ccross@android.com> * - * Copyright (C) 2010, NVIDIA Corporation + * Copyright (C) 2010,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 @@ -23,6 +23,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/irqchip/arm-gic.h> +#include <linux/syscore_ops.h> #include "board.h" #include "iomap.h" @@ -43,6 +44,7 @@ #define ICTLR_COP_IEP_CLASS 0x3c #define FIRST_LEGACY_IRQ 32 +#define TEGRA_MAX_NUM_ICTLRS 5 #define SGI_MASK 0xFFFF @@ -56,6 +58,15 @@ static void __iomem *ictlr_reg_base[] = { IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE), }; +#ifdef CONFIG_PM_SLEEP +static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS]; +static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS]; +static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS]; +static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS]; + +static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS]; +#endif + bool tegra_pending_sgi(void) { u32 pending_set; @@ -125,6 +136,87 @@ static int tegra_retrigger(struct irq_data *d) return 1; } +#ifdef CONFIG_PM_SLEEP +static int tegra_set_wake(struct irq_data *d, unsigned int enable) +{ + u32 irq = d->irq; + u32 index, mask; + + if (irq < FIRST_LEGACY_IRQ || + irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32) + return -EINVAL; + + index = ((irq - FIRST_LEGACY_IRQ) / 32); + mask = BIT((irq - FIRST_LEGACY_IRQ) % 32); + if (enable) + ictlr_wake_mask[index] |= mask; + else + ictlr_wake_mask[index] &= ~mask; + + return 0; +} + +static int tegra_legacy_irq_suspend(void) +{ + unsigned long flags; + int i; + + local_irq_save(flags); + for (i = 0; i < num_ictlrs; i++) { + void __iomem *ictlr = ictlr_reg_base[i]; + /* Save interrupt state */ + cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER); + cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS); + cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER); + cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS); + + /* Disable COP interrupts */ + writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR); + + /* Disable CPU interrupts */ + writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR); + + /* Enable the wakeup sources of ictlr */ + writel_relaxed(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET); + } + local_irq_restore(flags); + + return 0; +} + +static void tegra_legacy_irq_resume(void) +{ + unsigned long flags; + int i; + + local_irq_save(flags); + for (i = 0; i < num_ictlrs; i++) { + void __iomem *ictlr = ictlr_reg_base[i]; + writel_relaxed(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS); + writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR); + writel_relaxed(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET); + writel_relaxed(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS); + writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR); + writel_relaxed(cop_ier[i], ictlr + ICTLR_COP_IER_SET); + } + local_irq_restore(flags); +} + +static struct syscore_ops tegra_legacy_irq_syscore_ops = { + .suspend = tegra_legacy_irq_suspend, + .resume = tegra_legacy_irq_resume, +}; + +int tegra_legacy_irq_syscore_init(void) +{ + register_syscore_ops(&tegra_legacy_irq_syscore_ops); + + return 0; +} +#else +#define tegra_set_wake NULL +#endif + void __init tegra_init_irq(void) { int i; @@ -150,6 +242,8 @@ void __init tegra_init_irq(void) gic_arch_extn.irq_mask = tegra_mask; gic_arch_extn.irq_unmask = tegra_unmask; gic_arch_extn.irq_retrigger = tegra_retrigger; + gic_arch_extn.irq_set_wake = tegra_set_wake; + gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND; /* * Check if there is a devicetree present, since the GIC will be diff --git a/arch/arm/mach-tegra/irq.h b/arch/arm/mach-tegra/irq.h index 5142649bba05..bc05ce5613fb 100644 --- a/arch/arm/mach-tegra/irq.h +++ b/arch/arm/mach-tegra/irq.h @@ -19,4 +19,10 @@ bool tegra_pending_sgi(void); +#ifdef CONFIG_PM_SLEEP +int tegra_legacy_irq_syscore_init(void); +#else +static inline int tegra_legacy_irq_syscore_init(void) { return 0; } +#endif + #endif diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 2c6b3d55213b..516aab28fe34 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -26,22 +26,16 @@ #include <asm/smp_scu.h> #include <asm/smp_plat.h> -#include <mach/powergate.h> - #include "fuse.h" #include "flowctrl.h" #include "reset.h" +#include "pmc.h" #include "common.h" #include "iomap.h" -extern void tegra_secondary_startup(void); - static cpumask_t tegra_cpu_init_mask; -#define EVP_CPU_RESET_VECTOR \ - (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) - static void __cpuinit tegra_secondary_init(unsigned int cpu) { /* @@ -54,25 +48,43 @@ static void __cpuinit tegra_secondary_init(unsigned int cpu) cpumask_set_cpu(cpu, &tegra_cpu_init_mask); } -static int tegra20_power_up_cpu(unsigned int cpu) + +static int tegra20_boot_secondary(unsigned int cpu, struct task_struct *idle) { - /* Enable the CPU clock. */ - tegra_enable_cpu_clock(cpu); + cpu = cpu_logical_map(cpu); + + /* + * Force the CPU into reset. The CPU must remain in reset when + * the flow controller state is cleared (which will cause the + * flow controller to stop driving reset if the CPU has been + * power-gated via the flow controller). This will have no + * effect on first boot of the CPU since it should already be + * in reset. + */ + tegra_put_cpu_in_reset(cpu); - /* Clear flow controller CSR. */ - flowctrl_write_cpu_csr(cpu, 0); + /* + * Unhalt the CPU. If the flow controller was used to + * power-gate the CPU this will cause the flow controller to + * stop driving reset. The CPU will remain in reset because the + * clock and reset block is now driving reset. + */ + flowctrl_write_cpu_halt(cpu, 0); + tegra_enable_cpu_clock(cpu); + flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ + tegra_cpu_out_of_reset(cpu); return 0; } -static int tegra30_power_up_cpu(unsigned int cpu) +static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle) { - int ret, pwrgateid; + int ret; unsigned long timeout; - pwrgateid = tegra_cpu_powergate_id(cpu); - if (pwrgateid < 0) - return pwrgateid; + cpu = cpu_logical_map(cpu); + tegra_put_cpu_in_reset(cpu); + flowctrl_write_cpu_halt(cpu, 0); /* * The power up sequence of cold boot CPU and warm boot CPU @@ -85,13 +97,13 @@ static int tegra30_power_up_cpu(unsigned int cpu) * the IO clamps. * For cold boot CPU, do not wait. After the cold boot CPU be * booted, it will run to tegra_secondary_init() and set - * tegra_cpu_init_mask which influences what tegra30_power_up_cpu() + * tegra_cpu_init_mask which influences what tegra30_boot_secondary() * next time around. */ if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { timeout = jiffies + msecs_to_jiffies(50); do { - if (!tegra_powergate_is_powered(pwrgateid)) + if (tegra_pmc_cpu_is_powered(cpu)) goto remove_clamps; udelay(10); } while (time_before(jiffies, timeout)); @@ -103,14 +115,14 @@ static int tegra30_power_up_cpu(unsigned int cpu) * be un-gated by un-toggling the power gate register * manually. */ - if (!tegra_powergate_is_powered(pwrgateid)) { - ret = tegra_powergate_power_on(pwrgateid); + if (!tegra_pmc_cpu_is_powered(cpu)) { + ret = tegra_pmc_cpu_power_on(cpu); if (ret) return ret; /* Wait for the power to come up. */ timeout = jiffies + msecs_to_jiffies(100); - while (tegra_powergate_is_powered(pwrgateid)) { + while (tegra_pmc_cpu_is_powered(cpu)) { if (time_after(jiffies, timeout)) return -ETIMEDOUT; udelay(10); @@ -123,57 +135,34 @@ remove_clamps: udelay(10); /* Remove I/O clamps. */ - ret = tegra_powergate_remove_clamping(pwrgateid); - udelay(10); + ret = tegra_pmc_cpu_remove_clamping(cpu); + if (ret) + return ret; - /* Clear flow controller CSR. */ - flowctrl_write_cpu_csr(cpu, 0); + udelay(10); + flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ + tegra_cpu_out_of_reset(cpu); return 0; } -static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *idle) +static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle) { - int status; - cpu = cpu_logical_map(cpu); + return tegra_pmc_cpu_power_on(cpu); +} - /* - * Force the CPU into reset. The CPU must remain in reset when the - * flow controller state is cleared (which will cause the flow - * controller to stop driving reset if the CPU has been power-gated - * via the flow controller). This will have no effect on first boot - * of the CPU since it should already be in reset. - */ - tegra_put_cpu_in_reset(cpu); - - /* - * Unhalt the CPU. If the flow controller was used to power-gate the - * CPU this will cause the flow controller to stop driving reset. - * The CPU will remain in reset because the clock and reset block - * is now driving reset. - */ - flowctrl_write_cpu_halt(cpu, 0); - - switch (tegra_chip_id) { - case TEGRA20: - status = tegra20_power_up_cpu(cpu); - break; - case TEGRA30: - status = tegra30_power_up_cpu(cpu); - break; - default: - status = -EINVAL; - break; - } - - if (status) - goto done; - - /* Take the CPU out of reset. */ - tegra_cpu_out_of_reset(cpu); -done: - return status; +static int __cpuinit tegra_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) + return tegra20_boot_secondary(cpu, idle); + if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) + return tegra30_boot_secondary(cpu, idle); + if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114) + return tegra114_boot_secondary(cpu, idle); + + return -EINVAL; } static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 523604de666f..d0b7400e4606 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -22,7 +22,7 @@ #include <linux/cpumask.h> #include <linux/delay.h> #include <linux/cpu_pm.h> -#include <linux/clk.h> +#include <linux/suspend.h> #include <linux/err.h> #include <linux/clk/tegra.h> @@ -37,67 +37,13 @@ #include "reset.h" #include "flowctrl.h" #include "fuse.h" +#include "pmc.h" #include "sleep.h" -#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ - -#define PMC_CTRL 0x0 -#define PMC_CPUPWRGOOD_TIMER 0xc8 -#define PMC_CPUPWROFF_TIMER 0xcc - #ifdef CONFIG_PM_SLEEP -static unsigned int g_diag_reg; static DEFINE_SPINLOCK(tegra_lp2_lock); -static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); -static struct clk *tegra_pclk; void (*tegra_tear_down_cpu)(void); -void save_cpu_arch_register(void) -{ - /* read diagnostic register */ - asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc"); - return; -} - -void restore_cpu_arch_register(void) -{ - /* write diagnostic register */ - asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc"); - return; -} - -static void set_power_timers(unsigned long us_on, unsigned long us_off) -{ - unsigned long long ticks; - unsigned long long pclk; - unsigned long rate; - static unsigned long tegra_last_pclk; - - if (tegra_pclk == NULL) { - tegra_pclk = clk_get_sys(NULL, "pclk"); - WARN_ON(IS_ERR(tegra_pclk)); - } - - rate = clk_get_rate(tegra_pclk); - - if (WARN_ON_ONCE(rate <= 0)) - pclk = 100000000; - else - pclk = rate; - - if ((rate != tegra_last_pclk)) { - ticks = (us_on * pclk) + 999999ull; - do_div(ticks, 1000000); - writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER); - - ticks = (us_off * pclk) + 999999ull; - do_div(ticks, 1000000); - writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER); - wmb(); - } - tegra_last_pclk = pclk; -} - /* * restore_cpu_complex * @@ -119,8 +65,6 @@ static void restore_cpu_complex(void) tegra_cpu_clock_resume(); flowctrl_cpu_suspend_exit(cpu); - - restore_cpu_arch_register(); } /* @@ -145,8 +89,6 @@ static void suspend_cpu_complex(void) tegra_cpu_clock_suspend(); flowctrl_cpu_suspend_enter(cpu); - - save_cpu_arch_register(); } void tegra_clear_cpu_in_lp2(int phy_cpu_id) @@ -197,16 +139,9 @@ static int tegra_sleep_cpu(unsigned long v2p) return 0; } -void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time) +void tegra_idle_lp2_last(void) { - u32 mode; - - /* Only the last cpu down does the final suspend steps */ - mode = readl(pmc + PMC_CTRL); - mode |= TEGRA_POWER_CPU_PWRREQ_OE; - writel(mode, pmc + PMC_CTRL); - - set_power_timers(cpu_on_time, cpu_off_time); + tegra_pmc_pm_set(TEGRA_SUSPEND_LP2); cpu_cluster_pm_enter(); suspend_cpu_complex(); @@ -216,4 +151,81 @@ void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time) restore_cpu_complex(); cpu_cluster_pm_exit(); } + +enum tegra_suspend_mode tegra_pm_validate_suspend_mode( + enum tegra_suspend_mode mode) +{ + /* Tegra114 didn't support any suspending mode yet. */ + if (tegra_chip_id == TEGRA114) + return TEGRA_SUSPEND_NONE; + + /* + * The Tegra devices only support suspending to LP2 currently. + */ + if (mode > TEGRA_SUSPEND_LP2) + return TEGRA_SUSPEND_LP2; + + return mode; +} + +static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = { + [TEGRA_SUSPEND_NONE] = "none", + [TEGRA_SUSPEND_LP2] = "LP2", + [TEGRA_SUSPEND_LP1] = "LP1", + [TEGRA_SUSPEND_LP0] = "LP0", +}; + +static int __cpuinit tegra_suspend_enter(suspend_state_t state) +{ + enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode(); + + if (WARN_ON(mode < TEGRA_SUSPEND_NONE || + mode >= TEGRA_MAX_SUSPEND_MODE)) + return -EINVAL; + + pr_info("Entering suspend state %s\n", lp_state[mode]); + + tegra_pmc_pm_set(mode); + + local_fiq_disable(); + + suspend_cpu_complex(); + switch (mode) { + case TEGRA_SUSPEND_LP2: + tegra_set_cpu_in_lp2(0); + break; + default: + break; + } + + cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); + + switch (mode) { + case TEGRA_SUSPEND_LP2: + tegra_clear_cpu_in_lp2(0); + break; + default: + break; + } + restore_cpu_complex(); + + local_fiq_enable(); + + return 0; +} + +static const struct platform_suspend_ops tegra_suspend_ops = { + .valid = suspend_valid_only_mem, + .enter = tegra_suspend_enter, +}; + +void __init tegra_init_suspend(void) +{ + if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE) + return; + + tegra_pmc_suspend_init(); + + suspend_set_ops(&tegra_suspend_ops); +} #endif diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h index 787335cc964c..9d2d038bf12e 100644 --- a/arch/arm/mach-tegra/pm.h +++ b/arch/arm/mach-tegra/pm.h @@ -21,6 +21,8 @@ #ifndef _MACH_TEGRA_PM_H_ #define _MACH_TEGRA_PM_H_ +#include "pmc.h" + extern unsigned long l2x0_saved_regs_addr; void save_cpu_arch_register(void); @@ -29,7 +31,20 @@ void restore_cpu_arch_register(void); void tegra_clear_cpu_in_lp2(int phy_cpu_id); bool tegra_set_cpu_in_lp2(int phy_cpu_id); -void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time); +void tegra_idle_lp2_last(void); extern void (*tegra_tear_down_cpu)(void); +#ifdef CONFIG_PM_SLEEP +enum tegra_suspend_mode tegra_pm_validate_suspend_mode( + enum tegra_suspend_mode mode); +void tegra_init_suspend(void); +#else +enum tegra_suspend_mode tegra_pm_validate_suspend_mode( + enum tegra_suspend_mode mode) +{ + return TEGRA_SUSPEND_NONE; +} +static inline void tegra_init_suspend(void) {} +#endif + #endif /* _MACH_TEGRA_PM_H_ */ diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index d4fdb5fcec20..32360e540ce6 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2012,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, @@ -16,59 +16,313 @@ */ #include <linux/kernel.h> +#include <linux/clk.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/of_address.h> -#include "iomap.h" +#include "fuse.h" +#include "pm.h" +#include "pmc.h" +#include "sleep.h" -#define PMC_CTRL 0x0 -#define PMC_CTRL_INTR_LOW (1 << 17) +#define TEGRA_POWER_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */ +#define TEGRA_POWER_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ +#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ + +#define PMC_CTRL 0x0 +#define PMC_CTRL_INTR_LOW (1 << 17) +#define PMC_PWRGATE_TOGGLE 0x30 +#define PMC_PWRGATE_TOGGLE_START (1 << 8) +#define PMC_REMOVE_CLAMPING 0x34 +#define PMC_PWRGATE_STATUS 0x38 + +#define PMC_CPUPWRGOOD_TIMER 0xc8 +#define PMC_CPUPWROFF_TIMER 0xcc + +#define TEGRA_POWERGATE_PCIE 3 +#define TEGRA_POWERGATE_VDEC 4 +#define TEGRA_POWERGATE_CPU1 9 +#define TEGRA_POWERGATE_CPU2 10 +#define TEGRA_POWERGATE_CPU3 11 + +static u8 tegra_cpu_domains[] = { + 0xFF, /* not available for CPU0 */ + TEGRA_POWERGATE_CPU1, + TEGRA_POWERGATE_CPU2, + TEGRA_POWERGATE_CPU3, +}; +static DEFINE_SPINLOCK(tegra_powergate_lock); + +static void __iomem *tegra_pmc_base; +static bool tegra_pmc_invert_interrupt; +static struct clk *tegra_pclk; + +struct pmc_pm_data { + u32 cpu_good_time; /* CPU power good time in uS */ + u32 cpu_off_time; /* CPU power off time in uS */ + u32 core_osc_time; /* Core power good osc time in uS */ + u32 core_pmu_time; /* Core power good pmu time in uS */ + u32 core_off_time; /* Core power off time in uS */ + bool corereq_high; /* Core power request active-high */ + bool sysclkreq_high; /* System clock request active-high */ + bool combined_req; /* Combined pwr req for CPU & Core */ + bool cpu_pwr_good_en; /* CPU power good signal is enabled */ + u32 lp0_vec_phy_addr; /* The phy addr of LP0 warm boot code */ + u32 lp0_vec_size; /* The size of LP0 warm boot code */ + enum tegra_suspend_mode suspend_mode; +}; +static struct pmc_pm_data pmc_pm_data; static inline u32 tegra_pmc_readl(u32 reg) { - return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg)); + return readl(tegra_pmc_base + reg); } static inline void tegra_pmc_writel(u32 val, u32 reg) { - writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg)); + writel(val, tegra_pmc_base + reg); +} + +static int tegra_pmc_get_cpu_powerdomain_id(int cpuid) +{ + if (cpuid <= 0 || cpuid >= num_possible_cpus()) + return -EINVAL; + return tegra_cpu_domains[cpuid]; +} + +static bool tegra_pmc_powergate_is_powered(int id) +{ + return (tegra_pmc_readl(PMC_PWRGATE_STATUS) >> id) & 1; +} + +static int tegra_pmc_powergate_set(int id, bool new_state) +{ + bool old_state; + unsigned long flags; + + spin_lock_irqsave(&tegra_powergate_lock, flags); + + old_state = tegra_pmc_powergate_is_powered(id); + WARN_ON(old_state == new_state); + + tegra_pmc_writel(PMC_PWRGATE_TOGGLE_START | id, PMC_PWRGATE_TOGGLE); + + spin_unlock_irqrestore(&tegra_powergate_lock, flags); + + return 0; +} + +static int tegra_pmc_powergate_remove_clamping(int id) +{ + u32 mask; + + /* + * Tegra has a bug where PCIE and VDE clamping masks are + * swapped relatively to the partition ids. + */ + if (id == TEGRA_POWERGATE_VDEC) + mask = (1 << TEGRA_POWERGATE_PCIE); + else if (id == TEGRA_POWERGATE_PCIE) + mask = (1 << TEGRA_POWERGATE_VDEC); + else + mask = (1 << id); + + tegra_pmc_writel(mask, PMC_REMOVE_CLAMPING); + + return 0; +} + +bool tegra_pmc_cpu_is_powered(int cpuid) +{ + int id; + + id = tegra_pmc_get_cpu_powerdomain_id(cpuid); + if (id < 0) + return false; + return tegra_pmc_powergate_is_powered(id); } -#ifdef CONFIG_OF +int tegra_pmc_cpu_power_on(int cpuid) +{ + int id; + + id = tegra_pmc_get_cpu_powerdomain_id(cpuid); + if (id < 0) + return id; + return tegra_pmc_powergate_set(id, true); +} + +int tegra_pmc_cpu_remove_clamping(int cpuid) +{ + int id; + + id = tegra_pmc_get_cpu_powerdomain_id(cpuid); + if (id < 0) + return id; + return tegra_pmc_powergate_remove_clamping(id); +} + +#ifdef CONFIG_PM_SLEEP +static void set_power_timers(u32 us_on, u32 us_off, unsigned long rate) +{ + unsigned long long ticks; + unsigned long long pclk; + static unsigned long tegra_last_pclk; + + if (WARN_ON_ONCE(rate <= 0)) + pclk = 100000000; + else + pclk = rate; + + if ((rate != tegra_last_pclk)) { + ticks = (us_on * pclk) + 999999ull; + do_div(ticks, 1000000); + tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWRGOOD_TIMER); + + ticks = (us_off * pclk) + 999999ull; + do_div(ticks, 1000000); + tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWROFF_TIMER); + wmb(); + } + tegra_last_pclk = pclk; +} + +enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) +{ + return pmc_pm_data.suspend_mode; +} + +void tegra_pmc_pm_set(enum tegra_suspend_mode mode) +{ + u32 reg; + unsigned long rate = 0; + + reg = tegra_pmc_readl(PMC_CTRL); + reg |= TEGRA_POWER_CPU_PWRREQ_OE; + reg &= ~TEGRA_POWER_EFFECT_LP0; + + switch (mode) { + case TEGRA_SUSPEND_LP2: + rate = clk_get_rate(tegra_pclk); + break; + default: + break; + } + + set_power_timers(pmc_pm_data.cpu_good_time, pmc_pm_data.cpu_off_time, + rate); + + tegra_pmc_writel(reg, PMC_CTRL); +} + +void tegra_pmc_suspend_init(void) +{ + u32 reg; + + /* Always enable CPU power request */ + reg = tegra_pmc_readl(PMC_CTRL); + reg |= TEGRA_POWER_CPU_PWRREQ_OE; + tegra_pmc_writel(reg, PMC_CTRL); +} +#endif + static const struct of_device_id matches[] __initconst = { + { .compatible = "nvidia,tegra114-pmc" }, + { .compatible = "nvidia,tegra30-pmc" }, { .compatible = "nvidia,tegra20-pmc" }, { } }; -#endif -void __init tegra_pmc_init(void) +static void tegra_pmc_parse_dt(void) { - /* - * For now, Harmony is the only board that uses the PMC, and it wants - * the signal inverted. Seaboard would too if it used the PMC. - * Hopefully by the time other boards want to use the PMC, everything - * will be device-tree, or they also want it inverted. - */ - bool invert_interrupt = true; - u32 val; + struct device_node *np; + u32 prop; + enum tegra_suspend_mode suspend_mode; + u32 core_good_time[2] = {0, 0}; + u32 lp0_vec[2] = {0, 0}; -#ifdef CONFIG_OF - if (of_have_populated_dt()) { - struct device_node *np; + np = of_find_matching_node(NULL, matches); + BUG_ON(!np); - invert_interrupt = false; + tegra_pmc_base = of_iomap(np, 0); - np = of_find_matching_node(NULL, matches); - if (np) { - if (of_find_property(np, "nvidia,invert-interrupt", - NULL)) - invert_interrupt = true; + tegra_pmc_invert_interrupt = of_property_read_bool(np, + "nvidia,invert-interrupt"); + tegra_pclk = of_clk_get_by_name(np, "pclk"); + WARN_ON(IS_ERR(tegra_pclk)); + + /* Grabbing the power management configurations */ + if (of_property_read_u32(np, "nvidia,suspend-mode", &prop)) { + suspend_mode = TEGRA_SUSPEND_NONE; + } else { + switch (prop) { + case 0: + suspend_mode = TEGRA_SUSPEND_LP0; + break; + case 1: + suspend_mode = TEGRA_SUSPEND_LP1; + break; + case 2: + suspend_mode = TEGRA_SUSPEND_LP2; + break; + default: + suspend_mode = TEGRA_SUSPEND_NONE; + break; } } -#endif + suspend_mode = tegra_pm_validate_suspend_mode(suspend_mode); + + if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &prop)) + suspend_mode = TEGRA_SUSPEND_NONE; + pmc_pm_data.cpu_good_time = prop; + + if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &prop)) + suspend_mode = TEGRA_SUSPEND_NONE; + pmc_pm_data.cpu_off_time = prop; + + if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time", + core_good_time, ARRAY_SIZE(core_good_time))) + suspend_mode = TEGRA_SUSPEND_NONE; + pmc_pm_data.core_osc_time = core_good_time[0]; + pmc_pm_data.core_pmu_time = core_good_time[1]; + + if (of_property_read_u32(np, "nvidia,core-pwr-off-time", + &prop)) + suspend_mode = TEGRA_SUSPEND_NONE; + pmc_pm_data.core_off_time = prop; + + pmc_pm_data.corereq_high = of_property_read_bool(np, + "nvidia,core-power-req-active-high"); + + pmc_pm_data.sysclkreq_high = of_property_read_bool(np, + "nvidia,sys-clock-req-active-high"); + + pmc_pm_data.combined_req = of_property_read_bool(np, + "nvidia,combined-power-req"); + + pmc_pm_data.cpu_pwr_good_en = of_property_read_bool(np, + "nvidia,cpu-pwr-good-en"); + + if (of_property_read_u32_array(np, "nvidia,lp0-vec", lp0_vec, + ARRAY_SIZE(lp0_vec))) + if (suspend_mode == TEGRA_SUSPEND_LP0) + suspend_mode = TEGRA_SUSPEND_LP1; + + pmc_pm_data.lp0_vec_phy_addr = lp0_vec[0]; + pmc_pm_data.lp0_vec_size = lp0_vec[1]; + + pmc_pm_data.suspend_mode = suspend_mode; +} + +void __init tegra_pmc_init(void) +{ + u32 val; + + tegra_pmc_parse_dt(); val = tegra_pmc_readl(PMC_CTRL); - if (invert_interrupt) + if (tegra_pmc_invert_interrupt) val |= PMC_CTRL_INTR_LOW; else val &= ~PMC_CTRL_INTR_LOW; diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h index 8995ee4a8768..e1c2df272f7d 100644 --- a/arch/arm/mach-tegra/pmc.h +++ b/arch/arm/mach-tegra/pmc.h @@ -18,6 +18,24 @@ #ifndef __MACH_TEGRA_PMC_H #define __MACH_TEGRA_PMC_H +enum tegra_suspend_mode { + TEGRA_SUSPEND_NONE = 0, + TEGRA_SUSPEND_LP2, /* CPU voltage off */ + TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */ + TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */ + TEGRA_MAX_SUSPEND_MODE, +}; + +#ifdef CONFIG_PM_SLEEP +enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void); +void tegra_pmc_pm_set(enum tegra_suspend_mode mode); +void tegra_pmc_suspend_init(void); +#endif + +bool tegra_pmc_cpu_is_powered(int cpuid); +int tegra_pmc_cpu_power_on(int cpuid); +int tegra_pmc_cpu_remove_clamping(int cpuid); + void tegra_pmc_init(void); #endif diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index 54382ceade4a..1676aba5e7b8 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S @@ -41,9 +41,6 @@ */ ENTRY(tegra_resume) bl v7_invalidate_l1 - /* Enable coresight */ - mov32 r0, 0xC5ACCE55 - mcr p14, 0, r0, c7, c12, 6 cpu_id r0 cmp r0, #0 @ CPU0? @@ -99,6 +96,8 @@ ENTRY(__tegra_cpu_reset_handler_start) * * Register usage within the reset handler: * + * Others: scratch + * R6 = SoC ID << 8 * R7 = CPU present (to the OS) mask * R8 = CPU in LP1 state mask * R9 = CPU in LP2 state mask @@ -114,6 +113,40 @@ ENTRY(__tegra_cpu_reset_handler_start) ENTRY(__tegra_cpu_reset_handler) cpsid aif, 0x13 @ SVC mode, interrupts disabled + + mov32 r6, TEGRA_APB_MISC_BASE + ldr r6, [r6, #APB_MISC_GP_HIDREV] + and r6, r6, #0xff00 +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +t20_check: + cmp r6, #(0x20 << 8) + bne after_t20_check +t20_errata: + # Tegra20 is a Cortex-A9 r1p1 + mrc p15, 0, r0, c1, c0, 0 @ read system control register + orr r0, r0, #1 << 14 @ erratum 716044 + mcr p15, 0, r0, c1, c0, 0 @ write system control register + mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register + orr r0, r0, #1 << 4 @ erratum 742230 + orr r0, r0, #1 << 11 @ erratum 751472 + mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register + b after_errata +after_t20_check: +#endif +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +t30_check: + cmp r6, #(0x30 << 8) + bne after_t30_check +t30_errata: + # Tegra30 is a Cortex-A9 r2p9 + mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register + orr r0, r0, #1 << 6 @ erratum 743622 + orr r0, r0, #1 << 11 @ erratum 751472 + mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register + b after_errata +after_t30_check: +#endif +after_errata: mrc p15, 0, r10, c0, c0, 5 @ MPIDR and r10, r10, #0x3 @ R10 = CPU number mov r11, #1 @@ -129,16 +162,13 @@ ENTRY(__tegra_cpu_reset_handler) #ifdef CONFIG_ARCH_TEGRA_2x_SOC /* Are we on Tegra20? */ - mov32 r6, TEGRA_APB_MISC_BASE - ldr r0, [r6, #APB_MISC_GP_HIDREV] - and r0, r0, #0xff00 - cmp r0, #(0x20 << 8) + cmp r6, #(0x20 << 8) bne 1f /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ - mov32 r6, TEGRA_PMC_BASE + mov32 r5, TEGRA_PMC_BASE mov r0, #0 cmp r10, #0 - strne r0, [r6, #PMC_SCRATCH41] + strne r0, [r5, #PMC_SCRATCH41] 1: #endif diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h index 4ffae541726e..970ebd5138b9 100644 --- a/arch/arm/mach-tegra/sleep.h +++ b/arch/arm/mach-tegra/sleep.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2010-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, @@ -124,11 +124,11 @@ int tegra_sleep_cpu_finish(unsigned long); void tegra_disable_clean_inv_dcache(void); #ifdef CONFIG_HOTPLUG_CPU -void tegra20_hotplug_init(void); -void tegra30_hotplug_init(void); +void tegra20_hotplug_shutdown(void); +void tegra30_hotplug_shutdown(void); +void tegra_hotplug_init(void); #else -static inline void tegra20_hotplug_init(void) {} -static inline void tegra30_hotplug_init(void) {} +static inline void tegra_hotplug_init(void) {} #endif void tegra20_cpu_shutdown(int cpu); diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/tegra.c index a0edf2510280..61749e2d8111 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/tegra.c @@ -1,6 +1,7 @@ /* - * nVidia Tegra device tree board support + * NVIDIA Tegra SoC device tree board support * + * Copyright (C) 2011, 2013, NVIDIA Corporation * Copyright (C) 2010 Secret Lab Technologies, Ltd. * Copyright (C) 2010 Google, Inc. * @@ -32,7 +33,10 @@ #include <linux/io.h> #include <linux/i2c.h> #include <linux/i2c-tegra.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> #include <linux/usb/tegra_usb_phy.h> +#include <linux/clk/tegra.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -41,6 +45,7 @@ #include "board.h" #include "common.h" +#include "fuse.h" #include "iomap.h" static struct tegra_ehci_platform_data tegra_ehci1_pdata = { @@ -79,12 +84,38 @@ static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { static void __init tegra_dt_init(void) { + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + struct device *parent = NULL; + + tegra_clocks_apply_init_table(); + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + goto out; + + soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra"); + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision); + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->family); + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr->soc_id); + kfree(soc_dev_attr); + goto out; + } + + parent = soc_device_to_device(soc_dev); + /* * Finished with the static registrations now; fill in the missing * devices */ +out: of_platform_populate(NULL, of_default_bus_match_table, - tegra20_auxdata_lookup, NULL); + tegra20_auxdata_lookup, parent); } static void __init trimslice_init(void) @@ -111,7 +142,8 @@ static void __init harmony_init(void) static void __init paz00_init(void) { - tegra_paz00_wifikill_init(); + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) + tegra_paz00_wifikill_init(); } static struct { @@ -137,19 +169,21 @@ static void __init tegra_dt_init_late(void) } } -static const char *tegra20_dt_board_compat[] = { +static const char * const tegra_dt_board_compat[] = { + "nvidia,tegra114", + "nvidia,tegra30", "nvidia,tegra20", NULL }; -DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)") +DT_MACHINE_START(TEGRA_DT, "NVIDIA Tegra SoC (Flattened Device Tree)") .map_io = tegra_map_common_io, .smp = smp_ops(tegra_smp_ops), - .init_early = tegra20_init_early, + .init_early = tegra_init_early, .init_irq = tegra_dt_init_irq, .init_time = clocksource_of_init, .init_machine = tegra_dt_init, .init_late = tegra_dt_init_late, .restart = tegra_assert_system_reset, - .dt_compat = tegra20_dt_board_compat, + .dt_compat = tegra_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c new file mode 100644 index 000000000000..5218d4853cd3 --- /dev/null +++ b/arch/arm/mach-tegra/tegra114_speedo.c @@ -0,0 +1,104 @@ +/* + * 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/bug.h> + +#include "fuse.h" + +#define CORE_PROCESS_CORNERS_NUM 2 +#define CPU_PROCESS_CORNERS_NUM 2 + +enum { + THRESHOLD_INDEX_0, + THRESHOLD_INDEX_1, + THRESHOLD_INDEX_COUNT, +}; + +static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { + {1123, UINT_MAX}, + {0, UINT_MAX}, +}; + +static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { + {1695, UINT_MAX}, + {0, UINT_MAX}, +}; + +static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold) +{ + u32 tmp; + + switch (sku) { + case 0x00: + case 0x10: + case 0x05: + case 0x06: + tegra_cpu_speedo_id = 1; + tegra_soc_speedo_id = 0; + *threshold = THRESHOLD_INDEX_0; + break; + + case 0x03: + case 0x04: + tegra_cpu_speedo_id = 2; + tegra_soc_speedo_id = 1; + *threshold = THRESHOLD_INDEX_1; + break; + + default: + pr_err("Tegra114 Unknown SKU %d\n", sku); + tegra_cpu_speedo_id = 0; + tegra_soc_speedo_id = 0; + *threshold = THRESHOLD_INDEX_0; + break; + } + + if (rev == TEGRA_REVISION_A01) { + tmp = tegra_fuse_readl(0x270) << 1; + tmp |= tegra_fuse_readl(0x26c); + if (!tmp) + tegra_cpu_speedo_id = 0; + } +} + +void tegra114_init_speedo_data(void) +{ + u32 cpu_speedo_val; + u32 core_speedo_val; + int threshold; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != + THRESHOLD_INDEX_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != + THRESHOLD_INDEX_COUNT); + + rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold); + + cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024; + core_speedo_val = tegra_fuse_readl(0x134); + + for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) + if (cpu_speedo_val < cpu_process_speedos[threshold][i]) + break; + tegra_cpu_process_id = i; + + for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) + if (core_speedo_val < core_process_speedos[threshold][i]) + break; + tegra_core_process_id = i; +} diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index ce7ce42a1ac9..9e8bdfa2b369 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c @@ -276,7 +276,7 @@ static struct tegra_emc_pdata *tegra_emc_fill_pdata(struct platform_device *pdev int i; WARN_ON(pdev->dev.platform_data); - BUG_ON(IS_ERR_OR_NULL(c)); + BUG_ON(IS_ERR(c)); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables), diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index 0a3f30df1eb8..152ae38cd18c 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -48,8 +48,12 @@ BIAS(slpm_in_nopull_wkup, PIN_SLEEPMODE_ENABLED| PIN_SLPM_DIR_INPUT|PIN_SLPM_PULL_NONE|PIN_SLPM_WAKEUP_ENABLE); BIAS(slpm_in_wkup_pdis, PIN_SLEEPMODE_ENABLED| PIN_SLPM_DIR_INPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED); +BIAS(slpm_in_wkup_pdis_en, PIN_SLEEPMODE_ENABLED| + PIN_SLPM_DIR_INPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_ENABLED); BIAS(slpm_wkup_pdis, PIN_SLEEPMODE_ENABLED| PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED); +BIAS(slpm_wkup_pdis_en, PIN_SLEEPMODE_ENABLED| + PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_ENABLED); BIAS(slpm_out_lo_pdis, PIN_SLEEPMODE_ENABLED| PIN_SLPM_OUTPUT_LOW|PIN_SLPM_WAKEUP_DISABLE|PIN_SLPM_PDIS_DISABLED); BIAS(slpm_out_lo_wkup, PIN_SLEEPMODE_ENABLED| @@ -78,9 +82,6 @@ BIAS(out_wkup_pdis, PIN_SLPM_DIR_OUTPUT|PIN_SLPM_WAKEUP_ENABLE| PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-db8500", group, func) #define DB8500_PIN_HOG(pin,conf) \ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-db8500", pin, conf) -#define DB8500_PIN_SLEEP(pin, conf, dev) \ - PIN_MAP_CONFIGS_PIN(dev, PINCTRL_STATE_SLEEP, "pinctrl-db8500", \ - pin, conf) /* These are default states associated with device and changed runtime */ #define DB8500_MUX(group,func,dev) \ @@ -309,8 +310,23 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = { DB8500_PIN_SLEEP("GPIO207_AJ23", slpm_in_wkup_pdis, "sdi4"), /* DAT4 */ /* Mux in USB pins, drive STP high */ - DB8500_MUX("usb_a_1", "usb", "musb-ux500.0"), - DB8500_PIN("GPIO257_AE29", out_hi, "musb-ux500.0"), /* STP */ + /* USB default state */ + DB8500_MUX("usb_a_1", "usb", "ab8500-usb.0"), + DB8500_PIN("GPIO257_AE29", out_hi, "ab8500-usb.0"), /* STP */ + /* USB sleep state */ + DB8500_PIN_SLEEP("GPIO256_AF28", slpm_wkup_pdis_en, "ab8500-usb.0"), /* NXT */ + DB8500_PIN_SLEEP("GPIO257_AE29", slpm_out_hi_wkup_pdis, "ab8500-usb.0"), /* STP */ + DB8500_PIN_SLEEP("GPIO258_AD29", slpm_wkup_pdis_en, "ab8500-usb.0"), /* XCLK */ + DB8500_PIN_SLEEP("GPIO259_AC29", slpm_wkup_pdis_en, "ab8500-usb.0"), /* DIR */ + DB8500_PIN_SLEEP("GPIO260_AD28", slpm_in_wkup_pdis_en, "ab8500-usb.0"), /* DAT7 */ + DB8500_PIN_SLEEP("GPIO261_AD26", slpm_in_wkup_pdis_en, "ab8500-usb.0"), /* DAT6 */ + DB8500_PIN_SLEEP("GPIO262_AE26", slpm_in_wkup_pdis_en, "ab8500-usb.0"), /* DAT5 */ + DB8500_PIN_SLEEP("GPIO263_AG29", slpm_in_wkup_pdis_en, "ab8500-usb.0"), /* DAT4 */ + DB8500_PIN_SLEEP("GPIO264_AE27", slpm_in_wkup_pdis_en, "ab8500-usb.0"), /* DAT3 */ + DB8500_PIN_SLEEP("GPIO265_AD27", slpm_in_wkup_pdis_en, "ab8500-usb.0"), /* DAT2 */ + DB8500_PIN_SLEEP("GPIO266_AC28", slpm_in_wkup_pdis_en, "ab8500-usb.0"), /* DAT1 */ + DB8500_PIN_SLEEP("GPIO267_AC27", slpm_in_wkup_pdis_en, "ab8500-usb.0"), /* DAT0 */ + /* Mux in SPI2 pins on the "other C1" altfunction */ DB8500_MUX("spi2_oc1_2", "spi2", "spi2"), DB8500_PIN("GPIO216_AG12", gpio_out_hi, "spi2"), /* FRM */ @@ -318,9 +334,9 @@ static struct pinctrl_map __initdata mop500_family_pinmap[] = { DB8500_PIN("GPIO215_AH13", out_lo, "spi2"), /* TXD */ DB8500_PIN("GPIO217_AH12", out_lo, "spi2"), /* CLK */ /* SPI2 idle state */ - DB8500_PIN_SLEEP("GPIO218_AH11", slpm_in_wkup_pdis, "spi2"), /* RXD */ - DB8500_PIN_SLEEP("GPIO215_AH13", slpm_out_lo_wkup_pdis, "spi2"), /* TXD */ - DB8500_PIN_SLEEP("GPIO217_AH12", slpm_wkup_pdis, "spi2"), /* CLK */ + DB8500_PIN_IDLE("GPIO218_AH11", slpm_in_wkup_pdis, "spi2"), /* RXD */ + DB8500_PIN_IDLE("GPIO215_AH13", slpm_out_lo_wkup_pdis, "spi2"), /* TXD */ + DB8500_PIN_IDLE("GPIO217_AH12", slpm_wkup_pdis, "spi2"), /* CLK */ /* SPI2 sleep state */ DB8500_PIN_SLEEP("GPIO216_AG12", slpm_in_wkup_pdis, "spi2"), /* FRM */ DB8500_PIN_SLEEP("GPIO218_AH11", slpm_in_wkup_pdis, "spi2"), /* RXD */ @@ -747,6 +763,8 @@ static struct pinctrl_map __initdata snowball_pinmap[] = { DB8500_PIN_HOG("GPIO21_AB3", out_hi), /* Mux in "SM" which is used for the SMSC911x Ethernet adapter */ DB8500_MUX_HOG("sm_b_1", "sm"), + /* User LED */ + DB8500_PIN_HOG("GPIO142_C11", gpio_out_hi), /* Drive RSTn_LAN high */ DB8500_PIN_HOG("GPIO141_C12", gpio_out_hi), /* Accelerometer/Magnetometer */ diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index 537870d3fea8..002da9a369d5 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -140,14 +140,13 @@ struct device * __init ux500_soc_device_init(const char *soc_id) soc_info_populate(soc_dev_attr, soc_id); soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR_OR_NULL(soc_dev)) { + if (IS_ERR(soc_dev)) { kfree(soc_dev_attr); return NULL; } parent = soc_device_to_device(soc_dev); - if (!IS_ERR_OR_NULL(parent)) - device_create_file(parent, &ux500_soc_attr); + device_create_file(parent, &ux500_soc_attr); return parent; } diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c index a6af0b8732ba..d07bbe7f04a6 100644 --- a/arch/arm/mach-ux500/timer.c +++ b/arch/arm/mach-ux500/timer.c @@ -7,6 +7,7 @@ #include <linux/io.h> #include <linux/errno.h> #include <linux/clksrc-dbx500-prcmu.h> +#include <linux/clocksource.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_data/clocksource-nomadik-mtu.h> @@ -32,7 +33,7 @@ static void __init ux500_twd_init(void) twd_local_timer = &u8500_twd_local_timer; if (of_have_populated_dt()) - twd_local_timer_of_register(); + clocksource_of_init(); else { err = twd_local_timer_register(twd_local_timer); if (err) diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 915683cb67d6..d0ad78998cb6 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -5,6 +5,7 @@ #include <linux/amba/bus.h> #include <linux/amba/mmci.h> #include <linux/io.h> +#include <linux/clocksource.h> #include <linux/smp.h> #include <linux/init.h> #include <linux/irqchip.h> @@ -25,7 +26,6 @@ #include <asm/arch_timer.h> #include <asm/mach-types.h> #include <asm/sizes.h> -#include <asm/smp_twd.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/time.h> @@ -435,6 +435,7 @@ static void __init v2m_dt_timer_init(void) vexpress_clk_of_init(); + clocksource_of_init(); do { node = of_find_compatible_node(node, NULL, "arm,sp804"); } while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB); @@ -445,8 +446,7 @@ static void __init v2m_dt_timer_init(void) irq_of_parse_and_map(node, 0)); } - if (arch_timer_of_register() != 0) - twd_local_timer_of_register(); + arch_timer_of_register(); if (arch_timer_sched_clock_init() != 0) versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), diff --git a/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig index e3e94b2fa145..9b252934b206 100644 --- a/arch/arm/mach-vt8500/Kconfig +++ b/arch/arm/mach-vt8500/Kconfig @@ -7,6 +7,7 @@ config ARCH_VT8500 select GENERIC_CLOCKEVENTS select HAVE_CLK select VT8500_TIMER + select PINCTRL help Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile index 92ceb2436b60..4c8a84637594 100644 --- a/arch/arm/mach-vt8500/Makefile +++ b/arch/arm/mach-vt8500/Makefile @@ -1 +1 @@ -obj-$(CONFIG_ARCH_VT8500) += irq.o vt8500.o +obj-$(CONFIG_ARCH_VT8500) += vt8500.o diff --git a/arch/arm/mach-vt8500/common.h b/arch/arm/mach-vt8500/common.h index 77611a6968d6..087787af62f1 100644 --- a/arch/arm/mach-vt8500/common.h +++ b/arch/arm/mach-vt8500/common.h @@ -18,13 +18,7 @@ #include <linux/of.h> -int __init vt8500_irq_init(struct device_node *node, - struct device_node *parent); - /* defined in drivers/clk/clk-vt8500.c */ void __init vtwm_clk_init(void __iomem *pmc_base); -/* defined in irq.c */ -asmlinkage void vt8500_handle_irq(struct pt_regs *regs); - #endif diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c index 49e80053d828..1dd281efc020 100644 --- a/arch/arm/mach-vt8500/vt8500.c +++ b/arch/arm/mach-vt8500/vt8500.c @@ -20,6 +20,7 @@ #include <linux/clocksource.h> #include <linux/io.h> +#include <linux/irqchip.h> #include <linux/pm.h> #include <asm/mach-types.h> @@ -166,16 +167,6 @@ void __init vt8500_init(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } -static const struct of_device_id vt8500_irq_match[] __initconst = { - { .compatible = "via,vt8500-intc", .data = vt8500_irq_init, }, - { /* sentinel */ }, -}; - -static void __init vt8500_init_irq(void) -{ - of_irq_init(vt8500_irq_match); -}; - static const char * const vt8500_dt_compat[] = { "via,vt8500", "wm,wm8650", @@ -187,10 +178,9 @@ static const char * const vt8500_dt_compat[] = { DT_MACHINE_START(WMT_DT, "VIA/Wondermedia SoC (Device Tree Support)") .dt_compat = vt8500_dt_compat, .map_io = vt8500_map_io, - .init_irq = vt8500_init_irq, + .init_irq = irqchip_init, .init_machine = vt8500_init, .init_time = clocksource_of_init, .restart = vt8500_restart, - .handle_irq = vt8500_handle_irq, MACHINE_END diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index adb6c0ea0e53..d70651e8b705 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig @@ -9,5 +9,6 @@ config ARCH_ZYNQ select MIGHT_HAVE_CACHE_L2X0 select USE_OF select SPARSE_IRQ + select CADENCE_TTC_TIMER help Support for Xilinx Zynq ARM Cortex A9 Platform diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile index 397268c1b250..320faedeb484 100644 --- a/arch/arm/mach-zynq/Makefile +++ b/arch/arm/mach-zynq/Makefile @@ -3,4 +3,4 @@ # # Common support -obj-y := common.o timer.o +obj-y := common.o diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 5c8983218183..68e0907de5d0 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -20,6 +20,7 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/clk/zynq.h> +#include <linux/clocksource.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> @@ -77,7 +78,7 @@ static void __init xilinx_zynq_timer_init(void) xilinx_zynq_clocks_init(slcr); - xttcps_timer_init(); + clocksource_of_init(); } /** diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index 8b4dbbaa01cf..5050bb10bb12 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -17,6 +17,4 @@ #ifndef __MACH_ZYNQ_COMMON_H__ #define __MACH_ZYNQ_COMMON_H__ -void __init xttcps_timer_init(void); - #endif diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c deleted file mode 100644 index f9fbc9c1e7a6..000000000000 --- a/arch/arm/mach-zynq/timer.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * This file contains driver for the Xilinx PS Timer Counter IP. - * - * Copyright (C) 2011 Xilinx - * - * based on arch/mips/kernel/time.c timer driver - * - * 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/interrupt.h> -#include <linux/clockchips.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/slab.h> -#include <linux/clk-provider.h> -#include "common.h" - -/* - * Timer Register Offset Definitions of Timer 1, Increment base address by 4 - * and use same offsets for Timer 2 - */ -#define XTTCPS_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */ -#define XTTCPS_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */ -#define XTTCPS_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */ -#define XTTCPS_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */ -#define XTTCPS_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */ -#define XTTCPS_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */ - -#define XTTCPS_CNT_CNTRL_DISABLE_MASK 0x1 - -/* - * Setup the timers to use pre-scaling, using a fixed value for now that will - * work across most input frequency, but it may need to be more dynamic - */ -#define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */ -#define PRESCALE 2048 /* The exponent must match this */ -#define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1) -#define CLK_CNTRL_PRESCALE_EN 1 -#define CNT_CNTRL_RESET (1<<4) - -/** - * struct xttcps_timer - This definition defines local timer structure - * - * @base_addr: Base address of timer - **/ -struct xttcps_timer { - void __iomem *base_addr; -}; - -struct xttcps_timer_clocksource { - struct xttcps_timer xttc; - struct clocksource cs; -}; - -#define to_xttcps_timer_clksrc(x) \ - container_of(x, struct xttcps_timer_clocksource, cs) - -struct xttcps_timer_clockevent { - struct xttcps_timer xttc; - struct clock_event_device ce; - struct clk *clk; -}; - -#define to_xttcps_timer_clkevent(x) \ - container_of(x, struct xttcps_timer_clockevent, ce) - -/** - * xttcps_set_interval - Set the timer interval value - * - * @timer: Pointer to the timer instance - * @cycles: Timer interval ticks - **/ -static void xttcps_set_interval(struct xttcps_timer *timer, - unsigned long cycles) -{ - u32 ctrl_reg; - - /* Disable the counter, set the counter value and re-enable counter */ - ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); - ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK; - __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); - - __raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET); - - /* - * Reset the counter (0x10) so that it starts from 0, one-shot - * mode makes this needed for timing to be right. - */ - ctrl_reg |= CNT_CNTRL_RESET; - ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK; - __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); -} - -/** - * xttcps_clock_event_interrupt - Clock event timer interrupt handler - * - * @irq: IRQ number of the Timer - * @dev_id: void pointer to the xttcps_timer instance - * - * returns: Always IRQ_HANDLED - success - **/ -static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id) -{ - struct xttcps_timer_clockevent *xttce = dev_id; - struct xttcps_timer *timer = &xttce->xttc; - - /* Acknowledge the interrupt and call event handler */ - __raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET); - - xttce->ce.event_handler(&xttce->ce); - - return IRQ_HANDLED; -} - -/** - * __xttc_clocksource_read - Reads the timer counter register - * - * returns: Current timer counter register value - **/ -static cycle_t __xttc_clocksource_read(struct clocksource *cs) -{ - struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc; - - return (cycle_t)__raw_readl(timer->base_addr + - XTTCPS_COUNT_VAL_OFFSET); -} - -/** - * xttcps_set_next_event - Sets the time interval for next event - * - * @cycles: Timer interval ticks - * @evt: Address of clock event instance - * - * returns: Always 0 - success - **/ -static int xttcps_set_next_event(unsigned long cycles, - struct clock_event_device *evt) -{ - struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt); - struct xttcps_timer *timer = &xttce->xttc; - - xttcps_set_interval(timer, cycles); - return 0; -} - -/** - * xttcps_set_mode - Sets the mode of timer - * - * @mode: Mode to be set - * @evt: Address of clock event instance - **/ -static void xttcps_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt); - struct xttcps_timer *timer = &xttce->xttc; - u32 ctrl_reg; - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - xttcps_set_interval(timer, - DIV_ROUND_CLOSEST(clk_get_rate(xttce->clk), - PRESCALE * HZ)); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl_reg = __raw_readl(timer->base_addr + - XTTCPS_CNT_CNTRL_OFFSET); - ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK; - __raw_writel(ctrl_reg, - timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); - break; - case CLOCK_EVT_MODE_RESUME: - ctrl_reg = __raw_readl(timer->base_addr + - XTTCPS_CNT_CNTRL_OFFSET); - ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK; - __raw_writel(ctrl_reg, - timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); - break; - } -} - -static void __init zynq_ttc_setup_clocksource(struct device_node *np, - void __iomem *base) -{ - struct xttcps_timer_clocksource *ttccs; - struct clk *clk; - int err; - u32 reg; - - ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); - if (WARN_ON(!ttccs)) - return; - - err = of_property_read_u32(np, "reg", ®); - if (WARN_ON(err)) - return; - - clk = of_clk_get_by_name(np, "cpu_1x"); - if (WARN_ON(IS_ERR(clk))) - return; - - err = clk_prepare_enable(clk); - if (WARN_ON(err)) - return; - - ttccs->xttc.base_addr = base + reg * 4; - - ttccs->cs.name = np->name; - ttccs->cs.rating = 200; - ttccs->cs.read = __xttc_clocksource_read; - ttccs->cs.mask = CLOCKSOURCE_MASK(16); - ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; - - __raw_writel(0x0, ttccs->xttc.base_addr + XTTCPS_IER_OFFSET); - __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, - ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET); - __raw_writel(CNT_CNTRL_RESET, - ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET); - - err = clocksource_register_hz(&ttccs->cs, clk_get_rate(clk) / PRESCALE); - if (WARN_ON(err)) - return; -} - -static void __init zynq_ttc_setup_clockevent(struct device_node *np, - void __iomem *base) -{ - struct xttcps_timer_clockevent *ttcce; - int err, irq; - u32 reg; - - ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); - if (WARN_ON(!ttcce)) - return; - - err = of_property_read_u32(np, "reg", ®); - if (WARN_ON(err)) - return; - - ttcce->xttc.base_addr = base + reg * 4; - - ttcce->clk = of_clk_get_by_name(np, "cpu_1x"); - if (WARN_ON(IS_ERR(ttcce->clk))) - return; - - err = clk_prepare_enable(ttcce->clk); - if (WARN_ON(err)) - return; - - irq = irq_of_parse_and_map(np, 0); - if (WARN_ON(!irq)) - return; - - ttcce->ce.name = np->name; - ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - ttcce->ce.set_next_event = xttcps_set_next_event; - ttcce->ce.set_mode = xttcps_set_mode; - ttcce->ce.rating = 200; - ttcce->ce.irq = irq; - ttcce->ce.cpumask = cpu_possible_mask; - - __raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET); - __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, - ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET); - __raw_writel(0x1, ttcce->xttc.base_addr + XTTCPS_IER_OFFSET); - - err = request_irq(irq, xttcps_clock_event_interrupt, IRQF_TIMER, - np->name, ttcce); - if (WARN_ON(err)) - return; - - clockevents_config_and_register(&ttcce->ce, - clk_get_rate(ttcce->clk) / PRESCALE, - 1, 0xfffe); -} - -static const __initconst struct of_device_id zynq_ttc_match[] = { - { .compatible = "xlnx,ttc-counter-clocksource", - .data = zynq_ttc_setup_clocksource, }, - { .compatible = "xlnx,ttc-counter-clockevent", - .data = zynq_ttc_setup_clockevent, }, - {} -}; - -/** - * xttcps_timer_init - Initialize the timer - * - * Initializes the timer hardware and register the clock source and clock event - * timers with Linux kernal timer framework - **/ -void __init xttcps_timer_init(void) -{ - struct device_node *np; - - for_each_compatible_node(np, NULL, "xlnx,ttc") { - struct device_node *np_chld; - void __iomem *base; - - base = of_iomap(np, 0); - if (WARN_ON(!base)) - return; - - for_each_available_child_of_node(np, np_chld) { - int (*cb)(struct device_node *np, void __iomem *base); - const struct of_device_id *match; - - match = of_match_node(zynq_ttc_match, np_chld); - if (match) { - cb = match->data; - cb(np_chld, base); - } - } - } -} diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index a0daa2fb5de6..e6dbc8dbe6a6 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -140,8 +140,7 @@ static int omap_dm_timer_prepare(struct omap_dm_timer *timer) */ if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { timer->fclk = clk_get(&timer->pdev->dev, "fck"); - if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) { - timer->fclk = NULL; + if (WARN_ON_ONCE(IS_ERR(timer->fclk))) { dev_err(&timer->pdev->dev, ": No fclk handle.\n"); return -EINVAL; } @@ -373,7 +372,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) { - if (timer) + if (timer && !IS_ERR(timer->fclk)) return timer->fclk; return NULL; } @@ -482,7 +481,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) if (pdata && pdata->set_timer_src) return pdata->set_timer_src(timer->pdev, source); - if (!timer->fclk) + if (IS_ERR(timer->fclk)) return -EINVAL; switch (source) { @@ -500,13 +499,13 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) } parent = clk_get(&timer->pdev->dev, parent_name); - if (IS_ERR_OR_NULL(parent)) { + if (IS_ERR(parent)) { pr_err("%s: %s not found\n", __func__, parent_name); return -EINVAL; } ret = clk_set_parent(timer->fclk, parent); - if (IS_ERR_VALUE(ret)) + if (ret < 0) pr_err("%s: failed to set %s as parent\n", __func__, parent_name); @@ -808,6 +807,7 @@ static int omap_dm_timer_probe(struct platform_device *pdev) return -ENOMEM; } + timer->fclk = ERR_PTR(-ENODEV); timer->io_base = devm_ioremap_resource(dev, mem); if (IS_ERR(timer->io_base)) return PTR_ERR(timer->io_base); diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index a9d52167e16e..6cb19c6aa9d6 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -25,7 +25,7 @@ config PLAT_S5P select PLAT_SAMSUNG select S3C_GPIO_TRACK select S5P_GPIO_DRVSTR - select SAMSUNG_CLKSRC + select SAMSUNG_CLKSRC if !COMMON_CLK select SAMSUNG_GPIOLIB_4BIT select SAMSUNG_IRQ_VIC_TIMER help @@ -70,7 +70,7 @@ config S3C_LOWLEVEL_UART_PORT # timer options -config S5P_HRT +config SAMSUNG_HRT bool select SAMSUNG_DEV_PWM help @@ -89,7 +89,7 @@ config SAMSUNG_CLKSRC used by newer systems such as the S3C64XX. config S5P_CLOCK - def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) + def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210) help Support common clock part for ARCH_S5P and ARCH_EXYNOS SoCs diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 3a7c64d1814a..a23c460299a1 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -12,8 +12,7 @@ obj- := # Objects we always build independent of SoC choice obj-y += init.o cpu.o -obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) += time.o -obj-$(CONFIG_S5P_HRT) += s5p-time.o +obj-$(CONFIG_SAMSUNG_HRT) += samsung-time.o obj-$(CONFIG_SAMSUNG_CLOCK) += clock.o obj-$(CONFIG_SAMSUNG_CLOCK) += pwm-clock.o diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 51afedda9ab6..e1124d9fd2b0 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -1113,7 +1113,7 @@ struct platform_device s5p_device_onenand = { /* PMU */ -#ifdef CONFIG_PLAT_S5P +#if defined(CONFIG_PLAT_S5P) && !defined(CONFIG_ARCH_EXYNOS) static struct resource s5p_pmu_resource[] = { DEFINE_RES_IRQ(IRQ_PMU) }; diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h index 37703ef6dfc7..989fefe18be6 100644 --- a/arch/arm/plat-samsung/include/plat/cpu.h +++ b/arch/arm/plat-samsung/include/plat/cpu.h @@ -23,6 +23,9 @@ extern unsigned long samsung_cpu_id; #define S3C24XX_CPU_ID 0x32400000 #define S3C24XX_CPU_MASK 0xFFF00000 +#define S3C2412_CPU_ID 0x32412000 +#define S3C2412_CPU_MASK 0xFFFFF000 + #define S3C6400_CPU_ID 0x36400000 #define S3C6410_CPU_ID 0x36410000 #define S3C64XX_CPU_MASK 0xFFFFF000 @@ -53,6 +56,7 @@ static inline int is_samsung_##name(void) \ } IS_SAMSUNG_CPU(s3c24xx, S3C24XX_CPU_ID, S3C24XX_CPU_MASK) +IS_SAMSUNG_CPU(s3c2412, S3C2412_CPU_ID, S3C2412_CPU_MASK) IS_SAMSUNG_CPU(s3c6400, S3C6400_CPU_ID, S3C64XX_CPU_MASK) IS_SAMSUNG_CPU(s3c6410, S3C6410_CPU_ID, S3C64XX_CPU_MASK) IS_SAMSUNG_CPU(s5p6440, S5P6440_CPU_ID, S5P64XX_CPU_MASK) @@ -74,6 +78,12 @@ IS_SAMSUNG_CPU(exynos5440, EXYNOS5440_SOC_ID, EXYNOS5_SOC_MASK) # define soc_is_s3c24xx() 0 #endif +#if defined(CONFIG_CPU_S3C2412) +# define soc_is_s3c2412() is_samsung_s3c2412() +#else +# define soc_is_s3c2412() 0 +#endif + #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) # define soc_is_s3c64xx() (is_samsung_s3c6400() || is_samsung_s3c6410()) #else @@ -173,7 +183,6 @@ extern void s3c_init_cpu(unsigned long idcode, /* core initialisation functions */ -extern void s3c24xx_init_irq(void); extern void s5p_init_irq(u32 *vic, u32 num_vic); extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); @@ -192,10 +201,6 @@ extern void s3c24xx_init_uartdevs(char *name, struct s3c24xx_uart_resources *res, struct s3c2410_uartcfg *cfg, int no); -/* timer for 2410/2440 */ - -extern void s3c24xx_timer_init(void); - extern struct syscore_ops s3c2410_pm_syscore_ops; extern struct syscore_ops s3c2412_pm_syscore_ops; extern struct syscore_ops s3c2416_pm_syscore_ops; diff --git a/arch/arm/plat-samsung/include/plat/irq.h b/arch/arm/plat-samsung/include/plat/irq.h deleted file mode 100644 index e21a89bc26c9..000000000000 --- a/arch/arm/plat-samsung/include/plat/irq.h +++ /dev/null @@ -1,116 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/irq.h - * - * Copyright (c) 2004-2005 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * Header file for S3C24XX CPU IRQ support - * - * 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/io.h> - -#include <mach/hardware.h> -#include <mach/regs-irq.h> -#include <mach/regs-gpio.h> - -#define irqdbf(x...) -#define irqdbf2(x...) - -#define EXTINT_OFF (IRQ_EINT4 - 4) - -/* these are exported for arch/arm/mach-* usage */ -extern struct irq_chip s3c_irq_level_chip; -extern struct irq_chip s3c_irq_chip; - -static inline void s3c_irqsub_mask(unsigned int irqno, - unsigned int parentbit, - int subcheck) -{ - unsigned long mask; - unsigned long submask; - - submask = __raw_readl(S3C2410_INTSUBMSK); - mask = __raw_readl(S3C2410_INTMSK); - - submask |= (1UL << (irqno - IRQ_S3CUART_RX0)); - - /* check to see if we need to mask the parent IRQ */ - - if ((submask & subcheck) == subcheck) - __raw_writel(mask | parentbit, S3C2410_INTMSK); - - /* write back masks */ - __raw_writel(submask, S3C2410_INTSUBMSK); - -} - -static inline void s3c_irqsub_unmask(unsigned int irqno, - unsigned int parentbit) -{ - unsigned long mask; - unsigned long submask; - - submask = __raw_readl(S3C2410_INTSUBMSK); - mask = __raw_readl(S3C2410_INTMSK); - - submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0)); - mask &= ~parentbit; - - /* write back masks */ - __raw_writel(submask, S3C2410_INTSUBMSK); - __raw_writel(mask, S3C2410_INTMSK); -} - - -static inline void s3c_irqsub_maskack(unsigned int irqno, - unsigned int parentmask, - unsigned int group) -{ - unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0); - - s3c_irqsub_mask(irqno, parentmask, group); - - __raw_writel(bit, S3C2410_SUBSRCPND); - - /* only ack parent if we've got all the irqs (seems we must - * ack, all and hope that the irq system retriggers ok when - * the interrupt goes off again) - */ - - if (1) { - __raw_writel(parentmask, S3C2410_SRCPND); - __raw_writel(parentmask, S3C2410_INTPND); - } -} - -static inline void s3c_irqsub_ack(unsigned int irqno, - unsigned int parentmask, - unsigned int group) -{ - unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0); - - __raw_writel(bit, S3C2410_SUBSRCPND); - - /* only ack parent if we've got all the irqs (seems we must - * ack, all and hope that the irq system retriggers ok when - * the interrupt goes off again) - */ - - if (1) { - __raw_writel(parentmask, S3C2410_SRCPND); - __raw_writel(parentmask, S3C2410_INTPND); - } -} - -/* exported for use in arch/arm/mach-s3c2410 */ - -#ifdef CONFIG_PM -extern int s3c_irq_wake(struct irq_data *data, unsigned int state); -#else -#define s3c_irq_wake NULL -#endif - -extern int s3c_irqext_type(struct irq_data *d, unsigned int type); diff --git a/arch/arm/plat-samsung/include/plat/s3c2410.h b/arch/arm/plat-samsung/include/plat/s3c2410.h deleted file mode 100644 index 55b0e5f51e97..000000000000 --- a/arch/arm/plat-samsung/include/plat/s3c2410.h +++ /dev/null @@ -1,31 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/s3c2410.h - * - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * Header file for s3c2410 machine directory - * - * 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. - * -*/ - -#ifdef CONFIG_CPU_S3C2410 - -extern int s3c2410_init(void); -extern int s3c2410a_init(void); - -extern void s3c2410_map_io(void); - -extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); - -extern void s3c2410_init_clocks(int xtal); - -#else -#define s3c2410_init_clocks NULL -#define s3c2410_init_uarts NULL -#define s3c2410_map_io NULL -#define s3c2410_init NULL -#define s3c2410a_init NULL -#endif diff --git a/arch/arm/plat-samsung/include/plat/s3c2412.h b/arch/arm/plat-samsung/include/plat/s3c2412.h deleted file mode 100644 index cbae50ddacc8..000000000000 --- a/arch/arm/plat-samsung/include/plat/s3c2412.h +++ /dev/null @@ -1,32 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/s3c2412.h - * - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * Header file for s3c2412 cpu support - * - * 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. -*/ - -#ifdef CONFIG_CPU_S3C2412 - -extern int s3c2412_init(void); - -extern void s3c2412_map_io(void); - -extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no); - -extern void s3c2412_init_clocks(int xtal); - -extern int s3c2412_baseclk_add(void); - -extern void s3c2412_restart(char mode, const char *cmd); -#else -#define s3c2412_init_clocks NULL -#define s3c2412_init_uarts NULL -#define s3c2412_map_io NULL -#define s3c2412_init NULL -#define s3c2412_restart NULL -#endif diff --git a/arch/arm/plat-samsung/include/plat/s3c2416.h b/arch/arm/plat-samsung/include/plat/s3c2416.h deleted file mode 100644 index f27399a3c68d..000000000000 --- a/arch/arm/plat-samsung/include/plat/s3c2416.h +++ /dev/null @@ -1,37 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/s3c2416.h - * - * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com> - * - * Header file for s3c2416 cpu support - * - * 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. -*/ - -#ifdef CONFIG_CPU_S3C2416 - -struct s3c2410_uartcfg; - -extern int s3c2416_init(void); - -extern void s3c2416_map_io(void); - -extern void s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no); - -extern void s3c2416_init_clocks(int xtal); - -extern int s3c2416_baseclk_add(void); - -extern void s3c2416_restart(char mode, const char *cmd); - -extern void s3c2416_init_irq(void); -extern struct syscore_ops s3c2416_irq_syscore_ops; - -#else -#define s3c2416_init_clocks NULL -#define s3c2416_init_uarts NULL -#define s3c2416_map_io NULL -#define s3c2416_init NULL -#define s3c2416_restart NULL -#endif diff --git a/arch/arm/plat-samsung/include/plat/s3c2443.h b/arch/arm/plat-samsung/include/plat/s3c2443.h deleted file mode 100644 index 71b88ec48956..000000000000 --- a/arch/arm/plat-samsung/include/plat/s3c2443.h +++ /dev/null @@ -1,36 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/s3c2443.h - * - * Copyright (c) 2004-2005 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * Header file for s3c2443 cpu support - * - * 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. -*/ - -#ifdef CONFIG_CPU_S3C2443 - -struct s3c2410_uartcfg; - -extern int s3c2443_init(void); - -extern void s3c2443_map_io(void); - -extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no); - -extern void s3c2443_init_clocks(int xtal); - -extern int s3c2443_baseclk_add(void); - -extern void s3c2443_restart(char mode, const char *cmd); - -extern void s3c2443_init_irq(void); -#else -#define s3c2443_init_clocks NULL -#define s3c2443_init_uarts NULL -#define s3c2443_map_io NULL -#define s3c2443_init NULL -#define s3c2443_restart NULL -#endif diff --git a/arch/arm/plat-samsung/include/plat/s3c244x.h b/arch/arm/plat-samsung/include/plat/s3c244x.h deleted file mode 100644 index ea0c961b7603..000000000000 --- a/arch/arm/plat-samsung/include/plat/s3c244x.h +++ /dev/null @@ -1,42 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/s3c244x.h - * - * Copyright (c) 2004-2005 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * Header file for S3C2440 and S3C2442 cpu support - * - * 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. -*/ - -#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) - -extern void s3c244x_map_io(void); - -extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no); - -extern void s3c244x_init_clocks(int xtal); - -#else -#define s3c244x_init_clocks NULL -#define s3c244x_init_uarts NULL -#endif - -#ifdef CONFIG_CPU_S3C2440 -extern int s3c2440_init(void); - -extern void s3c2440_map_io(void); -#else -#define s3c2440_init NULL -#define s3c2440_map_io NULL -#endif - -#ifdef CONFIG_CPU_S3C2442 -extern int s3c2442_init(void); - -extern void s3c2442_map_io(void); -#else -#define s3c2442_init NULL -#define s3c2442_map_io NULL -#endif diff --git a/arch/arm/plat-samsung/include/plat/s5p-time.h b/arch/arm/plat-samsung/include/plat/s5p-time.h deleted file mode 100644 index 9c96f3586ce0..000000000000 --- a/arch/arm/plat-samsung/include/plat/s5p-time.h +++ /dev/null @@ -1,40 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/s5p-time.h - * - * Copyright 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * Header file for s5p time support - * - * 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 __ASM_PLAT_S5P_TIME_H -#define __ASM_PLAT_S5P_TIME_H __FILE__ - -/* S5P HR-Timer Clock mode */ -enum s5p_timer_mode { - S5P_PWM0, - S5P_PWM1, - S5P_PWM2, - S5P_PWM3, - S5P_PWM4, -}; - -struct s5p_timer_source { - unsigned int event_id; - unsigned int source_id; -}; - -/* Be able to sleep for atleast 4 seconds (usually more) */ -#define S5PTIMER_MIN_RANGE 4 - -#define TCNT_MAX 0xffffffff -#define NON_PERIODIC 0 -#define PERIODIC 1 - -extern void __init s5p_set_timer_source(enum s5p_timer_mode event, - enum s5p_timer_mode source); -extern void s5p_timer_init(void); -#endif /* __ASM_PLAT_S5P_TIME_H */ diff --git a/arch/arm/plat-samsung/include/plat/samsung-time.h b/arch/arm/plat-samsung/include/plat/samsung-time.h new file mode 100644 index 000000000000..4cc99bb1f176 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/samsung-time.h @@ -0,0 +1,53 @@ +/* linux/arch/arm/plat-samsung/include/plat/samsung-time.h + * + * Copyright 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Header file for samsung s3c and s5p time support + * + * 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 __ASM_PLAT_SAMSUNG_TIME_H +#define __ASM_PLAT_SAMSUNG_TIME_H __FILE__ + +/* SAMSUNG HR-Timer Clock mode */ +enum samsung_timer_mode { + SAMSUNG_PWM0, + SAMSUNG_PWM1, + SAMSUNG_PWM2, + SAMSUNG_PWM3, + SAMSUNG_PWM4, +}; + +struct samsung_timer_source { + unsigned int event_id; + unsigned int source_id; +}; + +/* Be able to sleep for atleast 4 seconds (usually more) */ +#define SAMSUNG_TIMER_MIN_RANGE 4 + +#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S5PC100) +#define TCNT_MAX 0xffff +#define TSCALER_DIV 25 +#define TDIV 50 +#define TSIZE 16 +#else +#define TCNT_MAX 0xffffffff +#define TSCALER_DIV 2 +#define TDIV 2 +#define TSIZE 32 +#endif + +#define NON_PERIODIC 0 +#define PERIODIC 1 + +extern void __init samsung_set_timer_source(enum samsung_timer_mode event, + enum samsung_timer_mode source); + +extern void __init samsung_timer_init(void); + +#endif /* __ASM_PLAT_SAMSUNG_TIME_H */ diff --git a/arch/arm/plat-samsung/s5p-time.c b/arch/arm/plat-samsung/samsung-time.c index e92510cf82ee..f899cbc9b288 100644 --- a/arch/arm/plat-samsung/s5p-time.c +++ b/arch/arm/plat-samsung/samsung-time.c @@ -2,7 +2,7 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * - * S5P - Common hr-timer support + * samsung - Common hr-timer support (s3c and s5p) * * 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 @@ -25,41 +25,41 @@ #include <mach/map.h> #include <plat/devs.h> #include <plat/regs-timer.h> -#include <plat/s5p-time.h> +#include <plat/samsung-time.h> static struct clk *tin_event; static struct clk *tin_source; static struct clk *tdiv_event; static struct clk *tdiv_source; static struct clk *timerclk; -static struct s5p_timer_source timer_source; +static struct samsung_timer_source timer_source; static unsigned long clock_count_per_tick; -static void s5p_timer_resume(void); +static void samsung_timer_resume(void); -static void s5p_time_stop(enum s5p_timer_mode mode) +static void samsung_time_stop(enum samsung_timer_mode mode) { unsigned long tcon; tcon = __raw_readl(S3C2410_TCON); switch (mode) { - case S5P_PWM0: + case SAMSUNG_PWM0: tcon &= ~S3C2410_TCON_T0START; break; - case S5P_PWM1: + case SAMSUNG_PWM1: tcon &= ~S3C2410_TCON_T1START; break; - case S5P_PWM2: + case SAMSUNG_PWM2: tcon &= ~S3C2410_TCON_T2START; break; - case S5P_PWM3: + case SAMSUNG_PWM3: tcon &= ~S3C2410_TCON_T3START; break; - case S5P_PWM4: + case SAMSUNG_PWM4: tcon &= ~S3C2410_TCON_T4START; break; @@ -70,7 +70,7 @@ static void s5p_time_stop(enum s5p_timer_mode mode) __raw_writel(tcon, S3C2410_TCON); } -static void s5p_time_setup(enum s5p_timer_mode mode, unsigned long tcnt) +static void samsung_time_setup(enum samsung_timer_mode mode, unsigned long tcnt) { unsigned long tcon; @@ -79,27 +79,27 @@ static void s5p_time_setup(enum s5p_timer_mode mode, unsigned long tcnt) tcnt--; switch (mode) { - case S5P_PWM0: + case SAMSUNG_PWM0: tcon &= ~(0x0f << 0); tcon |= S3C2410_TCON_T0MANUALUPD; break; - case S5P_PWM1: + case SAMSUNG_PWM1: tcon &= ~(0x0f << 8); tcon |= S3C2410_TCON_T1MANUALUPD; break; - case S5P_PWM2: + case SAMSUNG_PWM2: tcon &= ~(0x0f << 12); tcon |= S3C2410_TCON_T2MANUALUPD; break; - case S5P_PWM3: + case SAMSUNG_PWM3: tcon &= ~(0x0f << 16); tcon |= S3C2410_TCON_T3MANUALUPD; break; - case S5P_PWM4: + case SAMSUNG_PWM4: tcon &= ~(0x07 << 20); tcon |= S3C2410_TCON_T4MANUALUPD; break; @@ -114,14 +114,14 @@ static void s5p_time_setup(enum s5p_timer_mode mode, unsigned long tcnt) __raw_writel(tcon, S3C2410_TCON); } -static void s5p_time_start(enum s5p_timer_mode mode, bool periodic) +static void samsung_time_start(enum samsung_timer_mode mode, bool periodic) { unsigned long tcon; tcon = __raw_readl(S3C2410_TCON); switch (mode) { - case S5P_PWM0: + case SAMSUNG_PWM0: tcon |= S3C2410_TCON_T0START; tcon &= ~S3C2410_TCON_T0MANUALUPD; @@ -131,7 +131,7 @@ static void s5p_time_start(enum s5p_timer_mode mode, bool periodic) tcon &= ~S3C2410_TCON_T0RELOAD; break; - case S5P_PWM1: + case SAMSUNG_PWM1: tcon |= S3C2410_TCON_T1START; tcon &= ~S3C2410_TCON_T1MANUALUPD; @@ -141,7 +141,7 @@ static void s5p_time_start(enum s5p_timer_mode mode, bool periodic) tcon &= ~S3C2410_TCON_T1RELOAD; break; - case S5P_PWM2: + case SAMSUNG_PWM2: tcon |= S3C2410_TCON_T2START; tcon &= ~S3C2410_TCON_T2MANUALUPD; @@ -151,7 +151,7 @@ static void s5p_time_start(enum s5p_timer_mode mode, bool periodic) tcon &= ~S3C2410_TCON_T2RELOAD; break; - case S5P_PWM3: + case SAMSUNG_PWM3: tcon |= S3C2410_TCON_T3START; tcon &= ~S3C2410_TCON_T3MANUALUPD; @@ -161,7 +161,7 @@ static void s5p_time_start(enum s5p_timer_mode mode, bool periodic) tcon &= ~S3C2410_TCON_T3RELOAD; break; - case S5P_PWM4: + case SAMSUNG_PWM4: tcon |= S3C2410_TCON_T4START; tcon &= ~S3C2410_TCON_T4MANUALUPD; @@ -178,24 +178,24 @@ static void s5p_time_start(enum s5p_timer_mode mode, bool periodic) __raw_writel(tcon, S3C2410_TCON); } -static int s5p_set_next_event(unsigned long cycles, +static int samsung_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - s5p_time_setup(timer_source.event_id, cycles); - s5p_time_start(timer_source.event_id, NON_PERIODIC); + samsung_time_setup(timer_source.event_id, cycles); + samsung_time_start(timer_source.event_id, NON_PERIODIC); return 0; } -static void s5p_set_mode(enum clock_event_mode mode, +static void samsung_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { - s5p_time_stop(timer_source.event_id); + samsung_time_stop(timer_source.event_id); switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - s5p_time_setup(timer_source.event_id, clock_count_per_tick); - s5p_time_start(timer_source.event_id, PERIODIC); + samsung_time_setup(timer_source.event_id, clock_count_per_tick); + samsung_time_start(timer_source.event_id, PERIODIC); break; case CLOCK_EVT_MODE_ONESHOT: @@ -206,24 +206,24 @@ static void s5p_set_mode(enum clock_event_mode mode, break; case CLOCK_EVT_MODE_RESUME: - s5p_timer_resume(); + samsung_timer_resume(); break; } } -static void s5p_timer_resume(void) +static void samsung_timer_resume(void) { /* event timer restart */ - s5p_time_setup(timer_source.event_id, clock_count_per_tick); - s5p_time_start(timer_source.event_id, PERIODIC); + samsung_time_setup(timer_source.event_id, clock_count_per_tick); + samsung_time_start(timer_source.event_id, PERIODIC); /* source timer restart */ - s5p_time_setup(timer_source.source_id, TCNT_MAX); - s5p_time_start(timer_source.source_id, PERIODIC); + samsung_time_setup(timer_source.source_id, TCNT_MAX); + samsung_time_start(timer_source.source_id, PERIODIC); } -void __init s5p_set_timer_source(enum s5p_timer_mode event, - enum s5p_timer_mode source) +void __init samsung_set_timer_source(enum samsung_timer_mode event, + enum samsung_timer_mode source) { s3c_device_timer[event].dev.bus = &platform_bus_type; s3c_device_timer[source].dev.bus = &platform_bus_type; @@ -233,14 +233,14 @@ void __init s5p_set_timer_source(enum s5p_timer_mode event, } static struct clock_event_device time_event_device = { - .name = "s5p_event_timer", + .name = "samsung_event_timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .rating = 200, - .set_next_event = s5p_set_next_event, - .set_mode = s5p_set_mode, + .set_next_event = samsung_set_next_event, + .set_mode = samsung_set_mode, }; -static irqreturn_t s5p_clock_event_isr(int irq, void *dev_id) +static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) { struct clock_event_device *evt = dev_id; @@ -249,14 +249,14 @@ static irqreturn_t s5p_clock_event_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction s5p_clock_event_irq = { - .name = "s5p_time_irq", +static struct irqaction samsung_clock_event_irq = { + .name = "samsung_time_irq", .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = s5p_clock_event_isr, + .handler = samsung_clock_event_isr, .dev_id = &time_event_device, }; -static void __init s5p_clockevent_init(void) +static void __init samsung_clockevent_init(void) { unsigned long pclk; unsigned long clock_rate; @@ -267,8 +267,8 @@ static void __init s5p_clockevent_init(void) tscaler = clk_get_parent(tdiv_event); - clk_set_rate(tscaler, pclk / 2); - clk_set_rate(tdiv_event, pclk / 2); + clk_set_rate(tscaler, pclk / TSCALER_DIV); + clk_set_rate(tdiv_event, pclk / TDIV); clk_set_parent(tin_event, tdiv_event); clock_rate = clk_get_rate(tin_event); @@ -278,22 +278,22 @@ static void __init s5p_clockevent_init(void) clockevents_config_and_register(&time_event_device, clock_rate, 1, -1); irq_number = timer_source.event_id + IRQ_TIMER0; - setup_irq(irq_number, &s5p_clock_event_irq); + setup_irq(irq_number, &samsung_clock_event_irq); } -static void __iomem *s5p_timer_reg(void) +static void __iomem *samsung_timer_reg(void) { unsigned long offset = 0; switch (timer_source.source_id) { - case S5P_PWM0: - case S5P_PWM1: - case S5P_PWM2: - case S5P_PWM3: + case SAMSUNG_PWM0: + case SAMSUNG_PWM1: + case SAMSUNG_PWM2: + case SAMSUNG_PWM3: offset = (timer_source.source_id * 0x0c) + 0x14; break; - case S5P_PWM4: + case SAMSUNG_PWM4: offset = 0x40; break; @@ -312,9 +312,9 @@ static void __iomem *s5p_timer_reg(void) * this wraps around for now, since it is just a relative time * stamp. (Inspired by U300 implementation.) */ -static u32 notrace s5p_read_sched_clock(void) +static u32 notrace samsung_read_sched_clock(void) { - void __iomem *reg = s5p_timer_reg(); + void __iomem *reg = samsung_timer_reg(); if (!reg) return 0; @@ -322,29 +322,29 @@ static u32 notrace s5p_read_sched_clock(void) return ~__raw_readl(reg); } -static void __init s5p_clocksource_init(void) +static void __init samsung_clocksource_init(void) { unsigned long pclk; unsigned long clock_rate; pclk = clk_get_rate(timerclk); - clk_set_rate(tdiv_source, pclk / 2); + clk_set_rate(tdiv_source, pclk / TDIV); clk_set_parent(tin_source, tdiv_source); clock_rate = clk_get_rate(tin_source); - s5p_time_setup(timer_source.source_id, TCNT_MAX); - s5p_time_start(timer_source.source_id, PERIODIC); + samsung_time_setup(timer_source.source_id, TCNT_MAX); + samsung_time_start(timer_source.source_id, PERIODIC); - setup_sched_clock(s5p_read_sched_clock, 32, clock_rate); + setup_sched_clock(samsung_read_sched_clock, TSIZE, clock_rate); - if (clocksource_mmio_init(s5p_timer_reg(), "s5p_clocksource_timer", - clock_rate, 250, 32, clocksource_mmio_readl_down)) - panic("s5p_clocksource_timer: can't register clocksource\n"); + if (clocksource_mmio_init(samsung_timer_reg(), "samsung_clocksource_timer", + clock_rate, 250, TSIZE, clocksource_mmio_readl_down)) + panic("samsung_clocksource_timer: can't register clocksource\n"); } -static void __init s5p_timer_resources(void) +static void __init samsung_timer_resources(void) { unsigned long event_id = timer_source.event_id; @@ -386,9 +386,9 @@ static void __init s5p_timer_resources(void) clk_enable(tin_source); } -void __init s5p_timer_init(void) +void __init samsung_timer_init(void) { - s5p_timer_resources(); - s5p_clockevent_init(); - s5p_clocksource_init(); + samsung_timer_resources(); + samsung_clockevent_init(); + samsung_clocksource_init(); } diff --git a/arch/arm/plat-samsung/time.c b/arch/arm/plat-samsung/time.c deleted file mode 100644 index 73defd00c3e4..000000000000 --- a/arch/arm/plat-samsung/time.c +++ /dev/null @@ -1,287 +0,0 @@ -/* linux/arch/arm/plat-samsung/time.c - * - * Copyright (C) 2003-2005 Simtec Electronics - * Ben Dooks, <ben@simtec.co.uk> - * - * 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/kernel.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/syscore_ops.h> - -#include <asm/mach-types.h> - -#include <asm/irq.h> -#include <mach/map.h> -#include <plat/regs-timer.h> -#include <mach/regs-irq.h> -#include <asm/mach/time.h> -#include <mach/tick.h> - -#include <plat/clock.h> -#include <plat/cpu.h> - -static unsigned long timer_startval; -static unsigned long timer_usec_ticks; - -#ifndef TICK_MAX -#define TICK_MAX (0xffff) -#endif - -#define TIMER_USEC_SHIFT 16 - -/* we use the shifted arithmetic to work out the ratio of timer ticks - * to usecs, as often the peripheral clock is not a nice even multiple - * of 1MHz. - * - * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok - * for the current HZ value of 200 without producing overflows. - * - * Original patch by Dimitry Andric, updated by Ben Dooks -*/ - - -/* timer_mask_usec_ticks - * - * given a clock and divisor, make the value to pass into timer_ticks_to_usec - * to scale the ticks into usecs -*/ - -static inline unsigned long -timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk) -{ - unsigned long den = pclk / 1000; - - return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den; -} - -/* timer_ticks_to_usec - * - * convert timer ticks to usec. -*/ - -static inline unsigned long timer_ticks_to_usec(unsigned long ticks) -{ - unsigned long res; - - res = ticks * timer_usec_ticks; - res += 1 << (TIMER_USEC_SHIFT - 4); /* round up slightly */ - - return res >> TIMER_USEC_SHIFT; -} - -/*** - * Returns microsecond since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() - * IRQs are disabled before entering here from do_gettimeofday() - */ - -static u32 s3c2410_gettimeoffset(void) -{ - unsigned long tdone; - unsigned long tval; - - /* work out how many ticks have gone since last timer interrupt */ - - tval = __raw_readl(S3C2410_TCNTO(4)); - tdone = timer_startval - tval; - - /* check to see if there is an interrupt pending */ - - if (s3c24xx_ostimer_pending()) { - /* re-read the timer, and try and fix up for the missed - * interrupt. Note, the interrupt may go off before the - * timer has re-loaded from wrapping. - */ - - tval = __raw_readl(S3C2410_TCNTO(4)); - tdone = timer_startval - tval; - - if (tval != 0) - tdone += timer_startval; - } - - return timer_ticks_to_usec(tdone) * 1000; -} - - -/* - * IRQ handler for the timer - */ -static irqreturn_t -s3c2410_timer_interrupt(int irq, void *dev_id) -{ - timer_tick(); - return IRQ_HANDLED; -} - -static struct irqaction s3c2410_timer_irq = { - .name = "S3C2410 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = s3c2410_timer_interrupt, -}; - -#define use_tclk1_12() ( \ - machine_is_bast() || \ - machine_is_vr1000() || \ - machine_is_anubis() || \ - machine_is_osiris()) - -static struct clk *tin; -static struct clk *tdiv; -static struct clk *timerclk; - -/* - * Set up timer interrupt, and return the current time in seconds. - * - * Currently we only use timer4, as it is the only timer which has no - * other function that can be exploited externally - */ -static void s3c2410_timer_setup (void) -{ - unsigned long tcon; - unsigned long tcnt; - unsigned long tcfg1; - unsigned long tcfg0; - - tcnt = TICK_MAX; /* default value for tcnt */ - - /* configure the system for whichever machine is in use */ - - if (use_tclk1_12()) { - /* timer is at 12MHz, scaler is 1 */ - timer_usec_ticks = timer_mask_usec_ticks(1, 12000000); - tcnt = 12000000 / HZ; - - tcfg1 = __raw_readl(S3C2410_TCFG1); - tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; - tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1; - __raw_writel(tcfg1, S3C2410_TCFG1); - } else { - unsigned long pclk; - struct clk *tscaler; - - /* for the h1940 (and others), we use the pclk from the core - * to generate the timer values. since values around 50 to - * 70MHz are not values we can directly generate the timer - * value from, we need to pre-scale and divide before using it. - * - * for instance, using 50.7MHz and dividing by 6 gives 8.45MHz - * (8.45 ticks per usec) - */ - - pclk = clk_get_rate(timerclk); - - /* configure clock tick */ - - timer_usec_ticks = timer_mask_usec_ticks(6, pclk); - - tscaler = clk_get_parent(tdiv); - - clk_set_rate(tscaler, pclk / 3); - clk_set_rate(tdiv, pclk / 6); - clk_set_parent(tin, tdiv); - - tcnt = clk_get_rate(tin) / HZ; - } - - tcon = __raw_readl(S3C2410_TCON); - tcfg0 = __raw_readl(S3C2410_TCFG0); - tcfg1 = __raw_readl(S3C2410_TCFG1); - - /* timers reload after counting zero, so reduce the count by 1 */ - - tcnt--; - - printk(KERN_DEBUG "timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n", - tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks); - - /* check to see if timer is within 16bit range... */ - if (tcnt > TICK_MAX) { - panic("setup_timer: HZ is too small, cannot configure timer!"); - return; - } - - __raw_writel(tcfg1, S3C2410_TCFG1); - __raw_writel(tcfg0, S3C2410_TCFG0); - - timer_startval = tcnt; - __raw_writel(tcnt, S3C2410_TCNTB(4)); - - /* ensure timer is stopped... */ - - tcon &= ~(7<<20); - tcon |= S3C2410_TCON_T4RELOAD; - tcon |= S3C2410_TCON_T4MANUALUPD; - - __raw_writel(tcon, S3C2410_TCON); - __raw_writel(tcnt, S3C2410_TCNTB(4)); - __raw_writel(tcnt, S3C2410_TCMPB(4)); - - /* start the timer running */ - tcon |= S3C2410_TCON_T4START; - tcon &= ~S3C2410_TCON_T4MANUALUPD; - __raw_writel(tcon, S3C2410_TCON); -} - -static void __init s3c2410_timer_resources(void) -{ - struct platform_device tmpdev; - - tmpdev.dev.bus = &platform_bus_type; - tmpdev.id = 4; - - timerclk = clk_get(NULL, "timers"); - if (IS_ERR(timerclk)) - panic("failed to get clock for system timer"); - - clk_enable(timerclk); - - if (!use_tclk1_12()) { - tmpdev.id = 4; - tmpdev.dev.init_name = "s3c24xx-pwm.4"; - tin = clk_get(&tmpdev.dev, "pwm-tin"); - if (IS_ERR(tin)) - panic("failed to get pwm-tin clock for system timer"); - - tdiv = clk_get(&tmpdev.dev, "pwm-tdiv"); - if (IS_ERR(tdiv)) - panic("failed to get pwm-tdiv clock for system timer"); - } - - clk_enable(tin); -} - -static struct syscore_ops s3c24xx_syscore_ops = { - .resume = s3c2410_timer_setup, -}; - -void __init s3c24xx_timer_init(void) -{ - arch_gettimeoffset = s3c2410_gettimeoffset; - - s3c2410_timer_resources(); - s3c2410_timer_setup(); - setup_irq(IRQ_TIMER4, &s3c2410_timer_irq); - register_syscore_ops(&s3c24xx_syscore_ops); -} diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 224b44ab534e..70b8cd4021c4 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -261,7 +261,7 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt, void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt) { unsigned long size, mask; - bool page64k = IS_ENABLED(ARM64_64K_PAGES); + bool page64k = IS_ENABLED(CONFIG_ARM64_64K_PAGES); pgd_t *pgd; pud_t *pud; pmd_t *pmd; diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index b323d8d3185b..7c2f6685bf43 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -1453,7 +1453,7 @@ static struct resource atmel_lcdfb0_resource[] = { }, }; DEFINE_DEV_DATA(atmel_lcdfb, 0); -DEV_CLK(hck1, atmel_lcdfb0, hsb, 7); +DEV_CLK(hclk, atmel_lcdfb0, hsb, 7); static struct clk atmel_lcdfb0_pixclk = { .name = "lcdc_clk", .dev = &atmel_lcdfb0_device.dev, @@ -1530,6 +1530,8 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, memcpy(info, data, sizeof(struct atmel_lcdfb_info)); info->default_monspecs = monspecs; + pdev->name = "at32ap-lcdfb"; + platform_device_register(pdev); return pdev; @@ -2246,7 +2248,7 @@ static __initdata struct clk *init_clocks[] = { &atmel_twi0_pclk, &atmel_mci0_pclk, #if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002) - &atmel_lcdfb0_hck1, + &atmel_lcdfb0_hclk, &atmel_lcdfb0_pixclk, #endif &ssc0_pclk, diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index e34f565f595a..6f7dc8b7b35c 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -291,7 +291,6 @@ cpu_idle (void) } if (!need_resched()) { - void (*idle)(void); #ifdef CONFIG_SMP min_xtp(); #endif @@ -299,9 +298,7 @@ cpu_idle (void) if (mark_idle) (*mark_idle)(1); - if (!idle) - idle = default_idle; - (*idle)(); + default_idle(); if (mark_idle) (*mark_idle)(0); #ifdef CONFIG_SMP diff --git a/arch/powerpc/kernel/epapr_paravirt.c b/arch/powerpc/kernel/epapr_paravirt.c index f3eab8594d9f..d44a571e45a7 100644 --- a/arch/powerpc/kernel/epapr_paravirt.c +++ b/arch/powerpc/kernel/epapr_paravirt.c @@ -23,8 +23,10 @@ #include <asm/code-patching.h> #include <asm/machdep.h> +#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64) extern void epapr_ev_idle(void); extern u32 epapr_ev_idle_start[]; +#endif bool epapr_paravirt_enabled; @@ -47,11 +49,15 @@ static int __init epapr_paravirt_init(void) for (i = 0; i < (len / 4); i++) { patch_instruction(epapr_hypercall_start + i, insts[i]); +#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64) patch_instruction(epapr_ev_idle_start + i, insts[i]); +#endif } +#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64) if (of_get_property(hyper_node, "has-idle", NULL)) ppc_md.power_save = epapr_ev_idle; +#endif epapr_paravirt_enabled = true; diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 200afa5bcfb7..56bd92362ce1 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1066,78 +1066,6 @@ unrecov_user_slb: #endif /* __DISABLED__ */ -/* - * r13 points to the PACA, r9 contains the saved CR, - * r12 contain the saved SRR1, SRR0 is still ready for return - * r3 has the faulting address - * r9 - r13 are saved in paca->exslb. - * r3 is saved in paca->slb_r3 - * We assume we aren't going to take any exceptions during this procedure. - */ -_GLOBAL(slb_miss_realmode) - mflr r10 -#ifdef CONFIG_RELOCATABLE - mtctr r11 -#endif - - stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ - std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ - - bl .slb_allocate_realmode - - /* All done -- return from exception. */ - - ld r10,PACA_EXSLB+EX_LR(r13) - ld r3,PACA_EXSLB+EX_R3(r13) - lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ - - mtlr r10 - - andi. r10,r12,MSR_RI /* check for unrecoverable exception */ - beq- 2f - -.machine push -.machine "power4" - mtcrf 0x80,r9 - mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ -.machine pop - - RESTORE_PPR_PACA(PACA_EXSLB, r9) - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - ld r11,PACA_EXSLB+EX_R11(r13) - ld r12,PACA_EXSLB+EX_R12(r13) - ld r13,PACA_EXSLB+EX_R13(r13) - rfid - b . /* prevent speculative execution */ - -2: mfspr r11,SPRN_SRR0 - ld r10,PACAKBASE(r13) - LOAD_HANDLER(r10,unrecov_slb) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - mtspr SPRN_SRR1,r10 - rfid - b . - -unrecov_slb: - EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) - DISABLE_INTS - bl .save_nvgprs -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception - b 1b - - -#ifdef CONFIG_PPC_970_NAP -power4_fixup_nap: - andc r9,r9,r10 - std r9,TI_LOCAL_FLAGS(r11) - ld r10,_LINK(r1) /* make idle task do the */ - std r10,_NIP(r1) /* equivalent of a blr */ - blr -#endif - .align 7 .globl alignment_common alignment_common: @@ -1336,6 +1264,78 @@ _GLOBAL(opal_mc_secondary_handler) /* + * r13 points to the PACA, r9 contains the saved CR, + * r12 contain the saved SRR1, SRR0 is still ready for return + * r3 has the faulting address + * r9 - r13 are saved in paca->exslb. + * r3 is saved in paca->slb_r3 + * We assume we aren't going to take any exceptions during this procedure. + */ +_GLOBAL(slb_miss_realmode) + mflr r10 +#ifdef CONFIG_RELOCATABLE + mtctr r11 +#endif + + stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ + std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ + + bl .slb_allocate_realmode + + /* All done -- return from exception. */ + + ld r10,PACA_EXSLB+EX_LR(r13) + ld r3,PACA_EXSLB+EX_R3(r13) + lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ + + mtlr r10 + + andi. r10,r12,MSR_RI /* check for unrecoverable exception */ + beq- 2f + +.machine push +.machine "power4" + mtcrf 0x80,r9 + mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ +.machine pop + + RESTORE_PPR_PACA(PACA_EXSLB, r9) + ld r9,PACA_EXSLB+EX_R9(r13) + ld r10,PACA_EXSLB+EX_R10(r13) + ld r11,PACA_EXSLB+EX_R11(r13) + ld r12,PACA_EXSLB+EX_R12(r13) + ld r13,PACA_EXSLB+EX_R13(r13) + rfid + b . /* prevent speculative execution */ + +2: mfspr r11,SPRN_SRR0 + ld r10,PACAKBASE(r13) + LOAD_HANDLER(r10,unrecov_slb) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) + mtspr SPRN_SRR1,r10 + rfid + b . + +unrecov_slb: + EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) + DISABLE_INTS + bl .save_nvgprs +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b 1b + + +#ifdef CONFIG_PPC_970_NAP +power4_fixup_nap: + andc r9,r9,r10 + std r9,TI_LOCAL_FLAGS(r11) + ld r10,_LINK(r1) /* make idle task do the */ + std r10,_NIP(r1) /* equivalent of a blr */ + blr +#endif + +/* * Hash table stuff */ .align 7 diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index c20d1ce62dc6..e709884d0ef9 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -382,14 +382,14 @@ HYPERVISOR_console_io(int cmd, int count, char *str) return _hypercall3(int, console_io, cmd, count, str); } -extern int __must_check HYPERVISOR_physdev_op_compat(int, void *); +extern int __must_check xen_physdev_op_compat(int, void *); static inline int HYPERVISOR_physdev_op(int cmd, void *arg) { int rc = _hypercall2(int, physdev_op, cmd, arg); if (unlikely(rc == -ENOSYS)) - rc = HYPERVISOR_physdev_op_compat(cmd, arg); + rc = xen_physdev_op_compat(cmd, arg); return rc; } diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index 892ce40a7470..7a060f4b411f 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -44,6 +44,7 @@ #define SNB_C1_AUTO_UNDEMOTE (1UL << 27) #define SNB_C3_AUTO_UNDEMOTE (1UL << 28) +#define MSR_PLATFORM_INFO 0x000000ce #define MSR_MTRRcap 0x000000fe #define MSR_IA32_BBL_CR_CTL 0x00000119 #define MSR_IA32_BBL_CR_CTL3 0x0000011e diff --git a/arch/x86/kernel/microcode_intel_early.c b/arch/x86/kernel/microcode_intel_early.c index 7890bc838952..d893e8ed8ac9 100644 --- a/arch/x86/kernel/microcode_intel_early.c +++ b/arch/x86/kernel/microcode_intel_early.c @@ -90,13 +90,13 @@ microcode_phys(struct microcode_intel **mc_saved_tmp, struct microcode_intel ***mc_saved; mc_saved = (struct microcode_intel ***) - __pa_symbol(&mc_saved_data->mc_saved); + __pa_nodebug(&mc_saved_data->mc_saved); for (i = 0; i < mc_saved_data->mc_saved_count; i++) { struct microcode_intel *p; p = *(struct microcode_intel **) - __pa(mc_saved_data->mc_saved + i); - mc_saved_tmp[i] = (struct microcode_intel *)__pa(p); + __pa_nodebug(mc_saved_data->mc_saved + i); + mc_saved_tmp[i] = (struct microcode_intel *)__pa_nodebug(p); } } #endif @@ -562,7 +562,7 @@ scan_microcode(unsigned long start, unsigned long end, struct cpio_data cd; long offset = 0; #ifdef CONFIG_X86_32 - char *p = (char *)__pa_symbol(ucode_name); + char *p = (char *)__pa_nodebug(ucode_name); #else char *p = ucode_name; #endif @@ -630,8 +630,8 @@ static void __cpuinit print_ucode(struct ucode_cpu_info *uci) if (mc_intel == NULL) return; - delay_ucode_info_p = (int *)__pa_symbol(&delay_ucode_info); - current_mc_date_p = (int *)__pa_symbol(¤t_mc_date); + delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info); + current_mc_date_p = (int *)__pa_nodebug(¤t_mc_date); *delay_ucode_info_p = 1; *current_mc_date_p = mc_intel->hdr.date; @@ -659,8 +659,8 @@ static inline void __cpuinit print_ucode(struct ucode_cpu_info *uci) } #endif -static int apply_microcode_early(struct mc_saved_data *mc_saved_data, - struct ucode_cpu_info *uci) +static int __cpuinit apply_microcode_early(struct mc_saved_data *mc_saved_data, + struct ucode_cpu_info *uci) { struct microcode_intel *mc_intel; unsigned int val[2]; @@ -741,15 +741,15 @@ load_ucode_intel_bsp(void) #ifdef CONFIG_X86_32 struct boot_params *boot_params_p; - boot_params_p = (struct boot_params *)__pa_symbol(&boot_params); + boot_params_p = (struct boot_params *)__pa_nodebug(&boot_params); ramdisk_image = boot_params_p->hdr.ramdisk_image; ramdisk_size = boot_params_p->hdr.ramdisk_size; initrd_start_early = ramdisk_image; initrd_end_early = initrd_start_early + ramdisk_size; _load_ucode_intel_bsp( - (struct mc_saved_data *)__pa_symbol(&mc_saved_data), - (unsigned long *)__pa_symbol(&mc_saved_in_initrd), + (struct mc_saved_data *)__pa_nodebug(&mc_saved_data), + (unsigned long *)__pa_nodebug(&mc_saved_in_initrd), initrd_start_early, initrd_end_early, &uci); #else ramdisk_image = boot_params.hdr.ramdisk_image; @@ -772,10 +772,10 @@ void __cpuinit load_ucode_intel_ap(void) unsigned long *initrd_start_p; mc_saved_in_initrd_p = - (unsigned long *)__pa_symbol(mc_saved_in_initrd); - mc_saved_data_p = (struct mc_saved_data *)__pa_symbol(&mc_saved_data); - initrd_start_p = (unsigned long *)__pa_symbol(&initrd_start); - initrd_start_addr = (unsigned long)__pa_symbol(*initrd_start_p); + (unsigned long *)__pa_nodebug(mc_saved_in_initrd); + mc_saved_data_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data); + initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start); + initrd_start_addr = (unsigned long)__pa_nodebug(*initrd_start_p); #else mc_saved_data_p = &mc_saved_data; mc_saved_in_initrd_p = mc_saved_in_initrd; diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index 05928aae911e..906fea315791 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -74,10 +74,10 @@ copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest) char c; unsigned zero_len; - for (; len; --len) { + for (; len; --len, to++) { if (__get_user_nocheck(c, from++, sizeof(char))) break; - if (__put_user_nocheck(c, to++, sizeof(char))) + if (__put_user_nocheck(c, to, sizeof(char))) break; } diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index e8e34938c57d..6afbb2ca9a0a 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1467,8 +1467,6 @@ static void __init xen_write_cr3_init(unsigned long cr3) __xen_write_cr3(true, cr3); xen_mc_issue(PARAVIRT_LAZY_CPU); /* interrupts restored */ - - pv_mmu_ops.write_cr3 = &xen_write_cr3; } #endif @@ -2122,6 +2120,7 @@ static void __init xen_post_allocator_init(void) #endif #ifdef CONFIG_X86_64 + pv_mmu_ops.write_cr3 = &xen_write_cr3; SetPagePinned(virt_to_page(level3_user_vsyscall)); #endif xen_mark_init_mm_pinned(); diff --git a/block/blk-flush.c b/block/blk-flush.c index db8f1b507857..cc2b827a853c 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -444,7 +444,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, * copied from blk_rq_pos(rq). */ if (error_sector) - *error_sector = bio->bi_sector; + *error_sector = bio->bi_sector; if (!bio_flagged(bio, BIO_UPTODATE)) ret = -EIO; diff --git a/block/partition-generic.c b/block/partition-generic.c index 789cdea05893..ae95ee6a58aa 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -257,6 +257,7 @@ void delete_partition(struct gendisk *disk, int partno) hd_struct_put(part); } +EXPORT_SYMBOL(delete_partition); static ssize_t whole_disk_show(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c index 1e5d8a40101e..fefc2ca7cc3e 100644 --- a/drivers/acpi/apei/cper.c +++ b/drivers/acpi/apei/cper.c @@ -405,7 +405,7 @@ int apei_estatus_check(const struct acpi_hest_generic_status *estatus) return rc; data_len = estatus->data_length; gdata = (struct acpi_hest_generic_data *)(estatus + 1); - while (data_len > sizeof(*gdata)) { + while (data_len >= sizeof(*gdata)) { gedata_len = gdata->error_data_length; if (gedata_len > data_len - sizeof(*gdata)) return -EINVAL; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0ac546d5e53f..5ff173066127 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -646,6 +646,7 @@ static void handle_root_bridge_insertion(acpi_handle handle) static void handle_root_bridge_removal(struct acpi_device *device) { + acpi_status status; struct acpi_eject_event *ej_event; ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); @@ -661,7 +662,9 @@ static void handle_root_bridge_removal(struct acpi_device *device) ej_event->device = device; ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; - acpi_bus_hot_remove_device(ej_event); + status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event); + if (ACPI_FAILURE(status)) + kfree(ej_event); } static void _handle_hotplug_event_root(struct work_struct *work) @@ -676,8 +679,9 @@ static void _handle_hotplug_event_root(struct work_struct *work) handle = hp_work->handle; type = hp_work->type; - root = acpi_pci_find_root(handle); + acpi_scan_lock_acquire(); + root = acpi_pci_find_root(handle); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { @@ -711,6 +715,7 @@ static void _handle_hotplug_event_root(struct work_struct *work) break; } + acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ kfree(buffer.pointer); } diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 24213033fbae..9c1a435d10e6 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -193,6 +193,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, { .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW21M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21M"), + }, + }, + { + .callback = init_nvs_nosave, .ident = "Sony Vaio VPCEB17FX", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 5dc0daed8fac..b81ddfea1da0 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -532,11 +532,11 @@ config BLK_DEV_RBD If unsure, say N. config BLK_DEV_RSXX - tristate "RamSam PCIe Flash SSD Device Driver" + tristate "IBM FlashSystem 70/80 PCIe SSD Device Driver" depends on PCI help Device driver for IBM's high speed PCIe SSD - storage devices: RamSan-70 and RamSan-80. + storage devices: FlashSystem-70 and FlashSystem-80. To compile this driver as a module, choose M here: the module will be called rsxx. diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index ade58bc8f3c4..1c1b8e544aa2 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -4206,7 +4206,7 @@ static int cciss_find_cfgtables(ctlr_info_t *h) if (rc) return rc; h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, - cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable)); + cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); if (!h->cfgtable) return -ENOMEM; rc = write_driver_ver_to_cfgtable(h->cfgtable); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 747bb2af69dc..fe5f6403417f 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1044,12 +1044,29 @@ static int loop_clr_fd(struct loop_device *lo) lo->lo_state = Lo_unbound; /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); - if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev) - ioctl_by_bdev(bdev, BLKRRPART, 0); lo->lo_flags = 0; if (!part_shift) lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; mutex_unlock(&lo->lo_ctl_mutex); + + /* + * Remove all partitions, since BLKRRPART won't remove user + * added partitions when max_part=0 + */ + if (bdev) { + struct disk_part_iter piter; + struct hd_struct *part; + + mutex_lock_nested(&bdev->bd_mutex, 1); + invalidate_partition(bdev->bd_disk, 0); + disk_part_iter_init(&piter, bdev->bd_disk, + DISK_PITER_INCL_EMPTY); + while ((part = disk_part_iter_next(&piter))) + delete_partition(bdev->bd_disk, part->partno); + disk_part_iter_exit(&piter); + mutex_unlock(&bdev->bd_mutex); + } + /* * Need not hold lo_ctl_mutex to fput backing file. * Calling fput holding lo_ctl_mutex triggers a circular @@ -1623,6 +1640,7 @@ static int loop_add(struct loop_device **l, int i) goto out_free_dev; i = err; + err = -ENOMEM; lo->lo_queue = blk_alloc_queue(GFP_KERNEL); if (!lo->lo_queue) goto out_free_dev; diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 1788f491e0fb..076ae7f1b781 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -890,8 +890,10 @@ static int mg_probe(struct platform_device *plat_dev) gpio_direction_output(host->rst, 1); /* reset out pin */ - if (!(prv_data->dev_attr & MG_DEV_MASK)) + if (!(prv_data->dev_attr & MG_DEV_MASK)) { + err = -EINVAL; goto probe_err_3a; + } if (prv_data->dev_attr != MG_BOOT_DEV) { rsc = platform_get_resource_byname(plat_dev, IORESOURCE_IO, diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 11cc9522cdd4..92250af84e7d 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -4224,6 +4224,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, dd->isr_workq = create_workqueue(dd->workq_name); if (!dd->isr_workq) { dev_warn(&pdev->dev, "Can't create wq %d\n", dd->instance); + rv = -ENOMEM; goto block_initialize_err; } @@ -4282,7 +4283,8 @@ static int mtip_pci_probe(struct pci_dev *pdev, INIT_WORK(&dd->work[7].work, mtip_workq_sdbf7); pci_set_master(pdev); - if (pci_enable_msi(pdev)) { + rv = pci_enable_msi(pdev); + if (rv) { dev_warn(&pdev->dev, "Unable to enable MSI interrupt.\n"); goto block_initialize_err; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 6c81a4c040b9..f556f8a8b3f9 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1264,6 +1264,32 @@ static bool obj_request_done_test(struct rbd_obj_request *obj_request) return atomic_read(&obj_request->done) != 0; } +static void +rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request) +{ + dout("%s: obj %p img %p result %d %llu/%llu\n", __func__, + obj_request, obj_request->img_request, obj_request->result, + obj_request->xferred, obj_request->length); + /* + * ENOENT means a hole in the image. We zero-fill the + * entire length of the request. A short read also implies + * zero-fill to the end of the request. Either way we + * update the xferred count to indicate the whole request + * was satisfied. + */ + BUG_ON(obj_request->type != OBJ_REQUEST_BIO); + if (obj_request->result == -ENOENT) { + zero_bio_chain(obj_request->bio_list, 0); + obj_request->result = 0; + obj_request->xferred = obj_request->length; + } else if (obj_request->xferred < obj_request->length && + !obj_request->result) { + zero_bio_chain(obj_request->bio_list, obj_request->xferred); + obj_request->xferred = obj_request->length; + } + obj_request_done_set(obj_request); +} + static void rbd_obj_request_complete(struct rbd_obj_request *obj_request) { dout("%s: obj %p cb %p\n", __func__, obj_request, @@ -1284,23 +1310,10 @@ static void rbd_osd_read_callback(struct rbd_obj_request *obj_request) { dout("%s: obj %p result %d %llu/%llu\n", __func__, obj_request, obj_request->result, obj_request->xferred, obj_request->length); - /* - * ENOENT means a hole in the object. We zero-fill the - * entire length of the request. A short read also implies - * zero-fill to the end of the request. Either way we - * update the xferred count to indicate the whole request - * was satisfied. - */ - if (obj_request->result == -ENOENT) { - zero_bio_chain(obj_request->bio_list, 0); - obj_request->result = 0; - obj_request->xferred = obj_request->length; - } else if (obj_request->xferred < obj_request->length && - !obj_request->result) { - zero_bio_chain(obj_request->bio_list, obj_request->xferred); - obj_request->xferred = obj_request->length; - } - obj_request_done_set(obj_request); + if (obj_request->img_request) + rbd_img_obj_request_read_callback(obj_request); + else + obj_request_done_set(obj_request); } static void rbd_osd_write_callback(struct rbd_obj_request *obj_request) diff --git a/drivers/block/rsxx/Makefile b/drivers/block/rsxx/Makefile index f35cd0b71f7b..b1c53c0aa450 100644 --- a/drivers/block/rsxx/Makefile +++ b/drivers/block/rsxx/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_BLK_DEV_RSXX) += rsxx.o -rsxx-y := config.o core.o cregs.o dev.o dma.o +rsxx-objs := config.o core.o cregs.o dev.o dma.o diff --git a/drivers/block/rsxx/config.c b/drivers/block/rsxx/config.c index a295e7e9ee41..10cd530d3e10 100644 --- a/drivers/block/rsxx/config.c +++ b/drivers/block/rsxx/config.c @@ -29,15 +29,13 @@ #include "rsxx_priv.h" #include "rsxx_cfg.h" -static void initialize_config(void *config) +static void initialize_config(struct rsxx_card_cfg *cfg) { - struct rsxx_card_cfg *cfg = config; - cfg->hdr.version = RSXX_CFG_VERSION; cfg->data.block_size = RSXX_HW_BLK_SIZE; cfg->data.stripe_size = RSXX_HW_BLK_SIZE; - cfg->data.vendor_id = RSXX_VENDOR_ID_TMS_IBM; + cfg->data.vendor_id = RSXX_VENDOR_ID_IBM; cfg->data.cache_order = (-1); cfg->data.intr_coal.mode = RSXX_INTR_COAL_DISABLED; cfg->data.intr_coal.count = 0; @@ -181,7 +179,7 @@ int rsxx_load_config(struct rsxx_cardinfo *card) } else { dev_info(CARD_TO_DEV(card), "Initializing card configuration.\n"); - initialize_config(card); + initialize_config(&card->config); st = rsxx_save_config(card); if (st) return st; diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index e5162487686a..5af21f2db29c 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -30,6 +30,7 @@ #include <linux/reboot.h> #include <linux/slab.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <linux/genhd.h> #include <linux/idr.h> @@ -39,8 +40,8 @@ #define NO_LEGACY 0 -MODULE_DESCRIPTION("IBM RamSan PCIe Flash SSD Device Driver"); -MODULE_AUTHOR("IBM <support@ramsan.com>"); +MODULE_DESCRIPTION("IBM FlashSystem 70/80 PCIe SSD Device Driver"); +MODULE_AUTHOR("Joshua Morris/Philip Kelleher, IBM"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION); @@ -52,6 +53,13 @@ static DEFINE_IDA(rsxx_disk_ida); static DEFINE_SPINLOCK(rsxx_ida_lock); /*----------------- Interrupt Control & Handling -------------------*/ + +static void rsxx_mask_interrupts(struct rsxx_cardinfo *card) +{ + card->isr_mask = 0; + card->ier_mask = 0; +} + static void __enable_intr(unsigned int *mask, unsigned int intr) { *mask |= intr; @@ -71,7 +79,8 @@ static void __disable_intr(unsigned int *mask, unsigned int intr) */ void rsxx_enable_ier(struct rsxx_cardinfo *card, unsigned int intr) { - if (unlikely(card->halt)) + if (unlikely(card->halt) || + unlikely(card->eeh_state)) return; __enable_intr(&card->ier_mask, intr); @@ -80,6 +89,9 @@ void rsxx_enable_ier(struct rsxx_cardinfo *card, unsigned int intr) void rsxx_disable_ier(struct rsxx_cardinfo *card, unsigned int intr) { + if (unlikely(card->eeh_state)) + return; + __disable_intr(&card->ier_mask, intr); iowrite32(card->ier_mask, card->regmap + IER); } @@ -87,7 +99,8 @@ void rsxx_disable_ier(struct rsxx_cardinfo *card, unsigned int intr) void rsxx_enable_ier_and_isr(struct rsxx_cardinfo *card, unsigned int intr) { - if (unlikely(card->halt)) + if (unlikely(card->halt) || + unlikely(card->eeh_state)) return; __enable_intr(&card->isr_mask, intr); @@ -97,6 +110,9 @@ void rsxx_enable_ier_and_isr(struct rsxx_cardinfo *card, void rsxx_disable_ier_and_isr(struct rsxx_cardinfo *card, unsigned int intr) { + if (unlikely(card->eeh_state)) + return; + __disable_intr(&card->isr_mask, intr); __disable_intr(&card->ier_mask, intr); iowrite32(card->ier_mask, card->regmap + IER); @@ -115,6 +131,9 @@ static irqreturn_t rsxx_isr(int irq, void *pdata) do { reread_isr = 0; + if (unlikely(card->eeh_state)) + break; + isr = ioread32(card->regmap + ISR); if (isr == 0xffffffff) { /* @@ -161,9 +180,9 @@ static irqreturn_t rsxx_isr(int irq, void *pdata) } /*----------------- Card Event Handler -------------------*/ -static char *rsxx_card_state_to_str(unsigned int state) +static const char * const rsxx_card_state_to_str(unsigned int state) { - static char *state_strings[] = { + static const char * const state_strings[] = { "Unknown", "Shutdown", "Starting", "Formatting", "Uninitialized", "Good", "Shutting Down", "Fault", "Read Only Fault", "dStroying" @@ -304,6 +323,192 @@ static int card_shutdown(struct rsxx_cardinfo *card) return 0; } +static int rsxx_eeh_frozen(struct pci_dev *dev) +{ + struct rsxx_cardinfo *card = pci_get_drvdata(dev); + int i; + int st; + + dev_warn(&dev->dev, "IBM FlashSystem PCI: preparing for slot reset.\n"); + + card->eeh_state = 1; + rsxx_mask_interrupts(card); + + /* + * We need to guarantee that the write for eeh_state and masking + * interrupts does not become reordered. This will prevent a possible + * race condition with the EEH code. + */ + wmb(); + + pci_disable_device(dev); + + st = rsxx_eeh_save_issued_dmas(card); + if (st) + return st; + + rsxx_eeh_save_issued_creg(card); + + for (i = 0; i < card->n_targets; i++) { + if (card->ctrl[i].status.buf) + pci_free_consistent(card->dev, STATUS_BUFFER_SIZE8, + card->ctrl[i].status.buf, + card->ctrl[i].status.dma_addr); + if (card->ctrl[i].cmd.buf) + pci_free_consistent(card->dev, COMMAND_BUFFER_SIZE8, + card->ctrl[i].cmd.buf, + card->ctrl[i].cmd.dma_addr); + } + + return 0; +} + +static void rsxx_eeh_failure(struct pci_dev *dev) +{ + struct rsxx_cardinfo *card = pci_get_drvdata(dev); + int i; + + dev_err(&dev->dev, "IBM FlashSystem PCI: disabling failed card.\n"); + + card->eeh_state = 1; + + for (i = 0; i < card->n_targets; i++) + del_timer_sync(&card->ctrl[i].activity_timer); + + rsxx_eeh_cancel_dmas(card); +} + +static int rsxx_eeh_fifo_flush_poll(struct rsxx_cardinfo *card) +{ + unsigned int status; + int iter = 0; + + /* We need to wait for the hardware to reset */ + while (iter++ < 10) { + status = ioread32(card->regmap + PCI_RECONFIG); + + if (status & RSXX_FLUSH_BUSY) { + ssleep(1); + continue; + } + + if (status & RSXX_FLUSH_TIMEOUT) + dev_warn(CARD_TO_DEV(card), "HW: flash controller timeout\n"); + return 0; + } + + /* Hardware failed resetting itself. */ + return -1; +} + +static pci_ers_result_t rsxx_error_detected(struct pci_dev *dev, + enum pci_channel_state error) +{ + int st; + + if (dev->revision < RSXX_EEH_SUPPORT) + return PCI_ERS_RESULT_NONE; + + if (error == pci_channel_io_perm_failure) { + rsxx_eeh_failure(dev); + return PCI_ERS_RESULT_DISCONNECT; + } + + st = rsxx_eeh_frozen(dev); + if (st) { + dev_err(&dev->dev, "Slot reset setup failed\n"); + rsxx_eeh_failure(dev); + return PCI_ERS_RESULT_DISCONNECT; + } + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev) +{ + struct rsxx_cardinfo *card = pci_get_drvdata(dev); + unsigned long flags; + int i; + int st; + + dev_warn(&dev->dev, + "IBM FlashSystem PCI: recovering from slot reset.\n"); + + st = pci_enable_device(dev); + if (st) + goto failed_hw_setup; + + pci_set_master(dev); + + st = rsxx_eeh_fifo_flush_poll(card); + if (st) + goto failed_hw_setup; + + rsxx_dma_queue_reset(card); + + for (i = 0; i < card->n_targets; i++) { + st = rsxx_hw_buffers_init(dev, &card->ctrl[i]); + if (st) + goto failed_hw_buffers_init; + } + + if (card->config_valid) + rsxx_dma_configure(card); + + /* Clears the ISR register from spurious interrupts */ + st = ioread32(card->regmap + ISR); + + card->eeh_state = 0; + + st = rsxx_eeh_remap_dmas(card); + if (st) + goto failed_remap_dmas; + + spin_lock_irqsave(&card->irq_lock, flags); + if (card->n_targets & RSXX_MAX_TARGETS) + rsxx_enable_ier_and_isr(card, CR_INTR_ALL_G); + else + rsxx_enable_ier_and_isr(card, CR_INTR_ALL_C); + spin_unlock_irqrestore(&card->irq_lock, flags); + + rsxx_kick_creg_queue(card); + + for (i = 0; i < card->n_targets; i++) { + spin_lock(&card->ctrl[i].queue_lock); + if (list_empty(&card->ctrl[i].queue)) { + spin_unlock(&card->ctrl[i].queue_lock); + continue; + } + spin_unlock(&card->ctrl[i].queue_lock); + + queue_work(card->ctrl[i].issue_wq, + &card->ctrl[i].issue_dma_work); + } + + dev_info(&dev->dev, "IBM FlashSystem PCI: recovery complete.\n"); + + return PCI_ERS_RESULT_RECOVERED; + +failed_hw_buffers_init: +failed_remap_dmas: + for (i = 0; i < card->n_targets; i++) { + if (card->ctrl[i].status.buf) + pci_free_consistent(card->dev, + STATUS_BUFFER_SIZE8, + card->ctrl[i].status.buf, + card->ctrl[i].status.dma_addr); + if (card->ctrl[i].cmd.buf) + pci_free_consistent(card->dev, + COMMAND_BUFFER_SIZE8, + card->ctrl[i].cmd.buf, + card->ctrl[i].cmd.dma_addr); + } +failed_hw_setup: + rsxx_eeh_failure(dev); + return PCI_ERS_RESULT_DISCONNECT; + +} + /*----------------- Driver Initialization & Setup -------------------*/ /* Returns: 0 if the driver is compatible with the device -1 if the driver is NOT compatible with the device */ @@ -383,6 +588,7 @@ static int rsxx_pci_probe(struct pci_dev *dev, spin_lock_init(&card->irq_lock); card->halt = 0; + card->eeh_state = 0; spin_lock_irq(&card->irq_lock); rsxx_disable_ier_and_isr(card, CR_INTR_ALL); @@ -538,9 +744,6 @@ static void rsxx_pci_remove(struct pci_dev *dev) rsxx_disable_ier_and_isr(card, CR_INTR_EVENT); spin_unlock_irqrestore(&card->irq_lock, flags); - /* Prevent work_structs from re-queuing themselves. */ - card->halt = 1; - cancel_work_sync(&card->event_work); rsxx_destroy_dev(card); @@ -549,6 +752,10 @@ static void rsxx_pci_remove(struct pci_dev *dev) spin_lock_irqsave(&card->irq_lock, flags); rsxx_disable_ier_and_isr(card, CR_INTR_ALL); spin_unlock_irqrestore(&card->irq_lock, flags); + + /* Prevent work_structs from re-queuing themselves. */ + card->halt = 1; + free_irq(dev->irq, card); if (!force_legacy) @@ -592,11 +799,14 @@ static void rsxx_pci_shutdown(struct pci_dev *dev) card_shutdown(card); } +static const struct pci_error_handlers rsxx_err_handler = { + .error_detected = rsxx_error_detected, + .slot_reset = rsxx_slot_reset, +}; + static DEFINE_PCI_DEVICE_TABLE(rsxx_pci_ids) = { - {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS70_FLASH)}, - {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS70D_FLASH)}, - {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS80_FLASH)}, - {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS81_FLASH)}, + {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS70_FLASH)}, + {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS80_FLASH)}, {0,}, }; @@ -609,6 +819,7 @@ static struct pci_driver rsxx_pci_driver = { .remove = rsxx_pci_remove, .suspend = rsxx_pci_suspend, .shutdown = rsxx_pci_shutdown, + .err_handler = &rsxx_err_handler, }; static int __init rsxx_core_init(void) diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c index 80bbe639fccd..4b5c020a0a65 100644 --- a/drivers/block/rsxx/cregs.c +++ b/drivers/block/rsxx/cregs.c @@ -58,7 +58,7 @@ static struct kmem_cache *creg_cmd_pool; #error Unknown endianess!!! Aborting... #endif -static void copy_to_creg_data(struct rsxx_cardinfo *card, +static int copy_to_creg_data(struct rsxx_cardinfo *card, int cnt8, void *buf, unsigned int stream) @@ -66,6 +66,9 @@ static void copy_to_creg_data(struct rsxx_cardinfo *card, int i = 0; u32 *data = buf; + if (unlikely(card->eeh_state)) + return -EIO; + for (i = 0; cnt8 > 0; i++, cnt8 -= 4) { /* * Firmware implementation makes it necessary to byte swap on @@ -76,10 +79,12 @@ static void copy_to_creg_data(struct rsxx_cardinfo *card, else iowrite32(data[i], card->regmap + CREG_DATA(i)); } + + return 0; } -static void copy_from_creg_data(struct rsxx_cardinfo *card, +static int copy_from_creg_data(struct rsxx_cardinfo *card, int cnt8, void *buf, unsigned int stream) @@ -87,6 +92,9 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card, int i = 0; u32 *data = buf; + if (unlikely(card->eeh_state)) + return -EIO; + for (i = 0; cnt8 > 0; i++, cnt8 -= 4) { /* * Firmware implementation makes it necessary to byte swap on @@ -97,41 +105,31 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card, else data[i] = ioread32(card->regmap + CREG_DATA(i)); } -} - -static struct creg_cmd *pop_active_cmd(struct rsxx_cardinfo *card) -{ - struct creg_cmd *cmd; - /* - * Spin lock is needed because this can be called in atomic/interrupt - * context. - */ - spin_lock_bh(&card->creg_ctrl.lock); - cmd = card->creg_ctrl.active_cmd; - card->creg_ctrl.active_cmd = NULL; - spin_unlock_bh(&card->creg_ctrl.lock); - - return cmd; + return 0; } static void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd) { + int st; + + if (unlikely(card->eeh_state)) + return; + iowrite32(cmd->addr, card->regmap + CREG_ADD); iowrite32(cmd->cnt8, card->regmap + CREG_CNT); if (cmd->op == CREG_OP_WRITE) { - if (cmd->buf) - copy_to_creg_data(card, cmd->cnt8, - cmd->buf, cmd->stream); + if (cmd->buf) { + st = copy_to_creg_data(card, cmd->cnt8, + cmd->buf, cmd->stream); + if (st) + return; + } } - /* - * Data copy must complete before initiating the command. This is - * needed for weakly ordered processors (i.e. PowerPC), so that all - * neccessary registers are written before we kick the hardware. - */ - wmb(); + if (unlikely(card->eeh_state)) + return; /* Setting the valid bit will kick off the command. */ iowrite32(cmd->op, card->regmap + CREG_CMD); @@ -196,11 +194,11 @@ static int creg_queue_cmd(struct rsxx_cardinfo *card, cmd->cb_private = cb_private; cmd->status = 0; - spin_lock(&card->creg_ctrl.lock); + spin_lock_bh(&card->creg_ctrl.lock); list_add_tail(&cmd->list, &card->creg_ctrl.queue); card->creg_ctrl.q_depth++; creg_kick_queue(card); - spin_unlock(&card->creg_ctrl.lock); + spin_unlock_bh(&card->creg_ctrl.lock); return 0; } @@ -210,7 +208,11 @@ static void creg_cmd_timed_out(unsigned long data) struct rsxx_cardinfo *card = (struct rsxx_cardinfo *) data; struct creg_cmd *cmd; - cmd = pop_active_cmd(card); + spin_lock(&card->creg_ctrl.lock); + cmd = card->creg_ctrl.active_cmd; + card->creg_ctrl.active_cmd = NULL; + spin_unlock(&card->creg_ctrl.lock); + if (cmd == NULL) { card->creg_ctrl.creg_stats.creg_timeout++; dev_warn(CARD_TO_DEV(card), @@ -247,7 +249,11 @@ static void creg_cmd_done(struct work_struct *work) if (del_timer_sync(&card->creg_ctrl.cmd_timer) == 0) card->creg_ctrl.creg_stats.failed_cancel_timer++; - cmd = pop_active_cmd(card); + spin_lock_bh(&card->creg_ctrl.lock); + cmd = card->creg_ctrl.active_cmd; + card->creg_ctrl.active_cmd = NULL; + spin_unlock_bh(&card->creg_ctrl.lock); + if (cmd == NULL) { dev_err(CARD_TO_DEV(card), "Spurious creg interrupt!\n"); @@ -287,7 +293,7 @@ static void creg_cmd_done(struct work_struct *work) goto creg_done; } - copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream); + st = copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream); } creg_done: @@ -296,10 +302,10 @@ creg_done: kmem_cache_free(creg_cmd_pool, cmd); - spin_lock(&card->creg_ctrl.lock); + spin_lock_bh(&card->creg_ctrl.lock); card->creg_ctrl.active = 0; creg_kick_queue(card); - spin_unlock(&card->creg_ctrl.lock); + spin_unlock_bh(&card->creg_ctrl.lock); } static void creg_reset(struct rsxx_cardinfo *card) @@ -324,7 +330,7 @@ static void creg_reset(struct rsxx_cardinfo *card) "Resetting creg interface for recovery\n"); /* Cancel outstanding commands */ - spin_lock(&card->creg_ctrl.lock); + spin_lock_bh(&card->creg_ctrl.lock); list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) { list_del(&cmd->list); card->creg_ctrl.q_depth--; @@ -345,7 +351,7 @@ static void creg_reset(struct rsxx_cardinfo *card) card->creg_ctrl.active = 0; } - spin_unlock(&card->creg_ctrl.lock); + spin_unlock_bh(&card->creg_ctrl.lock); card->creg_ctrl.reset = 0; spin_lock_irqsave(&card->irq_lock, flags); @@ -399,12 +405,12 @@ static int __issue_creg_rw(struct rsxx_cardinfo *card, return st; /* - * This timeout is neccessary for unresponsive hardware. The additional + * This timeout is necessary for unresponsive hardware. The additional * 20 seconds to used to guarantee that each cregs requests has time to * complete. */ - timeout = msecs_to_jiffies((CREG_TIMEOUT_MSEC * - card->creg_ctrl.q_depth) + 20000); + timeout = msecs_to_jiffies(CREG_TIMEOUT_MSEC * + card->creg_ctrl.q_depth + 20000); /* * The creg interface is guaranteed to complete. It has a timeout @@ -690,6 +696,32 @@ int rsxx_reg_access(struct rsxx_cardinfo *card, return 0; } +void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card) +{ + struct creg_cmd *cmd = NULL; + + cmd = card->creg_ctrl.active_cmd; + card->creg_ctrl.active_cmd = NULL; + + if (cmd) { + del_timer_sync(&card->creg_ctrl.cmd_timer); + + spin_lock_bh(&card->creg_ctrl.lock); + list_add(&cmd->list, &card->creg_ctrl.queue); + card->creg_ctrl.q_depth++; + card->creg_ctrl.active = 0; + spin_unlock_bh(&card->creg_ctrl.lock); + } +} + +void rsxx_kick_creg_queue(struct rsxx_cardinfo *card) +{ + spin_lock_bh(&card->creg_ctrl.lock); + if (!list_empty(&card->creg_ctrl.queue)) + creg_kick_queue(card); + spin_unlock_bh(&card->creg_ctrl.lock); +} + /*------------ Initialization & Setup --------------*/ int rsxx_creg_setup(struct rsxx_cardinfo *card) { @@ -712,7 +744,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card) int cnt = 0; /* Cancel outstanding commands */ - spin_lock(&card->creg_ctrl.lock); + spin_lock_bh(&card->creg_ctrl.lock); list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) { list_del(&cmd->list); if (cmd->cb) @@ -737,7 +769,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card) "Canceled active creg command\n"); kmem_cache_free(creg_cmd_pool, cmd); } - spin_unlock(&card->creg_ctrl.lock); + spin_unlock_bh(&card->creg_ctrl.lock); cancel_work_sync(&card->creg_ctrl.done_work); } diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 63176e67662f..0607513cfb41 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -28,7 +28,7 @@ struct rsxx_dma { struct list_head list; u8 cmd; - unsigned int laddr; /* Logical address on the ramsan */ + unsigned int laddr; /* Logical address */ struct { u32 off; u32 cnt; @@ -81,9 +81,6 @@ enum rsxx_hw_status { HW_STATUS_FAULT = 0x08, }; -#define STATUS_BUFFER_SIZE8 4096 -#define COMMAND_BUFFER_SIZE8 4096 - static struct kmem_cache *rsxx_dma_pool; struct dma_tracker { @@ -122,7 +119,7 @@ static unsigned int rsxx_get_dma_tgt(struct rsxx_cardinfo *card, u64 addr8) return tgt; } -static void rsxx_dma_queue_reset(struct rsxx_cardinfo *card) +void rsxx_dma_queue_reset(struct rsxx_cardinfo *card) { /* Reset all DMA Command/Status Queues */ iowrite32(DMA_QUEUE_RESET, card->regmap + RESET); @@ -210,7 +207,8 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card) u32 q_depth = 0; u32 intr_coal; - if (card->config.data.intr_coal.mode != RSXX_INTR_COAL_AUTO_TUNE) + if (card->config.data.intr_coal.mode != RSXX_INTR_COAL_AUTO_TUNE || + unlikely(card->eeh_state)) return; for (i = 0; i < card->n_targets; i++) @@ -223,31 +221,26 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card) } /*----------------- RSXX DMA Handling -------------------*/ -static void rsxx_complete_dma(struct rsxx_cardinfo *card, +static void rsxx_complete_dma(struct rsxx_dma_ctrl *ctrl, struct rsxx_dma *dma, unsigned int status) { if (status & DMA_SW_ERR) - printk_ratelimited(KERN_ERR - "SW Error in DMA(cmd x%02x, laddr x%08x)\n", - dma->cmd, dma->laddr); + ctrl->stats.dma_sw_err++; if (status & DMA_HW_FAULT) - printk_ratelimited(KERN_ERR - "HW Fault in DMA(cmd x%02x, laddr x%08x)\n", - dma->cmd, dma->laddr); + ctrl->stats.dma_hw_fault++; if (status & DMA_CANCELLED) - printk_ratelimited(KERN_ERR - "DMA Cancelled(cmd x%02x, laddr x%08x)\n", - dma->cmd, dma->laddr); + ctrl->stats.dma_cancelled++; if (dma->dma_addr) - pci_unmap_page(card->dev, dma->dma_addr, get_dma_size(dma), + pci_unmap_page(ctrl->card->dev, dma->dma_addr, + get_dma_size(dma), dma->cmd == HW_CMD_BLK_WRITE ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (dma->cb) - dma->cb(card, dma->cb_data, status ? 1 : 0); + dma->cb(ctrl->card, dma->cb_data, status ? 1 : 0); kmem_cache_free(rsxx_dma_pool, dma); } @@ -330,14 +323,15 @@ static void rsxx_handle_dma_error(struct rsxx_dma_ctrl *ctrl, if (requeue_cmd) rsxx_requeue_dma(ctrl, dma); else - rsxx_complete_dma(ctrl->card, dma, status); + rsxx_complete_dma(ctrl, dma, status); } static void dma_engine_stalled(unsigned long data) { struct rsxx_dma_ctrl *ctrl = (struct rsxx_dma_ctrl *)data; - if (atomic_read(&ctrl->stats.hw_q_depth) == 0) + if (atomic_read(&ctrl->stats.hw_q_depth) == 0 || + unlikely(ctrl->card->eeh_state)) return; if (ctrl->cmd.idx != ioread32(ctrl->regmap + SW_CMD_IDX)) { @@ -369,7 +363,8 @@ static void rsxx_issue_dmas(struct work_struct *work) ctrl = container_of(work, struct rsxx_dma_ctrl, issue_dma_work); hw_cmd_buf = ctrl->cmd.buf; - if (unlikely(ctrl->card->halt)) + if (unlikely(ctrl->card->halt) || + unlikely(ctrl->card->eeh_state)) return; while (1) { @@ -397,7 +392,7 @@ static void rsxx_issue_dmas(struct work_struct *work) */ if (unlikely(ctrl->card->dma_fault)) { push_tracker(ctrl->trackers, tag); - rsxx_complete_dma(ctrl->card, dma, DMA_CANCELLED); + rsxx_complete_dma(ctrl, dma, DMA_CANCELLED); continue; } @@ -432,19 +427,15 @@ static void rsxx_issue_dmas(struct work_struct *work) /* Let HW know we've queued commands. */ if (cmds_pending) { - /* - * We must guarantee that the CPU writes to 'ctrl->cmd.buf' - * (which is in PCI-consistent system-memory) from the loop - * above make it into the coherency domain before the - * following PIO "trigger" updating the cmd.idx. A WMB is - * sufficient. We need not explicitly CPU cache-flush since - * the memory is a PCI-consistent (ie; coherent) mapping. - */ - wmb(); - atomic_add(cmds_pending, &ctrl->stats.hw_q_depth); mod_timer(&ctrl->activity_timer, jiffies + DMA_ACTIVITY_TIMEOUT); + + if (unlikely(ctrl->card->eeh_state)) { + del_timer_sync(&ctrl->activity_timer); + return; + } + iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX); } } @@ -463,7 +454,8 @@ static void rsxx_dma_done(struct work_struct *work) hw_st_buf = ctrl->status.buf; if (unlikely(ctrl->card->halt) || - unlikely(ctrl->card->dma_fault)) + unlikely(ctrl->card->dma_fault) || + unlikely(ctrl->card->eeh_state)) return; count = le16_to_cpu(hw_st_buf[ctrl->status.idx].count); @@ -508,7 +500,7 @@ static void rsxx_dma_done(struct work_struct *work) if (status) rsxx_handle_dma_error(ctrl, dma, status); else - rsxx_complete_dma(ctrl->card, dma, 0); + rsxx_complete_dma(ctrl, dma, 0); push_tracker(ctrl->trackers, tag); @@ -727,20 +719,54 @@ bvec_err: /*----------------- DMA Engine Initialization & Setup -------------------*/ +int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl) +{ + ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8, + &ctrl->status.dma_addr); + ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8, + &ctrl->cmd.dma_addr); + if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL) + return -ENOMEM; + + memset(ctrl->status.buf, 0xac, STATUS_BUFFER_SIZE8); + iowrite32(lower_32_bits(ctrl->status.dma_addr), + ctrl->regmap + SB_ADD_LO); + iowrite32(upper_32_bits(ctrl->status.dma_addr), + ctrl->regmap + SB_ADD_HI); + + memset(ctrl->cmd.buf, 0x83, COMMAND_BUFFER_SIZE8); + iowrite32(lower_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_LO); + iowrite32(upper_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_HI); + + ctrl->status.idx = ioread32(ctrl->regmap + HW_STATUS_CNT); + if (ctrl->status.idx > RSXX_MAX_OUTSTANDING_CMDS) { + dev_crit(&dev->dev, "Failed reading status cnt x%x\n", + ctrl->status.idx); + return -EINVAL; + } + iowrite32(ctrl->status.idx, ctrl->regmap + HW_STATUS_CNT); + iowrite32(ctrl->status.idx, ctrl->regmap + SW_STATUS_CNT); + + ctrl->cmd.idx = ioread32(ctrl->regmap + HW_CMD_IDX); + if (ctrl->cmd.idx > RSXX_MAX_OUTSTANDING_CMDS) { + dev_crit(&dev->dev, "Failed reading cmd cnt x%x\n", + ctrl->status.idx); + return -EINVAL; + } + iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX); + iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX); + + return 0; +} + static int rsxx_dma_ctrl_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl) { int i; + int st; memset(&ctrl->stats, 0, sizeof(ctrl->stats)); - ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8, - &ctrl->status.dma_addr); - ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8, - &ctrl->cmd.dma_addr); - if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL) - return -ENOMEM; - ctrl->trackers = vmalloc(DMA_TRACKER_LIST_SIZE8); if (!ctrl->trackers) return -ENOMEM; @@ -770,35 +796,9 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev, INIT_WORK(&ctrl->issue_dma_work, rsxx_issue_dmas); INIT_WORK(&ctrl->dma_done_work, rsxx_dma_done); - memset(ctrl->status.buf, 0xac, STATUS_BUFFER_SIZE8); - iowrite32(lower_32_bits(ctrl->status.dma_addr), - ctrl->regmap + SB_ADD_LO); - iowrite32(upper_32_bits(ctrl->status.dma_addr), - ctrl->regmap + SB_ADD_HI); - - memset(ctrl->cmd.buf, 0x83, COMMAND_BUFFER_SIZE8); - iowrite32(lower_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_LO); - iowrite32(upper_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_HI); - - ctrl->status.idx = ioread32(ctrl->regmap + HW_STATUS_CNT); - if (ctrl->status.idx > RSXX_MAX_OUTSTANDING_CMDS) { - dev_crit(&dev->dev, "Failed reading status cnt x%x\n", - ctrl->status.idx); - return -EINVAL; - } - iowrite32(ctrl->status.idx, ctrl->regmap + HW_STATUS_CNT); - iowrite32(ctrl->status.idx, ctrl->regmap + SW_STATUS_CNT); - - ctrl->cmd.idx = ioread32(ctrl->regmap + HW_CMD_IDX); - if (ctrl->cmd.idx > RSXX_MAX_OUTSTANDING_CMDS) { - dev_crit(&dev->dev, "Failed reading cmd cnt x%x\n", - ctrl->status.idx); - return -EINVAL; - } - iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX); - iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX); - - wmb(); + st = rsxx_hw_buffers_init(dev, ctrl); + if (st) + return st; return 0; } @@ -834,7 +834,7 @@ static int rsxx_dma_stripe_setup(struct rsxx_cardinfo *card, return 0; } -static int rsxx_dma_configure(struct rsxx_cardinfo *card) +int rsxx_dma_configure(struct rsxx_cardinfo *card) { u32 intr_coal; @@ -980,6 +980,103 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card) } } +int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) +{ + int i; + int j; + int cnt; + struct rsxx_dma *dma; + struct list_head *issued_dmas; + + issued_dmas = kzalloc(sizeof(*issued_dmas) * card->n_targets, + GFP_KERNEL); + if (!issued_dmas) + return -ENOMEM; + + for (i = 0; i < card->n_targets; i++) { + INIT_LIST_HEAD(&issued_dmas[i]); + cnt = 0; + for (j = 0; j < RSXX_MAX_OUTSTANDING_CMDS; j++) { + dma = get_tracker_dma(card->ctrl[i].trackers, j); + if (dma == NULL) + continue; + + if (dma->cmd == HW_CMD_BLK_WRITE) + card->ctrl[i].stats.writes_issued--; + else if (dma->cmd == HW_CMD_BLK_DISCARD) + card->ctrl[i].stats.discards_issued--; + else + card->ctrl[i].stats.reads_issued--; + + list_add_tail(&dma->list, &issued_dmas[i]); + push_tracker(card->ctrl[i].trackers, j); + cnt++; + } + + spin_lock(&card->ctrl[i].queue_lock); + list_splice(&issued_dmas[i], &card->ctrl[i].queue); + + atomic_sub(cnt, &card->ctrl[i].stats.hw_q_depth); + card->ctrl[i].stats.sw_q_depth += cnt; + card->ctrl[i].e_cnt = 0; + + list_for_each_entry(dma, &card->ctrl[i].queue, list) { + if (dma->dma_addr) + pci_unmap_page(card->dev, dma->dma_addr, + get_dma_size(dma), + dma->cmd == HW_CMD_BLK_WRITE ? + PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE); + } + spin_unlock(&card->ctrl[i].queue_lock); + } + + kfree(issued_dmas); + + return 0; +} + +void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card) +{ + struct rsxx_dma *dma; + struct rsxx_dma *tmp; + int i; + + for (i = 0; i < card->n_targets; i++) { + spin_lock(&card->ctrl[i].queue_lock); + list_for_each_entry_safe(dma, tmp, &card->ctrl[i].queue, list) { + list_del(&dma->list); + + rsxx_complete_dma(&card->ctrl[i], dma, DMA_CANCELLED); + } + spin_unlock(&card->ctrl[i].queue_lock); + } +} + +int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card) +{ + struct rsxx_dma *dma; + int i; + + for (i = 0; i < card->n_targets; i++) { + spin_lock(&card->ctrl[i].queue_lock); + list_for_each_entry(dma, &card->ctrl[i].queue, list) { + dma->dma_addr = pci_map_page(card->dev, dma->page, + dma->pg_off, get_dma_size(dma), + dma->cmd == HW_CMD_BLK_WRITE ? + PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE); + if (!dma->dma_addr) { + spin_unlock(&card->ctrl[i].queue_lock); + kmem_cache_free(rsxx_dma_pool, dma); + return -ENOMEM; + } + } + spin_unlock(&card->ctrl[i].queue_lock); + } + + return 0; +} int rsxx_dma_init(void) { diff --git a/drivers/block/rsxx/rsxx.h b/drivers/block/rsxx/rsxx.h index 2e50b65902b7..24ba3642bd89 100644 --- a/drivers/block/rsxx/rsxx.h +++ b/drivers/block/rsxx/rsxx.h @@ -27,15 +27,17 @@ /*----------------- IOCTL Definitions -------------------*/ +#define RSXX_MAX_DATA 8 + struct rsxx_reg_access { __u32 addr; __u32 cnt; __u32 stat; __u32 stream; - __u32 data[8]; + __u32 data[RSXX_MAX_DATA]; }; -#define RSXX_MAX_REG_CNT (8 * (sizeof(__u32))) +#define RSXX_MAX_REG_CNT (RSXX_MAX_DATA * (sizeof(__u32))) #define RSXX_IOC_MAGIC 'r' diff --git a/drivers/block/rsxx/rsxx_cfg.h b/drivers/block/rsxx/rsxx_cfg.h index c025fe5fdb70..f384c943846d 100644 --- a/drivers/block/rsxx/rsxx_cfg.h +++ b/drivers/block/rsxx/rsxx_cfg.h @@ -58,7 +58,7 @@ struct rsxx_card_cfg { }; /* Vendor ID Values */ -#define RSXX_VENDOR_ID_TMS_IBM 0 +#define RSXX_VENDOR_ID_IBM 0 #define RSXX_VENDOR_ID_DSI 1 #define RSXX_VENDOR_COUNT 2 diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h index a1ac907d8f4c..382e8bf5c03b 100644 --- a/drivers/block/rsxx/rsxx_priv.h +++ b/drivers/block/rsxx/rsxx_priv.h @@ -45,16 +45,13 @@ struct proc_cmd; -#define PCI_VENDOR_ID_TMS_IBM 0x15B6 -#define PCI_DEVICE_ID_RS70_FLASH 0x0019 -#define PCI_DEVICE_ID_RS70D_FLASH 0x001A -#define PCI_DEVICE_ID_RS80_FLASH 0x001C -#define PCI_DEVICE_ID_RS81_FLASH 0x001E +#define PCI_DEVICE_ID_FS70_FLASH 0x04A9 +#define PCI_DEVICE_ID_FS80_FLASH 0x04AA #define RS70_PCI_REV_SUPPORTED 4 #define DRIVER_NAME "rsxx" -#define DRIVER_VERSION "3.7" +#define DRIVER_VERSION "4.0" /* Block size is 4096 */ #define RSXX_HW_BLK_SHIFT 12 @@ -67,6 +64,9 @@ struct proc_cmd; #define RSXX_MAX_OUTSTANDING_CMDS 255 #define RSXX_CS_IDX_MASK 0xff +#define STATUS_BUFFER_SIZE8 4096 +#define COMMAND_BUFFER_SIZE8 4096 + #define RSXX_MAX_TARGETS 8 struct dma_tracker_list; @@ -91,6 +91,9 @@ struct rsxx_dma_stats { u32 discards_failed; u32 done_rescheduled; u32 issue_rescheduled; + u32 dma_sw_err; + u32 dma_hw_fault; + u32 dma_cancelled; u32 sw_q_depth; /* Number of DMAs on the SW queue. */ atomic_t hw_q_depth; /* Number of DMAs queued to HW. */ }; @@ -116,6 +119,7 @@ struct rsxx_dma_ctrl { struct rsxx_cardinfo { struct pci_dev *dev; unsigned int halt; + unsigned int eeh_state; void __iomem *regmap; spinlock_t irq_lock; @@ -224,6 +228,7 @@ enum rsxx_pci_regmap { PERF_RD512_HI = 0xac, PERF_WR512_LO = 0xb0, PERF_WR512_HI = 0xb4, + PCI_RECONFIG = 0xb8, }; enum rsxx_intr { @@ -237,6 +242,8 @@ enum rsxx_intr { CR_INTR_DMA5 = 0x00000080, CR_INTR_DMA6 = 0x00000100, CR_INTR_DMA7 = 0x00000200, + CR_INTR_ALL_C = 0x0000003f, + CR_INTR_ALL_G = 0x000003ff, CR_INTR_DMA_ALL = 0x000003f5, CR_INTR_ALL = 0xffffffff, }; @@ -253,8 +260,14 @@ enum rsxx_pci_reset { DMA_QUEUE_RESET = 0x00000001, }; +enum rsxx_hw_fifo_flush { + RSXX_FLUSH_BUSY = 0x00000002, + RSXX_FLUSH_TIMEOUT = 0x00000004, +}; + enum rsxx_pci_revision { RSXX_DISCARD_SUPPORT = 2, + RSXX_EEH_SUPPORT = 3, }; enum rsxx_creg_cmd { @@ -360,11 +373,17 @@ int rsxx_dma_setup(struct rsxx_cardinfo *card); void rsxx_dma_destroy(struct rsxx_cardinfo *card); int rsxx_dma_init(void); void rsxx_dma_cleanup(void); +void rsxx_dma_queue_reset(struct rsxx_cardinfo *card); +int rsxx_dma_configure(struct rsxx_cardinfo *card); int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, struct bio *bio, atomic_t *n_dmas, rsxx_dma_cb cb, void *cb_data); +int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl); +int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card); +void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card); +int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card); /***** cregs.c *****/ int rsxx_creg_write(struct rsxx_cardinfo *card, u32 addr, @@ -389,10 +408,11 @@ int rsxx_creg_setup(struct rsxx_cardinfo *card); void rsxx_creg_destroy(struct rsxx_cardinfo *card); int rsxx_creg_init(void); void rsxx_creg_cleanup(void); - int rsxx_reg_access(struct rsxx_cardinfo *card, struct rsxx_reg_access __user *ucmd, int read); +void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card); +void rsxx_kick_creg_queue(struct rsxx_cardinfo *card); diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index de1f319f7bd7..dd5b2fed97e9 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -164,7 +164,7 @@ static void make_response(struct xen_blkif *blkif, u64 id, #define foreach_grant_safe(pos, n, rbtree, node) \ for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node), \ - (n) = rb_next(&(pos)->node); \ + (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL; \ &(pos)->node != NULL; \ (pos) = container_of(n, typeof(*(pos)), node), \ (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL) @@ -381,8 +381,8 @@ irqreturn_t xen_blkif_be_int(int irq, void *dev_id) static void print_stats(struct xen_blkif *blkif) { - pr_info("xen-blkback (%s): oo %3d | rd %4d | wr %4d | f %4d" - " | ds %4d\n", + pr_info("xen-blkback (%s): oo %3llu | rd %4llu | wr %4llu | f %4llu" + " | ds %4llu\n", current->comm, blkif->st_oo_req, blkif->st_rd_req, blkif->st_wr_req, blkif->st_f_req, blkif->st_ds_req); @@ -442,7 +442,7 @@ int xen_blkif_schedule(void *arg) } struct seg_buf { - unsigned long buf; + unsigned int offset; unsigned int nsec; }; /* @@ -621,30 +621,21 @@ static int xen_blkbk_map(struct blkif_request *req, * If this is a new persistent grant * save the handler */ - persistent_gnts[i]->handle = map[j].handle; - persistent_gnts[i]->dev_bus_addr = - map[j++].dev_bus_addr; + persistent_gnts[i]->handle = map[j++].handle; } pending_handle(pending_req, i) = persistent_gnts[i]->handle; if (ret) continue; - - seg[i].buf = persistent_gnts[i]->dev_bus_addr | - (req->u.rw.seg[i].first_sect << 9); } else { - pending_handle(pending_req, i) = map[j].handle; + pending_handle(pending_req, i) = map[j++].handle; bitmap_set(pending_req->unmap_seg, i, 1); - if (ret) { - j++; + if (ret) continue; - } - - seg[i].buf = map[j++].dev_bus_addr | - (req->u.rw.seg[i].first_sect << 9); } + seg[i].offset = (req->u.rw.seg[i].first_sect << 9); } return ret; } @@ -679,6 +670,16 @@ static int dispatch_discard_io(struct xen_blkif *blkif, return err; } +static int dispatch_other_io(struct xen_blkif *blkif, + struct blkif_request *req, + struct pending_req *pending_req) +{ + free_req(pending_req); + make_response(blkif, req->u.other.id, req->operation, + BLKIF_RSP_EOPNOTSUPP); + return -EIO; +} + static void xen_blk_drain_io(struct xen_blkif *blkif) { atomic_set(&blkif->drain, 1); @@ -800,17 +801,30 @@ __do_block_io_op(struct xen_blkif *blkif) /* Apply all sanity checks to /private copy/ of request. */ barrier(); - if (unlikely(req.operation == BLKIF_OP_DISCARD)) { + + switch (req.operation) { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + if (dispatch_rw_block_io(blkif, &req, pending_req)) + goto done; + break; + case BLKIF_OP_DISCARD: free_req(pending_req); if (dispatch_discard_io(blkif, &req)) - break; - } else if (dispatch_rw_block_io(blkif, &req, pending_req)) + goto done; break; + default: + if (dispatch_other_io(blkif, &req, pending_req)) + goto done; + break; + } /* Yield point for this unbounded loop. */ cond_resched(); } - +done: return more_to_do; } @@ -904,7 +918,8 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, pr_debug(DRV_PFX "access denied: %s of [%llu,%llu] on dev=%04x\n", operation == READ ? "read" : "write", preq.sector_number, - preq.sector_number + preq.nr_sects, preq.dev); + preq.sector_number + preq.nr_sects, + blkif->vbd.pdevice); goto fail_response; } @@ -947,7 +962,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, (bio_add_page(bio, pages[i], seg[i].nsec << 9, - seg[i].buf & ~PAGE_MASK) == 0)) { + seg[i].offset) == 0)) { bio = bio_alloc(GFP_KERNEL, nseg-i); if (unlikely(bio == NULL)) @@ -977,13 +992,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, bio->bi_end_io = end_block_io_op; } - /* - * We set it one so that the last submit_bio does not have to call - * atomic_inc. - */ atomic_set(&pending_req->pendcnt, nbio); - - /* Get a reference count for the disk queue and start sending I/O */ blk_start_plug(&plug); for (i = 0; i < nbio; i++) @@ -1011,6 +1020,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, fail_put_bio: for (i = 0; i < nbio; i++) bio_put(biolist[i]); + atomic_set(&pending_req->pendcnt, 1); __end_block_io_op(pending_req, -EINVAL); msleep(1); /* back off a bit */ return -EIO; diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 6072390c7f57..60103e2517ba 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -77,11 +77,18 @@ struct blkif_x86_32_request_discard { uint64_t nr_sectors; } __attribute__((__packed__)); +struct blkif_x86_32_request_other { + uint8_t _pad1; + blkif_vdev_t _pad2; + uint64_t id; /* private guest value, echoed in resp */ +} __attribute__((__packed__)); + struct blkif_x86_32_request { uint8_t operation; /* BLKIF_OP_??? */ union { struct blkif_x86_32_request_rw rw; struct blkif_x86_32_request_discard discard; + struct blkif_x86_32_request_other other; } u; } __attribute__((__packed__)); @@ -113,11 +120,19 @@ struct blkif_x86_64_request_discard { uint64_t nr_sectors; } __attribute__((__packed__)); +struct blkif_x86_64_request_other { + uint8_t _pad1; + blkif_vdev_t _pad2; + uint32_t _pad3; /* offsetof(blkif_..,u.discard.id)==8 */ + uint64_t id; /* private guest value, echoed in resp */ +} __attribute__((__packed__)); + struct blkif_x86_64_request { uint8_t operation; /* BLKIF_OP_??? */ union { struct blkif_x86_64_request_rw rw; struct blkif_x86_64_request_discard discard; + struct blkif_x86_64_request_other other; } u; } __attribute__((__packed__)); @@ -172,7 +187,6 @@ struct persistent_gnt { struct page *page; grant_ref_t gnt; grant_handle_t handle; - uint64_t dev_bus_addr; struct rb_node node; }; @@ -208,13 +222,13 @@ struct xen_blkif { /* statistics */ unsigned long st_print; - int st_rd_req; - int st_wr_req; - int st_oo_req; - int st_f_req; - int st_ds_req; - int st_rd_sect; - int st_wr_sect; + unsigned long long st_rd_req; + unsigned long long st_wr_req; + unsigned long long st_oo_req; + unsigned long long st_f_req; + unsigned long long st_ds_req; + unsigned long long st_rd_sect; + unsigned long long st_wr_sect; wait_queue_head_t waiting_to_free; }; @@ -278,6 +292,11 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst, dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; default: + /* + * Don't know how to translate this op. Only get the + * ID so failure can be reported to the frontend. + */ + dst->u.other.id = src->u.other.id; break; } } @@ -309,6 +328,11 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst, dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; default: + /* + * Don't know how to translate this op. Only get the + * ID so failure can be reported to the frontend. + */ + dst->u.other.id = src->u.other.id; break; } } diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 5e237f630c47..8bfd1bcf95ec 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -230,13 +230,13 @@ int __init xen_blkif_interface_init(void) } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) -VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req); -VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req); -VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req); -VBD_SHOW(f_req, "%d\n", be->blkif->st_f_req); -VBD_SHOW(ds_req, "%d\n", be->blkif->st_ds_req); -VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect); -VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect); +VBD_SHOW(oo_req, "%llu\n", be->blkif->st_oo_req); +VBD_SHOW(rd_req, "%llu\n", be->blkif->st_rd_req); +VBD_SHOW(wr_req, "%llu\n", be->blkif->st_wr_req); +VBD_SHOW(f_req, "%llu\n", be->blkif->st_f_req); +VBD_SHOW(ds_req, "%llu\n", be->blkif->st_ds_req); +VBD_SHOW(rd_sect, "%llu\n", be->blkif->st_rd_sect); +VBD_SHOW(wr_sect, "%llu\n", be->blkif->st_wr_sect); static struct attribute *xen_vbdstat_attrs[] = { &dev_attr_oo_req.attr, diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index c3dae2e0f290..a894f88762d8 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -44,7 +44,7 @@ #include <linux/mutex.h> #include <linux/scatterlist.h> #include <linux/bitmap.h> -#include <linux/llist.h> +#include <linux/list.h> #include <xen/xen.h> #include <xen/xenbus.h> @@ -68,13 +68,12 @@ enum blkif_state { struct grant { grant_ref_t gref; unsigned long pfn; - struct llist_node node; + struct list_head node; }; struct blk_shadow { struct blkif_request req; struct request *request; - unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct grant *grants_used[BLKIF_MAX_SEGMENTS_PER_REQUEST]; }; @@ -105,7 +104,7 @@ struct blkfront_info struct work_struct work; struct gnttab_free_callback callback; struct blk_shadow shadow[BLK_RING_SIZE]; - struct llist_head persistent_gnts; + struct list_head persistent_gnts; unsigned int persistent_gnts_c; unsigned long shadow_free; unsigned int feature_flush; @@ -165,6 +164,69 @@ static int add_id_to_freelist(struct blkfront_info *info, return 0; } +static int fill_grant_buffer(struct blkfront_info *info, int num) +{ + struct page *granted_page; + struct grant *gnt_list_entry, *n; + int i = 0; + + while(i < num) { + gnt_list_entry = kzalloc(sizeof(struct grant), GFP_NOIO); + if (!gnt_list_entry) + goto out_of_memory; + + granted_page = alloc_page(GFP_NOIO); + if (!granted_page) { + kfree(gnt_list_entry); + goto out_of_memory; + } + + gnt_list_entry->pfn = page_to_pfn(granted_page); + gnt_list_entry->gref = GRANT_INVALID_REF; + list_add(&gnt_list_entry->node, &info->persistent_gnts); + i++; + } + + return 0; + +out_of_memory: + list_for_each_entry_safe(gnt_list_entry, n, + &info->persistent_gnts, node) { + list_del(&gnt_list_entry->node); + __free_page(pfn_to_page(gnt_list_entry->pfn)); + kfree(gnt_list_entry); + i--; + } + BUG_ON(i != 0); + return -ENOMEM; +} + +static struct grant *get_grant(grant_ref_t *gref_head, + struct blkfront_info *info) +{ + struct grant *gnt_list_entry; + unsigned long buffer_mfn; + + BUG_ON(list_empty(&info->persistent_gnts)); + gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant, + node); + list_del(&gnt_list_entry->node); + + if (gnt_list_entry->gref != GRANT_INVALID_REF) { + info->persistent_gnts_c--; + return gnt_list_entry; + } + + /* Assign a gref to this page */ + gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); + BUG_ON(gnt_list_entry->gref == -ENOSPC); + buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); + gnttab_grant_foreign_access_ref(gnt_list_entry->gref, + info->xbdev->otherend_id, + buffer_mfn, 0); + return gnt_list_entry; +} + static const char *op_name(int op) { static const char *const names[] = { @@ -293,7 +355,6 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode, static int blkif_queue_request(struct request *req) { struct blkfront_info *info = req->rq_disk->private_data; - unsigned long buffer_mfn; struct blkif_request *ring_req; unsigned long id; unsigned int fsect, lsect; @@ -306,7 +367,6 @@ static int blkif_queue_request(struct request *req) */ bool new_persistent_gnts; grant_ref_t gref_head; - struct page *granted_page; struct grant *gnt_list_entry = NULL; struct scatterlist *sg; @@ -370,41 +430,8 @@ static int blkif_queue_request(struct request *req) fsect = sg->offset >> 9; lsect = fsect + (sg->length >> 9) - 1; - if (info->persistent_gnts_c) { - BUG_ON(llist_empty(&info->persistent_gnts)); - gnt_list_entry = llist_entry( - llist_del_first(&info->persistent_gnts), - struct grant, node); - - ref = gnt_list_entry->gref; - buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); - info->persistent_gnts_c--; - } else { - ref = gnttab_claim_grant_reference(&gref_head); - BUG_ON(ref == -ENOSPC); - - gnt_list_entry = - kmalloc(sizeof(struct grant), - GFP_ATOMIC); - if (!gnt_list_entry) - return -ENOMEM; - - granted_page = alloc_page(GFP_ATOMIC); - if (!granted_page) { - kfree(gnt_list_entry); - return -ENOMEM; - } - - gnt_list_entry->pfn = - page_to_pfn(granted_page); - gnt_list_entry->gref = ref; - - buffer_mfn = pfn_to_mfn(page_to_pfn( - granted_page)); - gnttab_grant_foreign_access_ref(ref, - info->xbdev->otherend_id, - buffer_mfn, 0); - } + gnt_list_entry = get_grant(&gref_head, info); + ref = gnt_list_entry->gref; info->shadow[id].grants_used[i] = gnt_list_entry; @@ -435,7 +462,6 @@ static int blkif_queue_request(struct request *req) kunmap_atomic(shared_data); } - info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn); ring_req->u.rw.seg[i] = (struct blkif_request_segment) { .gref = ref, @@ -790,9 +816,8 @@ static void blkif_restart_queue(struct work_struct *work) static void blkif_free(struct blkfront_info *info, int suspend) { - struct llist_node *all_gnts; - struct grant *persistent_gnt, *tmp; - struct llist_node *n; + struct grant *persistent_gnt; + struct grant *n; /* Prevent new requests being issued until we fix things up. */ spin_lock_irq(&info->io_lock); @@ -803,22 +828,20 @@ static void blkif_free(struct blkfront_info *info, int suspend) blk_stop_queue(info->rq); /* Remove all persistent grants */ - if (info->persistent_gnts_c) { - all_gnts = llist_del_all(&info->persistent_gnts); - persistent_gnt = llist_entry(all_gnts, typeof(*(persistent_gnt)), node); - while (persistent_gnt) { - gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); + if (!list_empty(&info->persistent_gnts)) { + list_for_each_entry_safe(persistent_gnt, n, + &info->persistent_gnts, node) { + list_del(&persistent_gnt->node); + if (persistent_gnt->gref != GRANT_INVALID_REF) { + gnttab_end_foreign_access(persistent_gnt->gref, + 0, 0UL); + info->persistent_gnts_c--; + } __free_page(pfn_to_page(persistent_gnt->pfn)); - tmp = persistent_gnt; - n = persistent_gnt->node.next; - if (n) - persistent_gnt = llist_entry(n, typeof(*(persistent_gnt)), node); - else - persistent_gnt = NULL; - kfree(tmp); + kfree(persistent_gnt); } - info->persistent_gnts_c = 0; } + BUG_ON(info->persistent_gnts_c != 0); /* No more gnttab callback work. */ gnttab_cancel_free_callback(&info->callback); @@ -875,7 +898,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, } /* Add the persistent grant into the list of free grants */ for (i = 0; i < s->req.u.rw.nr_segments; i++) { - llist_add(&s->grants_used[i]->node, &info->persistent_gnts); + list_add(&s->grants_used[i]->node, &info->persistent_gnts); info->persistent_gnts_c++; } } @@ -1013,6 +1036,12 @@ static int setup_blkring(struct xenbus_device *dev, sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST); + /* Allocate memory for grants */ + err = fill_grant_buffer(info, BLK_RING_SIZE * + BLKIF_MAX_SEGMENTS_PER_REQUEST); + if (err) + goto fail; + err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); if (err < 0) { free_page((unsigned long)sring); @@ -1171,7 +1200,7 @@ static int blkfront_probe(struct xenbus_device *dev, spin_lock_init(&info->io_lock); info->xbdev = dev; info->vdevice = vdevice; - init_llist_head(&info->persistent_gnts); + INIT_LIST_HEAD(&info->persistent_gnts); info->persistent_gnts_c = 0; info->connected = BLKIF_STATE_DISCONNECTED; INIT_WORK(&info->work, blkif_restart_queue); @@ -1203,11 +1232,10 @@ static int blkif_recover(struct blkfront_info *info) int j; /* Stage 1: Make a safe copy of the shadow state. */ - copy = kmalloc(sizeof(info->shadow), + copy = kmemdup(info->shadow, sizeof(info->shadow), GFP_NOIO | __GFP_REPEAT | __GFP_HIGH); if (!copy) return -ENOMEM; - memcpy(copy, info->shadow, sizeof(info->shadow)); /* Stage 2: Set up free list. */ memset(&info->shadow, 0, sizeof(info->shadow)); @@ -1236,7 +1264,7 @@ static int blkif_recover(struct blkfront_info *info) gnttab_grant_foreign_access_ref( req->u.rw.seg[j].gref, info->xbdev->otherend_id, - pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]), + pfn_to_mfn(copy[i].grants_used[j]->pfn), 0); } info->shadow[req->u.rw.id].req = *req; diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index b282af181b44..6aab00ef4379 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -73,9 +73,11 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x03F0, 0x311D) }, /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, + { USB_DEVICE(0x0CF3, 0x817a) }, { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04CA, 0x3004) }, { USB_DEVICE(0x04CA, 0x3005) }, @@ -107,9 +109,11 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); static struct usb_device_id ath3k_blist_tbl[] = { /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e547851870e7..2cc5f774a29c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -131,9 +131,11 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, /* Atheros 3012 with sflash firmware */ + { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index a47e6ee98b8c..a64caefdba12 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -63,6 +63,14 @@ config CLK_TWL6040 McPDM. McPDM module is using the external bit clock on the McPDM bus as functional clock. +config COMMON_CLK_AXI_CLKGEN + tristate "AXI clkgen driver" + depends on ARCH_ZYNQ || MICROBLAZE + help + ---help--- + Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx + FPGAs. It is commonly used in Analog Devices' reference designs. + endmenu source "drivers/clk/mvebu/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 300d4775d926..17e8dc4e417c 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o +obj-$(CONFIG_COMMON_CLK) += clk-composite.o # SoCs specific obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o @@ -23,14 +24,17 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ endif obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o +obj-$(CONFIG_ARCH_SUNXI) += sunxi/ 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_PLAT_SAMSUNG) += samsung/ obj-$(CONFIG_X86) += x86/ # Chip specific +obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c new file mode 100644 index 000000000000..8137327847c3 --- /dev/null +++ b/drivers/clk/clk-axi-clkgen.c @@ -0,0 +1,331 @@ +/* + * AXI clkgen driver + * + * Copyright 2012-2013 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + * + */ + +#include <linux/platform_device.h> +#include <linux/clk-provider.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/err.h> + +#define AXI_CLKGEN_REG_UPDATE_ENABLE 0x04 +#define AXI_CLKGEN_REG_CLK_OUT1 0x08 +#define AXI_CLKGEN_REG_CLK_OUT2 0x0c +#define AXI_CLKGEN_REG_CLK_DIV 0x10 +#define AXI_CLKGEN_REG_CLK_FB1 0x14 +#define AXI_CLKGEN_REG_CLK_FB2 0x18 +#define AXI_CLKGEN_REG_LOCK1 0x1c +#define AXI_CLKGEN_REG_LOCK2 0x20 +#define AXI_CLKGEN_REG_LOCK3 0x24 +#define AXI_CLKGEN_REG_FILTER1 0x28 +#define AXI_CLKGEN_REG_FILTER2 0x2c + +struct axi_clkgen { + void __iomem *base; + struct clk_hw clk_hw; +}; + +static uint32_t axi_clkgen_lookup_filter(unsigned int m) +{ + switch (m) { + case 0: + return 0x01001990; + case 1: + return 0x01001190; + case 2: + return 0x01009890; + case 3: + return 0x01001890; + case 4: + return 0x01008890; + case 5 ... 8: + return 0x01009090; + case 9 ... 11: + return 0x01000890; + case 12: + return 0x08009090; + case 13 ... 22: + return 0x01001090; + case 23 ... 36: + return 0x01008090; + case 37 ... 46: + return 0x08001090; + default: + return 0x08008090; + } +} + +static const uint32_t axi_clkgen_lock_table[] = { + 0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8, + 0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8, + 0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339, + 0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271, + 0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4, + 0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190, + 0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e, + 0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c, + 0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113, +}; + +static uint32_t axi_clkgen_lookup_lock(unsigned int m) +{ + if (m < ARRAY_SIZE(axi_clkgen_lock_table)) + return axi_clkgen_lock_table[m]; + return 0x1f1f00fa; +} + +static const unsigned int fpfd_min = 10000; +static const unsigned int fpfd_max = 300000; +static const unsigned int fvco_min = 600000; +static const unsigned int fvco_max = 1200000; + +static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout, + unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout) +{ + unsigned long d, d_min, d_max, _d_min, _d_max; + unsigned long m, m_min, m_max; + unsigned long f, dout, best_f, fvco; + + fin /= 1000; + fout /= 1000; + + best_f = ULONG_MAX; + *best_d = 0; + *best_m = 0; + *best_dout = 0; + + d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1); + d_max = min_t(unsigned long, fin / fpfd_min, 80); + + m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1); + m_max = min_t(unsigned long, fvco_max * d_max / fin, 64); + + for (m = m_min; m <= m_max; m++) { + _d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max)); + _d_max = min(d_max, fin * m / fvco_min); + + for (d = _d_min; d <= _d_max; d++) { + fvco = fin * m / d; + + dout = DIV_ROUND_CLOSEST(fvco, fout); + dout = clamp_t(unsigned long, dout, 1, 128); + f = fvco / dout; + if (abs(f - fout) < abs(best_f - fout)) { + best_f = f; + *best_d = d; + *best_m = m; + *best_dout = dout; + if (best_f == fout) + return; + } + } + } +} + +static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low, + unsigned int *high, unsigned int *edge, unsigned int *nocount) +{ + if (divider == 1) + *nocount = 1; + else + *nocount = 0; + + *high = divider / 2; + *edge = divider % 2; + *low = divider - *high; +} + +static void axi_clkgen_write(struct axi_clkgen *axi_clkgen, + unsigned int reg, unsigned int val) +{ + writel(val, axi_clkgen->base + reg); +} + +static void axi_clkgen_read(struct axi_clkgen *axi_clkgen, + unsigned int reg, unsigned int *val) +{ + *val = readl(axi_clkgen->base + reg); +} + +static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw) +{ + return container_of(clk_hw, struct axi_clkgen, clk_hw); +} + +static int axi_clkgen_set_rate(struct clk_hw *clk_hw, + unsigned long rate, unsigned long parent_rate) +{ + struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw); + unsigned int d, m, dout; + unsigned int nocount; + unsigned int high; + unsigned int edge; + unsigned int low; + uint32_t filter; + uint32_t lock; + + if (parent_rate == 0 || rate == 0) + return -EINVAL; + + axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout); + + if (d == 0 || dout == 0 || m == 0) + return -EINVAL; + + filter = axi_clkgen_lookup_filter(m - 1); + lock = axi_clkgen_lookup_lock(m - 1); + + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 0); + + axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, + (high << 6) | low); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT2, + (edge << 7) | (nocount << 6)); + + axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, + (edge << 13) | (nocount << 12) | (high << 6) | low); + + axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, + (high << 6) | low); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB2, + (edge << 7) | (nocount << 6)); + + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK1, lock & 0x3ff); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK2, + (((lock >> 16) & 0x1f) << 10) | 0x1); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK3, + (((lock >> 24) & 0x1f) << 10) | 0x3e9); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER1, filter >> 16); + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER2, filter); + + axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 1); + + return 0; +} + +static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned int d, m, dout; + + axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout); + + if (d == 0 || dout == 0 || m == 0) + return -EINVAL; + + return *parent_rate / d * m / dout; +} + +static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw, + unsigned long parent_rate) +{ + struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw); + unsigned int d, m, dout; + unsigned int reg; + unsigned long long tmp; + + axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, ®); + dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); + axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, ®); + d = (reg & 0x3f) + ((reg >> 6) & 0x3f); + axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, ®); + m = (reg & 0x3f) + ((reg >> 6) & 0x3f); + + if (d == 0 || dout == 0) + return 0; + + tmp = (unsigned long long)(parent_rate / d) * m; + do_div(tmp, dout); + + if (tmp > ULONG_MAX) + return ULONG_MAX; + + return tmp; +} + +static const struct clk_ops axi_clkgen_ops = { + .recalc_rate = axi_clkgen_recalc_rate, + .round_rate = axi_clkgen_round_rate, + .set_rate = axi_clkgen_set_rate, +}; + +static int axi_clkgen_probe(struct platform_device *pdev) +{ + struct axi_clkgen *axi_clkgen; + struct clk_init_data init; + const char *parent_name; + const char *clk_name; + struct resource *mem; + struct clk *clk; + + axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL); + if (!axi_clkgen) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(axi_clkgen->base)) + return PTR_ERR(axi_clkgen->base); + + parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0); + if (!parent_name) + return -EINVAL; + + clk_name = pdev->dev.of_node->name; + of_property_read_string(pdev->dev.of_node, "clock-output-names", + &clk_name); + + init.name = clk_name; + init.ops = &axi_clkgen_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + axi_clkgen->clk_hw.init = &init; + clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, + clk); +} + +static int axi_clkgen_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + + return 0; +} + +static const struct of_device_id axi_clkgen_ids[] = { + { .compatible = "adi,axi-clkgen-1.00.a" }, + { }, +}; +MODULE_DEVICE_TABLE(of, axi_clkgen_ids); + +static struct platform_driver axi_clkgen_driver = { + .driver = { + .name = "adi-axi-clkgen", + .owner = THIS_MODULE, + .of_match_table = axi_clkgen_ids, + }, + .probe = axi_clkgen_probe, + .remove = axi_clkgen_remove, +}; +module_platform_driver(axi_clkgen_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator"); diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c new file mode 100644 index 000000000000..097dee4fd209 --- /dev/null +++ b/drivers/clk/clk-composite.c @@ -0,0 +1,201 @@ +/* + * 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/clk.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/slab.h> + +#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw) + +static u8 clk_composite_get_parent(struct clk_hw *hw) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *mux_ops = composite->mux_ops; + struct clk_hw *mux_hw = composite->mux_hw; + + mux_hw->clk = hw->clk; + + return mux_ops->get_parent(mux_hw); +} + +static int clk_composite_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *mux_ops = composite->mux_ops; + struct clk_hw *mux_hw = composite->mux_hw; + + mux_hw->clk = hw->clk; + + return mux_ops->set_parent(mux_hw, index); +} + +static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *div_ops = composite->div_ops; + struct clk_hw *div_hw = composite->div_hw; + + div_hw->clk = hw->clk; + + return div_ops->recalc_rate(div_hw, parent_rate); +} + +static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *div_ops = composite->div_ops; + struct clk_hw *div_hw = composite->div_hw; + + div_hw->clk = hw->clk; + + return div_ops->round_rate(div_hw, rate, prate); +} + +static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *div_ops = composite->div_ops; + struct clk_hw *div_hw = composite->div_hw; + + div_hw->clk = hw->clk; + + return div_ops->set_rate(div_hw, rate, parent_rate); +} + +static int clk_composite_is_enabled(struct clk_hw *hw) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *gate_ops = composite->gate_ops; + struct clk_hw *gate_hw = composite->gate_hw; + + gate_hw->clk = hw->clk; + + return gate_ops->is_enabled(gate_hw); +} + +static int clk_composite_enable(struct clk_hw *hw) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *gate_ops = composite->gate_ops; + struct clk_hw *gate_hw = composite->gate_hw; + + gate_hw->clk = hw->clk; + + return gate_ops->enable(gate_hw); +} + +static void clk_composite_disable(struct clk_hw *hw) +{ + struct clk_composite *composite = to_clk_composite(hw); + const struct clk_ops *gate_ops = composite->gate_ops; + struct clk_hw *gate_hw = composite->gate_hw; + + gate_hw->clk = hw->clk; + + gate_ops->disable(gate_hw); +} + +struct clk *clk_register_composite(struct device *dev, const char *name, + const char **parent_names, int num_parents, + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, + struct clk_hw *div_hw, const struct clk_ops *div_ops, + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, + unsigned long flags) +{ + struct clk *clk; + struct clk_init_data init; + struct clk_composite *composite; + struct clk_ops *clk_composite_ops; + + composite = kzalloc(sizeof(*composite), GFP_KERNEL); + if (!composite) { + pr_err("%s: could not allocate composite clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = parent_names; + init.num_parents = num_parents; + + clk_composite_ops = &composite->ops; + + if (mux_hw && mux_ops) { + if (!mux_ops->get_parent || !mux_ops->set_parent) { + clk = ERR_PTR(-EINVAL); + goto err; + } + + composite->mux_hw = mux_hw; + composite->mux_ops = mux_ops; + clk_composite_ops->get_parent = clk_composite_get_parent; + clk_composite_ops->set_parent = clk_composite_set_parent; + } + + if (div_hw && div_ops) { + if (!div_ops->recalc_rate || !div_ops->round_rate || + !div_ops->set_rate) { + clk = ERR_PTR(-EINVAL); + goto err; + } + + composite->div_hw = div_hw; + composite->div_ops = div_ops; + clk_composite_ops->recalc_rate = clk_composite_recalc_rate; + clk_composite_ops->round_rate = clk_composite_round_rate; + clk_composite_ops->set_rate = clk_composite_set_rate; + } + + if (gate_hw && gate_ops) { + if (!gate_ops->is_enabled || !gate_ops->enable || + !gate_ops->disable) { + clk = ERR_PTR(-EINVAL); + goto err; + } + + composite->gate_hw = gate_hw; + composite->gate_ops = gate_ops; + clk_composite_ops->is_enabled = clk_composite_is_enabled; + clk_composite_ops->enable = clk_composite_enable; + clk_composite_ops->disable = clk_composite_disable; + } + + init.ops = clk_composite_ops; + composite->hw.init = &init; + + clk = clk_register(dev, &composite->hw); + if (IS_ERR(clk)) + goto err; + + if (composite->mux_hw) + composite->mux_hw->clk = clk; + + if (composite->div_hw) + composite->div_hw->clk = clk; + + if (composite->gate_hw) + composite->gate_hw->clk = clk; + + return clk; + +err: + kfree(composite); + return clk; +} diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 508c032edce4..25b1734560d0 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -32,6 +32,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) { struct clk_mux *mux = to_clk_mux(hw); + int num_parents = __clk_get_num_parents(hw->clk); u32 val; /* @@ -42,7 +43,16 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) * val = 0x4 really means "bit 2, index starts at bit 0" */ val = readl(mux->reg) >> mux->shift; - val &= (1 << mux->width) - 1; + val &= mux->mask; + + if (mux->table) { + int i; + + for (i = 0; i < num_parents; i++) + if (mux->table[i] == val) + return i; + return -EINVAL; + } if (val && (mux->flags & CLK_MUX_INDEX_BIT)) val = ffs(val) - 1; @@ -50,7 +60,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) if (val && (mux->flags & CLK_MUX_INDEX_ONE)) val--; - if (val >= __clk_get_num_parents(hw->clk)) + if (val >= num_parents) return -EINVAL; return val; @@ -62,17 +72,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) u32 val; unsigned long flags = 0; - if (mux->flags & CLK_MUX_INDEX_BIT) - index = (1 << ffs(index)); + if (mux->table) + index = mux->table[index]; - if (mux->flags & CLK_MUX_INDEX_ONE) - index++; + else { + if (mux->flags & CLK_MUX_INDEX_BIT) + index = (1 << ffs(index)); + + if (mux->flags & CLK_MUX_INDEX_ONE) + index++; + } if (mux->lock) spin_lock_irqsave(mux->lock, flags); val = readl(mux->reg); - val &= ~(((1 << mux->width) - 1) << mux->shift); + val &= ~(mux->mask << mux->shift); val |= index << mux->shift; writel(val, mux->reg); @@ -88,10 +103,10 @@ const struct clk_ops clk_mux_ops = { }; EXPORT_SYMBOL_GPL(clk_mux_ops); -struct clk *clk_register_mux(struct device *dev, const char *name, +struct clk *clk_register_mux_table(struct device *dev, const char *name, const char **parent_names, u8 num_parents, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, - u8 clk_mux_flags, spinlock_t *lock) + void __iomem *reg, u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table, spinlock_t *lock) { struct clk_mux *mux; struct clk *clk; @@ -113,9 +128,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name, /* struct clk_mux assignments */ mux->reg = reg; mux->shift = shift; - mux->width = width; + mux->mask = mask; mux->flags = clk_mux_flags; mux->lock = lock; + mux->table = table; mux->hw.init = &init; clk = clk_register(dev, &mux->hw); @@ -125,3 +141,15 @@ struct clk *clk_register_mux(struct device *dev, const char *name, return clk; } + +struct clk *clk_register_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_mux_flags, spinlock_t *lock) +{ + u32 mask = BIT(width) - 1; + + return clk_register_mux_table(dev, name, parent_names, num_parents, + flags, reg, shift, mask, clk_mux_flags, + NULL, lock); +} diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c index f8e9d0c27be2..643ca653fef0 100644 --- a/drivers/clk/clk-prima2.c +++ b/drivers/clk/clk-prima2.c @@ -1113,7 +1113,7 @@ void __init sirfsoc_of_clk_init(void) for (i = pll1; i < maxclk; i++) { prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]); - BUG_ON(!prima2_clks[i]); + BUG_ON(IS_ERR(prima2_clks[i])); } clk_register_clkdev(prima2_clks[cpu], NULL, "cpu"); clk_register_clkdev(prima2_clks[io], NULL, "io"); diff --git a/drivers/clk/clk-zynq.c b/drivers/clk/clk-zynq.c index b14a25f39255..32062977f453 100644 --- a/drivers/clk/clk-zynq.c +++ b/drivers/clk/clk-zynq.c @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/clk-provider.h> +#include <linux/clk/zynq.h> static void __iomem *slcr_base; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ed87b2405806..0230c9d95975 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -19,14 +19,77 @@ #include <linux/of.h> #include <linux/device.h> #include <linux/init.h> +#include <linux/sched.h> static DEFINE_SPINLOCK(enable_lock); static DEFINE_MUTEX(prepare_lock); +static struct task_struct *prepare_owner; +static struct task_struct *enable_owner; + +static int prepare_refcnt; +static int enable_refcnt; + static HLIST_HEAD(clk_root_list); static HLIST_HEAD(clk_orphan_list); static LIST_HEAD(clk_notifier_list); +/*** locking ***/ +static void clk_prepare_lock(void) +{ + if (!mutex_trylock(&prepare_lock)) { + if (prepare_owner == current) { + prepare_refcnt++; + return; + } + mutex_lock(&prepare_lock); + } + WARN_ON_ONCE(prepare_owner != NULL); + WARN_ON_ONCE(prepare_refcnt != 0); + prepare_owner = current; + prepare_refcnt = 1; +} + +static void clk_prepare_unlock(void) +{ + WARN_ON_ONCE(prepare_owner != current); + WARN_ON_ONCE(prepare_refcnt == 0); + + if (--prepare_refcnt) + return; + prepare_owner = NULL; + mutex_unlock(&prepare_lock); +} + +static unsigned long clk_enable_lock(void) +{ + unsigned long flags; + + if (!spin_trylock_irqsave(&enable_lock, flags)) { + if (enable_owner == current) { + enable_refcnt++; + return flags; + } + spin_lock_irqsave(&enable_lock, flags); + } + WARN_ON_ONCE(enable_owner != NULL); + WARN_ON_ONCE(enable_refcnt != 0); + enable_owner = current; + enable_refcnt = 1; + return flags; +} + +static void clk_enable_unlock(unsigned long flags) +{ + WARN_ON_ONCE(enable_owner != current); + WARN_ON_ONCE(enable_refcnt == 0); + + if (--enable_refcnt) + return; + enable_owner = NULL; + spin_unlock_irqrestore(&enable_lock, flags); +} + /*** debugfs support ***/ #ifdef CONFIG_COMMON_CLK_DEBUG @@ -69,7 +132,7 @@ static int clk_summary_show(struct seq_file *s, void *data) seq_printf(s, " clock enable_cnt prepare_cnt rate\n"); seq_printf(s, "---------------------------------------------------------------------\n"); - mutex_lock(&prepare_lock); + clk_prepare_lock(); hlist_for_each_entry(c, &clk_root_list, child_node) clk_summary_show_subtree(s, c, 0); @@ -77,7 +140,7 @@ static int clk_summary_show(struct seq_file *s, void *data) hlist_for_each_entry(c, &clk_orphan_list, child_node) clk_summary_show_subtree(s, c, 0); - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return 0; } @@ -130,7 +193,7 @@ static int clk_dump(struct seq_file *s, void *data) seq_printf(s, "{"); - mutex_lock(&prepare_lock); + clk_prepare_lock(); hlist_for_each_entry(c, &clk_root_list, child_node) { if (!first_node) @@ -144,7 +207,7 @@ static int clk_dump(struct seq_file *s, void *data) clk_dump_subtree(s, c, 0); } - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); seq_printf(s, "}"); return 0; @@ -316,7 +379,7 @@ static int __init clk_debug_init(void) if (!orphandir) return -ENOMEM; - mutex_lock(&prepare_lock); + clk_prepare_lock(); hlist_for_each_entry(clk, &clk_root_list, child_node) clk_debug_create_subtree(clk, rootdir); @@ -326,7 +389,7 @@ static int __init clk_debug_init(void) inited = 1; - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return 0; } @@ -336,6 +399,31 @@ static inline int clk_debug_register(struct clk *clk) { return 0; } #endif /* caller must hold prepare_lock */ +static void clk_unprepare_unused_subtree(struct clk *clk) +{ + struct clk *child; + + if (!clk) + return; + + hlist_for_each_entry(child, &clk->children, child_node) + clk_unprepare_unused_subtree(child); + + if (clk->prepare_count) + return; + + if (clk->flags & CLK_IGNORE_UNUSED) + return; + + if (__clk_is_prepared(clk)) { + if (clk->ops->unprepare_unused) + clk->ops->unprepare_unused(clk->hw); + else if (clk->ops->unprepare) + clk->ops->unprepare(clk->hw); + } +} + +/* caller must hold prepare_lock */ static void clk_disable_unused_subtree(struct clk *clk) { struct clk *child; @@ -347,7 +435,7 @@ static void clk_disable_unused_subtree(struct clk *clk) hlist_for_each_entry(child, &clk->children, child_node) clk_disable_unused_subtree(child); - spin_lock_irqsave(&enable_lock, flags); + flags = clk_enable_lock(); if (clk->enable_count) goto unlock_out; @@ -368,7 +456,7 @@ static void clk_disable_unused_subtree(struct clk *clk) } unlock_out: - spin_unlock_irqrestore(&enable_lock, flags); + clk_enable_unlock(flags); out: return; @@ -378,7 +466,7 @@ static int clk_disable_unused(void) { struct clk *clk; - mutex_lock(&prepare_lock); + clk_prepare_lock(); hlist_for_each_entry(clk, &clk_root_list, child_node) clk_disable_unused_subtree(clk); @@ -386,7 +474,13 @@ static int clk_disable_unused(void) hlist_for_each_entry(clk, &clk_orphan_list, child_node) clk_disable_unused_subtree(clk); - mutex_unlock(&prepare_lock); + hlist_for_each_entry(clk, &clk_root_list, child_node) + clk_unprepare_unused_subtree(clk); + + hlist_for_each_entry(clk, &clk_orphan_list, child_node) + clk_unprepare_unused_subtree(clk); + + clk_prepare_unlock(); return 0; } @@ -451,6 +545,27 @@ unsigned long __clk_get_flags(struct clk *clk) return !clk ? 0 : clk->flags; } +bool __clk_is_prepared(struct clk *clk) +{ + int ret; + + if (!clk) + return false; + + /* + * .is_prepared is optional for clocks that can prepare + * fall back to software usage counter if it is missing + */ + if (!clk->ops->is_prepared) { + ret = clk->prepare_count ? 1 : 0; + goto out; + } + + ret = clk->ops->is_prepared(clk->hw); +out: + return !!ret; +} + bool __clk_is_enabled(struct clk *clk) { int ret; @@ -548,9 +663,9 @@ void __clk_unprepare(struct clk *clk) */ void clk_unprepare(struct clk *clk) { - mutex_lock(&prepare_lock); + clk_prepare_lock(); __clk_unprepare(clk); - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); } EXPORT_SYMBOL_GPL(clk_unprepare); @@ -596,9 +711,9 @@ int clk_prepare(struct clk *clk) { int ret; - mutex_lock(&prepare_lock); + clk_prepare_lock(); ret = __clk_prepare(clk); - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return ret; } @@ -640,9 +755,9 @@ void clk_disable(struct clk *clk) { unsigned long flags; - spin_lock_irqsave(&enable_lock, flags); + flags = clk_enable_lock(); __clk_disable(clk); - spin_unlock_irqrestore(&enable_lock, flags); + clk_enable_unlock(flags); } EXPORT_SYMBOL_GPL(clk_disable); @@ -693,9 +808,9 @@ int clk_enable(struct clk *clk) unsigned long flags; int ret; - spin_lock_irqsave(&enable_lock, flags); + flags = clk_enable_lock(); ret = __clk_enable(clk); - spin_unlock_irqrestore(&enable_lock, flags); + clk_enable_unlock(flags); return ret; } @@ -740,9 +855,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate) { unsigned long ret; - mutex_lock(&prepare_lock); + clk_prepare_lock(); ret = __clk_round_rate(clk, rate); - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return ret; } @@ -837,13 +952,13 @@ unsigned long clk_get_rate(struct clk *clk) { unsigned long rate; - mutex_lock(&prepare_lock); + clk_prepare_lock(); if (clk && (clk->flags & CLK_GET_RATE_NOCACHE)) __clk_recalc_rates(clk, 0); rate = __clk_get_rate(clk); - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return rate; } @@ -974,7 +1089,7 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even int ret = NOTIFY_DONE; if (clk->rate == clk->new_rate) - return 0; + return NULL; if (clk->notifier_count) { ret = __clk_notify(clk, event, clk->rate, clk->new_rate); @@ -1048,7 +1163,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) int ret = 0; /* prevent racing with updates to the clock topology */ - mutex_lock(&prepare_lock); + clk_prepare_lock(); /* bail early if nothing to do */ if (rate == clk->rate) @@ -1080,7 +1195,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) clk_change_rate(top); out: - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return ret; } @@ -1096,9 +1211,9 @@ struct clk *clk_get_parent(struct clk *clk) { struct clk *parent; - mutex_lock(&prepare_lock); + clk_prepare_lock(); parent = __clk_get_parent(clk); - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return parent; } @@ -1242,19 +1357,19 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent) __clk_prepare(parent); /* FIXME replace with clk_is_enabled(clk) someday */ - spin_lock_irqsave(&enable_lock, flags); + flags = clk_enable_lock(); if (clk->enable_count) __clk_enable(parent); - spin_unlock_irqrestore(&enable_lock, flags); + clk_enable_unlock(flags); /* change clock input source */ ret = clk->ops->set_parent(clk->hw, i); /* clean up old prepare and enable */ - spin_lock_irqsave(&enable_lock, flags); + flags = clk_enable_lock(); if (clk->enable_count) __clk_disable(old_parent); - spin_unlock_irqrestore(&enable_lock, flags); + clk_enable_unlock(flags); if (clk->prepare_count) __clk_unprepare(old_parent); @@ -1286,7 +1401,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent) return -ENOSYS; /* prevent racing with updates to the clock topology */ - mutex_lock(&prepare_lock); + clk_prepare_lock(); if (clk->parent == parent) goto out; @@ -1315,7 +1430,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent) __clk_reparent(clk, parent); out: - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return ret; } @@ -1338,7 +1453,7 @@ int __clk_init(struct device *dev, struct clk *clk) if (!clk) return -EINVAL; - mutex_lock(&prepare_lock); + clk_prepare_lock(); /* check to see if a clock with this name is already registered */ if (__clk_lookup(clk->name)) { @@ -1462,7 +1577,7 @@ int __clk_init(struct device *dev, struct clk *clk) clk_debug_register(clk); out: - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return ret; } @@ -1696,7 +1811,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb) if (!clk || !nb) return -EINVAL; - mutex_lock(&prepare_lock); + clk_prepare_lock(); /* search the list of notifiers for this clk */ list_for_each_entry(cn, &clk_notifier_list, node) @@ -1720,7 +1835,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb) clk->notifier_count++; out: - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return ret; } @@ -1745,7 +1860,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) if (!clk || !nb) return -EINVAL; - mutex_lock(&prepare_lock); + clk_prepare_lock(); list_for_each_entry(cn, &clk_notifier_list, node) if (cn->clk == clk) @@ -1766,7 +1881,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) ret = -ENOENT; } - mutex_unlock(&prepare_lock); + clk_prepare_unlock(); return ret; } diff --git a/drivers/clk/mxs/clk.c b/drivers/clk/mxs/clk.c index b24d56067c80..5301bce8957b 100644 --- a/drivers/clk/mxs/clk.c +++ b/drivers/clk/mxs/clk.c @@ -13,6 +13,7 @@ #include <linux/io.h> #include <linux/jiffies.h> #include <linux/spinlock.h> +#include "clk.h" DEFINE_SPINLOCK(mxs_lock); diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile new file mode 100644 index 000000000000..b7c232e67425 --- /dev/null +++ b/drivers/clk/samsung/Makefile @@ -0,0 +1,8 @@ +# +# Samsung Clock specific Makefile +# + +obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o +obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o +obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o +obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c new file mode 100644 index 000000000000..71046694d9dd --- /dev/null +++ b/drivers/clk/samsung/clk-exynos4.c @@ -0,0 +1,1091 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2013 Linaro Ltd. + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * 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. + * + * Common Clock Framework support for all Exynos4 SoCs. +*/ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <plat/cpu.h> +#include "clk.h" +#include "clk-pll.h" + +/* Exynos4 clock controller register offsets */ +#define SRC_LEFTBUS 0x4200 +#define DIV_LEFTBUS 0x4500 +#define GATE_IP_LEFTBUS 0x4800 +#define E4X12_GATE_IP_IMAGE 0x4930 +#define SRC_RIGHTBUS 0x8200 +#define DIV_RIGHTBUS 0x8500 +#define GATE_IP_RIGHTBUS 0x8800 +#define E4X12_GATE_IP_PERIR 0x8960 +#define EPLL_LOCK 0xc010 +#define VPLL_LOCK 0xc020 +#define EPLL_CON0 0xc110 +#define EPLL_CON1 0xc114 +#define EPLL_CON2 0xc118 +#define VPLL_CON0 0xc120 +#define VPLL_CON1 0xc124 +#define VPLL_CON2 0xc128 +#define SRC_TOP0 0xc210 +#define SRC_TOP1 0xc214 +#define SRC_CAM 0xc220 +#define SRC_TV 0xc224 +#define SRC_MFC 0xcc28 +#define SRC_G3D 0xc22c +#define E4210_SRC_IMAGE 0xc230 +#define SRC_LCD0 0xc234 +#define E4210_SRC_LCD1 0xc238 +#define E4X12_SRC_ISP 0xc238 +#define SRC_MAUDIO 0xc23c +#define SRC_FSYS 0xc240 +#define SRC_PERIL0 0xc250 +#define SRC_PERIL1 0xc254 +#define E4X12_SRC_CAM1 0xc258 +#define SRC_MASK_TOP 0xc310 +#define SRC_MASK_CAM 0xc320 +#define SRC_MASK_TV 0xc324 +#define SRC_MASK_LCD0 0xc334 +#define E4210_SRC_MASK_LCD1 0xc338 +#define E4X12_SRC_MASK_ISP 0xc338 +#define SRC_MASK_MAUDIO 0xc33c +#define SRC_MASK_FSYS 0xc340 +#define SRC_MASK_PERIL0 0xc350 +#define SRC_MASK_PERIL1 0xc354 +#define DIV_TOP 0xc510 +#define DIV_CAM 0xc520 +#define DIV_TV 0xc524 +#define DIV_MFC 0xc528 +#define DIV_G3D 0xc52c +#define DIV_IMAGE 0xc530 +#define DIV_LCD0 0xc534 +#define E4210_DIV_LCD1 0xc538 +#define E4X12_DIV_ISP 0xc538 +#define DIV_MAUDIO 0xc53c +#define DIV_FSYS0 0xc540 +#define DIV_FSYS1 0xc544 +#define DIV_FSYS2 0xc548 +#define DIV_FSYS3 0xc54c +#define DIV_PERIL0 0xc550 +#define DIV_PERIL1 0xc554 +#define DIV_PERIL2 0xc558 +#define DIV_PERIL3 0xc55c +#define DIV_PERIL4 0xc560 +#define DIV_PERIL5 0xc564 +#define E4X12_DIV_CAM1 0xc568 +#define GATE_SCLK_CAM 0xc820 +#define GATE_IP_CAM 0xc920 +#define GATE_IP_TV 0xc924 +#define GATE_IP_MFC 0xc928 +#define GATE_IP_G3D 0xc92c +#define E4210_GATE_IP_IMAGE 0xc930 +#define GATE_IP_LCD0 0xc934 +#define E4210_GATE_IP_LCD1 0xc938 +#define E4X12_GATE_IP_ISP 0xc938 +#define E4X12_GATE_IP_MAUDIO 0xc93c +#define GATE_IP_FSYS 0xc940 +#define GATE_IP_GPS 0xc94c +#define GATE_IP_PERIL 0xc950 +#define E4210_GATE_IP_PERIR 0xc960 +#define GATE_BLOCK 0xc970 +#define E4X12_MPLL_CON0 0x10108 +#define SRC_DMC 0x10200 +#define SRC_MASK_DMC 0x10300 +#define DIV_DMC0 0x10500 +#define DIV_DMC1 0x10504 +#define GATE_IP_DMC 0x10900 +#define APLL_CON0 0x14100 +#define E4210_MPLL_CON0 0x14108 +#define SRC_CPU 0x14200 +#define DIV_CPU0 0x14500 +#define DIV_CPU1 0x14504 +#define GATE_SCLK_CPU 0x14800 +#define GATE_IP_CPU 0x14900 +#define E4X12_DIV_ISP0 0x18300 +#define E4X12_DIV_ISP1 0x18304 +#define E4X12_GATE_ISP0 0x18800 +#define E4X12_GATE_ISP1 0x18804 + +/* the exynos4 soc type */ +enum exynos4_soc { + EXYNOS4210, + EXYNOS4X12, +}; + +/* + * Let each supported clock get a unique id. This id is used to lookup the clock + * for device tree based platforms. The clocks are categorized into three + * sections: core, sclk gate and bus interface gate clocks. + * + * When adding a new clock to this list, it is advised to choose a clock + * category and add it to the end of that category. That is because the the + * device tree source file is referring to these ids and any change in the + * sequence number of existing clocks will require corresponding change in the + * device tree files. This limitation would go away when pre-processor support + * for dtc would be available. + */ +enum exynos4_clks { + none, + + /* core clocks */ + xxti, xusbxti, fin_pll, fout_apll, fout_mpll, fout_epll, fout_vpll, + sclk_apll, sclk_mpll, sclk_epll, sclk_vpll, arm_clk, aclk200, aclk100, + aclk160, aclk133, mout_mpll_user_t, mout_mpll_user_c, mout_core, + mout_apll, /* 20 */ + + /* gate for special clocks (sclk) */ + sclk_fimc0 = 128, sclk_fimc1, sclk_fimc2, sclk_fimc3, sclk_cam0, + sclk_cam1, sclk_csis0, sclk_csis1, sclk_hdmi, sclk_mixer, sclk_dac, + sclk_pixel, sclk_fimd0, sclk_mdnie0, sclk_mdnie_pwm0, sclk_mipi0, + sclk_audio0, sclk_mmc0, sclk_mmc1, sclk_mmc2, sclk_mmc3, sclk_mmc4, + sclk_sata, sclk_uart0, sclk_uart1, sclk_uart2, sclk_uart3, sclk_uart4, + sclk_audio1, sclk_audio2, sclk_spdif, sclk_spi0, sclk_spi1, sclk_spi2, + sclk_slimbus, sclk_fimd1, sclk_mipi1, sclk_pcm1, sclk_pcm2, sclk_i2s1, + sclk_i2s2, sclk_mipihsi, sclk_mfc, sclk_pcm0, sclk_g3d, sclk_pwm_isp, + sclk_spi0_isp, sclk_spi1_isp, sclk_uart_isp, + + /* gate clocks */ + fimc0 = 256, fimc1, fimc2, fimc3, csis0, csis1, jpeg, smmu_fimc0, + smmu_fimc1, smmu_fimc2, smmu_fimc3, smmu_jpeg, vp, mixer, tvenc, hdmi, + smmu_tv, mfc, smmu_mfcl, smmu_mfcr, g3d, g2d, rotator, mdma, smmu_g2d, + smmu_rotator, smmu_mdma, fimd0, mie0, mdnie0, dsim0, smmu_fimd0, fimd1, + mie1, dsim1, smmu_fimd1, pdma0, pdma1, pcie_phy, sata_phy, tsi, sdmmc0, + sdmmc1, sdmmc2, sdmmc3, sdmmc4, sata, sromc, usb_host, usb_device, pcie, + onenand, nfcon, smmu_pcie, gps, smmu_gps, uart0, uart1, uart2, uart3, + uart4, i2c0, i2c1, i2c2, i2c3, i2c4, i2c5, i2c6, i2c7, i2c_hdmi, tsadc, + spi0, spi1, spi2, i2s1, i2s2, pcm0, i2s0, pcm1, pcm2, pwm, slimbus, + spdif, ac97, modemif, chipid, sysreg, hdmi_cec, mct, wdt, rtc, keyif, + audss, mipi_hsi, mdma2, pixelasyncm0, pixelasyncm1, fimc_lite0, + fimc_lite1, ppmuispx, ppmuispmx, fimc_isp, fimc_drc, fimc_fd, mcuisp, + gicisp, smmu_isp, smmu_drc, smmu_fd, smmu_lite0, smmu_lite1, mcuctl_isp, + mpwm_isp, i2c0_isp, i2c1_isp, mtcadc_isp, pwm_isp, wdt_isp, uart_isp, + asyncaxim, smmu_ispcx, spi0_isp, spi1_isp, pwm_isp_sclk, spi0_isp_sclk, + spi1_isp_sclk, uart_isp_sclk, + + /* mux clocks */ + mout_fimc0 = 384, mout_fimc1, mout_fimc2, mout_fimc3, mout_cam0, + mout_cam1, mout_csis0, mout_csis1, mout_g3d0, mout_g3d1, mout_g3d, + aclk400_mcuisp, + + /* div clocks */ + div_isp0 = 450, div_isp1, div_mcuisp0, div_mcuisp1, div_aclk200, + div_aclk400_mcuisp, + + nr_clks, +}; + +/* + * list of controller registers to be saved and restored during a + * suspend/resume cycle. + */ +static __initdata unsigned long exynos4210_clk_save[] = { + E4210_SRC_IMAGE, + E4210_SRC_LCD1, + E4210_SRC_MASK_LCD1, + E4210_DIV_LCD1, + E4210_GATE_IP_IMAGE, + E4210_GATE_IP_LCD1, + E4210_GATE_IP_PERIR, + E4210_MPLL_CON0, +}; + +static __initdata unsigned long exynos4x12_clk_save[] = { + E4X12_GATE_IP_IMAGE, + E4X12_GATE_IP_PERIR, + E4X12_SRC_CAM1, + E4X12_DIV_ISP, + E4X12_DIV_CAM1, + E4X12_MPLL_CON0, +}; + +static __initdata unsigned long exynos4_clk_regs[] = { + SRC_LEFTBUS, + DIV_LEFTBUS, + GATE_IP_LEFTBUS, + SRC_RIGHTBUS, + DIV_RIGHTBUS, + GATE_IP_RIGHTBUS, + EPLL_CON0, + EPLL_CON1, + EPLL_CON2, + VPLL_CON0, + VPLL_CON1, + VPLL_CON2, + SRC_TOP0, + SRC_TOP1, + SRC_CAM, + SRC_TV, + SRC_MFC, + SRC_G3D, + SRC_LCD0, + SRC_MAUDIO, + SRC_FSYS, + SRC_PERIL0, + SRC_PERIL1, + SRC_MASK_TOP, + SRC_MASK_CAM, + SRC_MASK_TV, + SRC_MASK_LCD0, + SRC_MASK_MAUDIO, + SRC_MASK_FSYS, + SRC_MASK_PERIL0, + SRC_MASK_PERIL1, + DIV_TOP, + DIV_CAM, + DIV_TV, + DIV_MFC, + DIV_G3D, + DIV_IMAGE, + DIV_LCD0, + DIV_MAUDIO, + DIV_FSYS0, + DIV_FSYS1, + DIV_FSYS2, + DIV_FSYS3, + DIV_PERIL0, + DIV_PERIL1, + DIV_PERIL2, + DIV_PERIL3, + DIV_PERIL4, + DIV_PERIL5, + GATE_SCLK_CAM, + GATE_IP_CAM, + GATE_IP_TV, + GATE_IP_MFC, + GATE_IP_G3D, + GATE_IP_LCD0, + GATE_IP_FSYS, + GATE_IP_GPS, + GATE_IP_PERIL, + GATE_BLOCK, + SRC_MASK_DMC, + SRC_DMC, + DIV_DMC0, + DIV_DMC1, + GATE_IP_DMC, + APLL_CON0, + SRC_CPU, + DIV_CPU0, + DIV_CPU1, + GATE_SCLK_CPU, + GATE_IP_CPU, +}; + +/* list of all parent clock list */ +PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; +PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", }; +PNAME(mout_epll_p) = { "fin_pll", "fout_epll", }; +PNAME(mout_vpllsrc_p) = { "fin_pll", "sclk_hdmi24m", }; +PNAME(mout_vpll_p) = { "fin_pll", "fout_vpll", }; +PNAME(sclk_evpll_p) = { "sclk_epll", "sclk_vpll", }; +PNAME(mout_mfc_p) = { "mout_mfc0", "mout_mfc1", }; +PNAME(mout_g3d_p) = { "mout_g3d0", "mout_g3d1", }; +PNAME(mout_g2d_p) = { "mout_g2d0", "mout_g2d1", }; +PNAME(mout_hdmi_p) = { "sclk_pixel", "sclk_hdmiphy", }; +PNAME(mout_jpeg_p) = { "mout_jpeg0", "mout_jpeg1", }; +PNAME(mout_spdif_p) = { "sclk_audio0", "sclk_audio1", "sclk_audio2", + "spdif_extclk", }; +PNAME(mout_onenand_p) = {"aclk133", "aclk160", }; +PNAME(mout_onenand1_p) = {"mout_onenand", "sclk_vpll", }; + +/* Exynos 4210-specific parent groups */ +PNAME(sclk_vpll_p4210) = { "mout_vpllsrc", "fout_vpll", }; +PNAME(mout_core_p4210) = { "mout_apll", "sclk_mpll", }; +PNAME(sclk_ampll_p4210) = { "sclk_mpll", "sclk_apll", }; +PNAME(group1_p4210) = { "xxti", "xusbxti", "sclk_hdmi24m", + "sclk_usbphy0", "none", "sclk_hdmiphy", + "sclk_mpll", "sclk_epll", "sclk_vpll", }; +PNAME(mout_audio0_p4210) = { "cdclk0", "none", "sclk_hdmi24m", + "sclk_usbphy0", "xxti", "xusbxti", "sclk_mpll", + "sclk_epll", "sclk_vpll" }; +PNAME(mout_audio1_p4210) = { "cdclk1", "none", "sclk_hdmi24m", + "sclk_usbphy0", "xxti", "xusbxti", "sclk_mpll", + "sclk_epll", "sclk_vpll", }; +PNAME(mout_audio2_p4210) = { "cdclk2", "none", "sclk_hdmi24m", + "sclk_usbphy0", "xxti", "xusbxti", "sclk_mpll", + "sclk_epll", "sclk_vpll", }; +PNAME(mout_mixer_p4210) = { "sclk_dac", "sclk_hdmi", }; +PNAME(mout_dac_p4210) = { "sclk_vpll", "sclk_hdmiphy", }; + +/* Exynos 4x12-specific parent groups */ +PNAME(mout_mpll_user_p4x12) = { "fin_pll", "sclk_mpll", }; +PNAME(mout_core_p4x12) = { "mout_apll", "mout_mpll_user_c", }; +PNAME(sclk_ampll_p4x12) = { "mout_mpll_user_t", "sclk_apll", }; +PNAME(group1_p4x12) = { "xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0", + "none", "sclk_hdmiphy", "mout_mpll_user_t", + "sclk_epll", "sclk_vpll", }; +PNAME(mout_audio0_p4x12) = { "cdclk0", "none", "sclk_hdmi24m", + "sclk_usbphy0", "xxti", "xusbxti", + "mout_mpll_user_t", "sclk_epll", "sclk_vpll" }; +PNAME(mout_audio1_p4x12) = { "cdclk1", "none", "sclk_hdmi24m", + "sclk_usbphy0", "xxti", "xusbxti", + "mout_mpll_user_t", "sclk_epll", "sclk_vpll", }; +PNAME(mout_audio2_p4x12) = { "cdclk2", "none", "sclk_hdmi24m", + "sclk_usbphy0", "xxti", "xusbxti", + "mout_mpll_user_t", "sclk_epll", "sclk_vpll", }; +PNAME(aclk_p4412) = { "mout_mpll_user_t", "sclk_apll", }; +PNAME(mout_user_aclk400_mcuisp_p4x12) = {"fin_pll", "div_aclk400_mcuisp", }; +PNAME(mout_user_aclk200_p4x12) = {"fin_pll", "div_aclk200", }; +PNAME(mout_user_aclk266_gps_p4x12) = {"fin_pll", "div_aclk266_gps", }; + +/* fixed rate clocks generated outside the soc */ +struct samsung_fixed_rate_clock exynos4_fixed_rate_ext_clks[] __initdata = { + FRATE(xxti, "xxti", NULL, CLK_IS_ROOT, 0), + FRATE(xusbxti, "xusbxti", NULL, CLK_IS_ROOT, 0), +}; + +/* fixed rate clocks generated inside the soc */ +struct samsung_fixed_rate_clock exynos4_fixed_rate_clks[] __initdata = { + FRATE(none, "sclk_hdmi24m", NULL, CLK_IS_ROOT, 24000000), + FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000), + FRATE(none, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000), +}; + +struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = { + FRATE(none, "sclk_usbphy1", NULL, CLK_IS_ROOT, 48000000), +}; + +/* list of mux clocks supported in all exynos4 soc's */ +struct samsung_mux_clock exynos4_mux_clks[] __initdata = { + MUX_F(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, + CLK_SET_RATE_PARENT, 0), + MUX(none, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1), + MUX(none, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1), + MUX(none, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1), + MUX_F(mout_g3d1, "mout_g3d1", sclk_evpll_p, SRC_G3D, 4, 1, + CLK_SET_RATE_PARENT, 0), + MUX_F(mout_g3d, "mout_g3d", mout_g3d_p, SRC_G3D, 8, 1, + CLK_SET_RATE_PARENT, 0), + MUX(none, "mout_spdif", mout_spdif_p, SRC_PERIL1, 8, 2), + MUX(none, "mout_onenand1", mout_onenand1_p, SRC_TOP0, 0, 1), + MUX_A(sclk_epll, "sclk_epll", mout_epll_p, SRC_TOP0, 4, 1, "sclk_epll"), + MUX(none, "mout_onenand", mout_onenand_p, SRC_TOP0, 28, 1), +}; + +/* list of mux clocks supported in exynos4210 soc */ +struct samsung_mux_clock exynos4210_mux_clks[] __initdata = { + MUX(none, "mout_aclk200", sclk_ampll_p4210, SRC_TOP0, 12, 1), + MUX(none, "mout_aclk100", sclk_ampll_p4210, SRC_TOP0, 16, 1), + MUX(none, "mout_aclk160", sclk_ampll_p4210, SRC_TOP0, 20, 1), + MUX(none, "mout_aclk133", sclk_ampll_p4210, SRC_TOP0, 24, 1), + MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP1, 0, 1), + MUX(none, "mout_mixer", mout_mixer_p4210, SRC_TV, 4, 1), + MUX(none, "mout_dac", mout_dac_p4210, SRC_TV, 8, 1), + MUX(none, "mout_g2d0", sclk_ampll_p4210, E4210_SRC_IMAGE, 0, 1), + MUX(none, "mout_g2d1", sclk_evpll_p, E4210_SRC_IMAGE, 4, 1), + MUX(none, "mout_g2d", mout_g2d_p, E4210_SRC_IMAGE, 8, 1), + MUX(none, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4), + MUX(none, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4), + MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "sclk_mpll"), + MUX_A(mout_core, "mout_core", mout_core_p4210, + SRC_CPU, 16, 1, "mout_core"), + MUX_A(sclk_vpll, "sclk_vpll", sclk_vpll_p4210, + SRC_TOP0, 8, 1, "sclk_vpll"), + MUX(mout_fimc0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4), + MUX(mout_fimc1, "mout_fimc1", group1_p4210, SRC_CAM, 4, 4), + MUX(mout_fimc2, "mout_fimc2", group1_p4210, SRC_CAM, 8, 4), + MUX(mout_fimc3, "mout_fimc3", group1_p4210, SRC_CAM, 12, 4), + MUX(mout_cam0, "mout_cam0", group1_p4210, SRC_CAM, 16, 4), + MUX(mout_cam1, "mout_cam1", group1_p4210, SRC_CAM, 20, 4), + MUX(mout_csis0, "mout_csis0", group1_p4210, SRC_CAM, 24, 4), + MUX(mout_csis1, "mout_csis1", group1_p4210, SRC_CAM, 28, 4), + MUX(none, "mout_mfc0", sclk_ampll_p4210, SRC_MFC, 0, 1), + MUX_F(mout_g3d0, "mout_g3d0", sclk_ampll_p4210, SRC_G3D, 0, 1, + CLK_SET_RATE_PARENT, 0), + MUX(none, "mout_fimd0", group1_p4210, SRC_LCD0, 0, 4), + MUX(none, "mout_mipi0", group1_p4210, SRC_LCD0, 12, 4), + MUX(none, "mout_audio0", mout_audio0_p4210, SRC_MAUDIO, 0, 4), + MUX(none, "mout_mmc0", group1_p4210, SRC_FSYS, 0, 4), + MUX(none, "mout_mmc1", group1_p4210, SRC_FSYS, 4, 4), + MUX(none, "mout_mmc2", group1_p4210, SRC_FSYS, 8, 4), + MUX(none, "mout_mmc3", group1_p4210, SRC_FSYS, 12, 4), + MUX(none, "mout_mmc4", group1_p4210, SRC_FSYS, 16, 4), + MUX(none, "mout_sata", sclk_ampll_p4210, SRC_FSYS, 24, 1), + MUX(none, "mout_uart0", group1_p4210, SRC_PERIL0, 0, 4), + MUX(none, "mout_uart1", group1_p4210, SRC_PERIL0, 4, 4), + MUX(none, "mout_uart2", group1_p4210, SRC_PERIL0, 8, 4), + MUX(none, "mout_uart3", group1_p4210, SRC_PERIL0, 12, 4), + MUX(none, "mout_uart4", group1_p4210, SRC_PERIL0, 16, 4), + MUX(none, "mout_audio1", mout_audio1_p4210, SRC_PERIL1, 0, 4), + MUX(none, "mout_audio2", mout_audio2_p4210, SRC_PERIL1, 4, 4), + MUX(none, "mout_spi0", group1_p4210, SRC_PERIL1, 16, 4), + MUX(none, "mout_spi1", group1_p4210, SRC_PERIL1, 20, 4), + MUX(none, "mout_spi2", group1_p4210, SRC_PERIL1, 24, 4), +}; + +/* list of mux clocks supported in exynos4x12 soc */ +struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = { + MUX(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12, + SRC_CPU, 24, 1), + MUX(none, "mout_aclk266_gps", aclk_p4412, SRC_TOP1, 4, 1), + MUX(none, "mout_aclk400_mcuisp", aclk_p4412, SRC_TOP1, 8, 1), + MUX(mout_mpll_user_t, "mout_mpll_user_t", mout_mpll_user_p4x12, + SRC_TOP1, 12, 1), + MUX(none, "mout_user_aclk266_gps", mout_user_aclk266_gps_p4x12, + SRC_TOP1, 16, 1), + MUX(aclk200, "aclk200", mout_user_aclk200_p4x12, SRC_TOP1, 20, 1), + MUX(aclk400_mcuisp, "aclk400_mcuisp", mout_user_aclk400_mcuisp_p4x12, + SRC_TOP1, 24, 1), + MUX(none, "mout_aclk200", aclk_p4412, SRC_TOP0, 12, 1), + MUX(none, "mout_aclk100", aclk_p4412, SRC_TOP0, 16, 1), + MUX(none, "mout_aclk160", aclk_p4412, SRC_TOP0, 20, 1), + MUX(none, "mout_aclk133", aclk_p4412, SRC_TOP0, 24, 1), + MUX(none, "mout_mdnie0", group1_p4x12, SRC_LCD0, 4, 4), + MUX(none, "mout_mdnie_pwm0", group1_p4x12, SRC_LCD0, 8, 4), + MUX(none, "mout_sata", sclk_ampll_p4x12, SRC_FSYS, 24, 1), + MUX(none, "mout_jpeg0", sclk_ampll_p4x12, E4X12_SRC_CAM1, 0, 1), + MUX(none, "mout_jpeg1", sclk_evpll_p, E4X12_SRC_CAM1, 4, 1), + MUX(none, "mout_jpeg", mout_jpeg_p, E4X12_SRC_CAM1, 8, 1), + MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, + SRC_DMC, 12, 1, "sclk_mpll"), + MUX_A(sclk_vpll, "sclk_vpll", mout_vpll_p, + SRC_TOP0, 8, 1, "sclk_vpll"), + MUX(mout_core, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1), + MUX(mout_fimc0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4), + MUX(mout_fimc1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4), + MUX(mout_fimc2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4), + MUX(mout_fimc3, "mout_fimc3", group1_p4x12, SRC_CAM, 12, 4), + MUX(mout_cam0, "mout_cam0", group1_p4x12, SRC_CAM, 16, 4), + MUX(mout_cam1, "mout_cam1", group1_p4x12, SRC_CAM, 20, 4), + MUX(mout_csis0, "mout_csis0", group1_p4x12, SRC_CAM, 24, 4), + MUX(mout_csis1, "mout_csis1", group1_p4x12, SRC_CAM, 28, 4), + MUX(none, "mout_mfc0", sclk_ampll_p4x12, SRC_MFC, 0, 1), + MUX_F(mout_g3d0, "mout_g3d0", sclk_ampll_p4x12, SRC_G3D, 0, 1, + CLK_SET_RATE_PARENT, 0), + MUX(none, "mout_fimd0", group1_p4x12, SRC_LCD0, 0, 4), + MUX(none, "mout_mipi0", group1_p4x12, SRC_LCD0, 12, 4), + MUX(none, "mout_audio0", mout_audio0_p4x12, SRC_MAUDIO, 0, 4), + MUX(none, "mout_mmc0", group1_p4x12, SRC_FSYS, 0, 4), + MUX(none, "mout_mmc1", group1_p4x12, SRC_FSYS, 4, 4), + MUX(none, "mout_mmc2", group1_p4x12, SRC_FSYS, 8, 4), + MUX(none, "mout_mmc3", group1_p4x12, SRC_FSYS, 12, 4), + MUX(none, "mout_mmc4", group1_p4x12, SRC_FSYS, 16, 4), + MUX(none, "mout_mipihsi", aclk_p4412, SRC_FSYS, 24, 1), + MUX(none, "mout_uart0", group1_p4x12, SRC_PERIL0, 0, 4), + MUX(none, "mout_uart1", group1_p4x12, SRC_PERIL0, 4, 4), + MUX(none, "mout_uart2", group1_p4x12, SRC_PERIL0, 8, 4), + MUX(none, "mout_uart3", group1_p4x12, SRC_PERIL0, 12, 4), + MUX(none, "mout_uart4", group1_p4x12, SRC_PERIL0, 16, 4), + MUX(none, "mout_audio1", mout_audio1_p4x12, SRC_PERIL1, 0, 4), + MUX(none, "mout_audio2", mout_audio2_p4x12, SRC_PERIL1, 4, 4), + MUX(none, "mout_spi0", group1_p4x12, SRC_PERIL1, 16, 4), + MUX(none, "mout_spi1", group1_p4x12, SRC_PERIL1, 20, 4), + MUX(none, "mout_spi2", group1_p4x12, SRC_PERIL1, 24, 4), + MUX(none, "mout_pwm_isp", group1_p4x12, E4X12_SRC_ISP, 0, 4), + MUX(none, "mout_spi0_isp", group1_p4x12, E4X12_SRC_ISP, 4, 4), + MUX(none, "mout_spi1_isp", group1_p4x12, E4X12_SRC_ISP, 8, 4), + MUX(none, "mout_uart_isp", group1_p4x12, E4X12_SRC_ISP, 12, 4), +}; + +/* list of divider clocks supported in all exynos4 soc's */ +struct samsung_div_clock exynos4_div_clks[] __initdata = { + DIV(none, "div_core", "mout_core", DIV_CPU0, 0, 3), + DIV(none, "div_core2", "div_core", DIV_CPU0, 28, 3), + DIV(none, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4), + DIV(none, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4), + DIV(none, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4), + DIV(none, "div_fimc3", "mout_fimc3", DIV_CAM, 12, 4), + DIV(none, "div_cam0", "mout_cam0", DIV_CAM, 16, 4), + DIV(none, "div_cam1", "mout_cam1", DIV_CAM, 20, 4), + DIV(none, "div_csis0", "mout_csis0", DIV_CAM, 24, 4), + DIV(none, "div_csis1", "mout_csis1", DIV_CAM, 28, 4), + DIV(sclk_mfc, "sclk_mfc", "mout_mfc", DIV_MFC, 0, 4), + DIV_F(none, "div_g3d", "mout_g3d", DIV_G3D, 0, 4, + CLK_SET_RATE_PARENT, 0), + DIV(none, "div_fimd0", "mout_fimd0", DIV_LCD0, 0, 4), + DIV(none, "div_mipi0", "mout_mipi0", DIV_LCD0, 16, 4), + DIV(none, "div_audio0", "mout_audio0", DIV_MAUDIO, 0, 4), + DIV(sclk_pcm0, "sclk_pcm0", "sclk_audio0", DIV_MAUDIO, 4, 8), + DIV(none, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4), + DIV(none, "div_mmc1", "mout_mmc1", DIV_FSYS1, 16, 4), + DIV(none, "div_mmc2", "mout_mmc2", DIV_FSYS2, 0, 4), + DIV(none, "div_mmc3", "mout_mmc3", DIV_FSYS2, 16, 4), + DIV(sclk_pixel, "sclk_pixel", "sclk_vpll", DIV_TV, 0, 4), + DIV(aclk100, "aclk100", "mout_aclk100", DIV_TOP, 4, 4), + DIV(aclk160, "aclk160", "mout_aclk160", DIV_TOP, 8, 3), + DIV(aclk133, "aclk133", "mout_aclk133", DIV_TOP, 12, 3), + DIV(none, "div_onenand", "mout_onenand1", DIV_TOP, 16, 3), + DIV(sclk_slimbus, "sclk_slimbus", "sclk_epll", DIV_PERIL3, 4, 4), + DIV(sclk_pcm1, "sclk_pcm1", "sclk_audio1", DIV_PERIL4, 4, 8), + DIV(sclk_pcm2, "sclk_pcm2", "sclk_audio2", DIV_PERIL4, 20, 8), + DIV(sclk_i2s1, "sclk_i2s1", "sclk_audio1", DIV_PERIL5, 0, 6), + DIV(sclk_i2s2, "sclk_i2s2", "sclk_audio2", DIV_PERIL5, 8, 6), + DIV(none, "div_mmc4", "mout_mmc4", DIV_FSYS3, 0, 4), + DIV(none, "div_mmc_pre4", "div_mmc4", DIV_FSYS3, 8, 8), + DIV(none, "div_uart0", "mout_uart0", DIV_PERIL0, 0, 4), + DIV(none, "div_uart1", "mout_uart1", DIV_PERIL0, 4, 4), + DIV(none, "div_uart2", "mout_uart2", DIV_PERIL0, 8, 4), + DIV(none, "div_uart3", "mout_uart3", DIV_PERIL0, 12, 4), + DIV(none, "div_uart4", "mout_uart4", DIV_PERIL0, 16, 4), + DIV(none, "div_spi0", "mout_spi0", DIV_PERIL1, 0, 4), + DIV(none, "div_spi_pre0", "div_spi0", DIV_PERIL1, 8, 8), + DIV(none, "div_spi1", "mout_spi1", DIV_PERIL1, 16, 4), + DIV(none, "div_spi_pre1", "div_spi1", DIV_PERIL1, 24, 8), + DIV(none, "div_spi2", "mout_spi2", DIV_PERIL2, 0, 4), + DIV(none, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8), + DIV(none, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4), + DIV(none, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4), + DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "arm_clk"), + DIV_A(sclk_apll, "sclk_apll", "mout_apll", + DIV_CPU0, 24, 3, "sclk_apll"), + DIV_F(none, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4, + CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8, + CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_mmc_pre1", "div_mmc1", DIV_FSYS1, 24, 8, + CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_mmc_pre2", "div_mmc2", DIV_FSYS2, 8, 8, + CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_mmc_pre3", "div_mmc3", DIV_FSYS2, 24, 8, + CLK_SET_RATE_PARENT, 0), +}; + +/* list of divider clocks supported in exynos4210 soc */ +struct samsung_div_clock exynos4210_div_clks[] __initdata = { + DIV(aclk200, "aclk200", "mout_aclk200", DIV_TOP, 0, 3), + DIV(none, "div_g2d", "mout_g2d", DIV_IMAGE, 0, 4), + DIV(none, "div_fimd1", "mout_fimd1", E4210_DIV_LCD1, 0, 4), + DIV(none, "div_mipi1", "mout_mipi1", E4210_DIV_LCD1, 16, 4), + DIV(none, "div_sata", "mout_sata", DIV_FSYS0, 20, 4), + DIV_F(none, "div_mipi_pre1", "div_mipi1", E4210_DIV_LCD1, 20, 4, + CLK_SET_RATE_PARENT, 0), +}; + +/* list of divider clocks supported in exynos4x12 soc */ +struct samsung_div_clock exynos4x12_div_clks[] __initdata = { + DIV(none, "div_mdnie0", "mout_mdnie0", DIV_LCD0, 4, 4), + DIV(none, "div_mdnie_pwm0", "mout_mdnie_pwm0", DIV_LCD0, 8, 4), + DIV(none, "div_mdnie_pwm_pre0", "div_mdnie_pwm0", DIV_LCD0, 12, 4), + DIV(none, "div_mipihsi", "mout_mipihsi", DIV_FSYS0, 20, 4), + DIV(none, "div_jpeg", "mout_jpeg", E4X12_DIV_CAM1, 0, 4), + DIV(div_aclk200, "div_aclk200", "mout_aclk200", DIV_TOP, 0, 3), + DIV(none, "div_aclk266_gps", "mout_aclk266_gps", DIV_TOP, 20, 3), + DIV(div_aclk400_mcuisp, "div_aclk400_mcuisp", "mout_aclk400_mcuisp", + DIV_TOP, 24, 3), + DIV(none, "div_pwm_isp", "mout_pwm_isp", E4X12_DIV_ISP, 0, 4), + DIV(none, "div_spi0_isp", "mout_spi0_isp", E4X12_DIV_ISP, 4, 4), + DIV(none, "div_spi0_isp_pre", "div_spi0_isp", E4X12_DIV_ISP, 8, 8), + DIV(none, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4), + DIV(none, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8), + DIV(none, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4), + DIV(div_isp0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3), + DIV(div_isp1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3), + DIV(none, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3), + DIV(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, 4, 3), + DIV(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, 8, 3), +}; + +/* list of gate clocks supported in all exynos4 soc's */ +struct samsung_gate_clock exynos4_gate_clks[] __initdata = { + /* + * After all Exynos4 based platforms are migrated to use device tree, + * the device name and clock alias names specified below for some + * of the clocks can be removed. + */ + GATE(sclk_hdmi, "sclk_hdmi", "mout_hdmi", SRC_MASK_TV, 0, 0, 0), + GATE(sclk_spdif, "sclk_spdif", "mout_spdif", SRC_MASK_PERIL1, 8, 0, 0), + GATE(jpeg, "jpeg", "aclk160", GATE_IP_CAM, 6, 0, 0), + GATE(mie0, "mie0", "aclk160", GATE_IP_LCD0, 1, 0, 0), + GATE(dsim0, "dsim0", "aclk160", GATE_IP_LCD0, 3, 0, 0), + GATE(fimd1, "fimd1", "aclk160", E4210_GATE_IP_LCD1, 0, 0, 0), + GATE(mie1, "mie1", "aclk160", E4210_GATE_IP_LCD1, 1, 0, 0), + GATE(dsim1, "dsim1", "aclk160", E4210_GATE_IP_LCD1, 3, 0, 0), + GATE(smmu_fimd1, "smmu_fimd1", "aclk160", E4210_GATE_IP_LCD1, 4, 0, 0), + GATE(tsi, "tsi", "aclk133", GATE_IP_FSYS, 4, 0, 0), + GATE(sromc, "sromc", "aclk133", GATE_IP_FSYS, 11, 0, 0), + GATE(sclk_g3d, "sclk_g3d", "div_g3d", GATE_IP_G3D, 0, + CLK_SET_RATE_PARENT, 0), + GATE(usb_device, "usb_device", "aclk133", GATE_IP_FSYS, 13, 0, 0), + GATE(onenand, "onenand", "aclk133", GATE_IP_FSYS, 15, 0, 0), + GATE(nfcon, "nfcon", "aclk133", GATE_IP_FSYS, 16, 0, 0), + GATE(gps, "gps", "aclk133", GATE_IP_GPS, 0, 0, 0), + GATE(smmu_gps, "smmu_gps", "aclk133", GATE_IP_GPS, 1, 0, 0), + GATE(slimbus, "slimbus", "aclk100", GATE_IP_PERIL, 25, 0, 0), + GATE(sclk_cam0, "sclk_cam0", "div_cam0", GATE_SCLK_CAM, 4, + CLK_SET_RATE_PARENT, 0), + GATE(sclk_cam1, "sclk_cam1", "div_cam1", GATE_SCLK_CAM, 5, + CLK_SET_RATE_PARENT, 0), + GATE(sclk_mipi0, "sclk_mipi0", "div_mipi_pre0", + SRC_MASK_LCD0, 12, CLK_SET_RATE_PARENT, 0), + GATE(sclk_audio0, "sclk_audio0", "div_audio0", SRC_MASK_MAUDIO, 0, + CLK_SET_RATE_PARENT, 0), + GATE(sclk_audio1, "sclk_audio1", "div_audio1", SRC_MASK_PERIL1, 0, + CLK_SET_RATE_PARENT, 0), + GATE_D(vp, "s5p-mixer", "vp", "aclk160", GATE_IP_TV, 0, 0, 0), + GATE_D(mixer, "s5p-mixer", "mixer", "aclk160", GATE_IP_TV, 1, 0, 0), + GATE_D(hdmi, "exynos4-hdmi", "hdmi", "aclk160", GATE_IP_TV, 3, 0, 0), + GATE_A(pwm, "pwm", "aclk100", GATE_IP_PERIL, 24, 0, 0, "timers"), + GATE_A(sdmmc4, "sdmmc4", "aclk133", GATE_IP_FSYS, 9, 0, 0, "biu"), + GATE_A(usb_host, "usb_host", "aclk133", + GATE_IP_FSYS, 12, 0, 0, "usbhost"), + GATE_DA(sclk_fimc0, "exynos4-fimc.0", "sclk_fimc0", "div_fimc0", + SRC_MASK_CAM, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimc"), + GATE_DA(sclk_fimc1, "exynos4-fimc.1", "sclk_fimc1", "div_fimc1", + SRC_MASK_CAM, 4, CLK_SET_RATE_PARENT, 0, "sclk_fimc"), + GATE_DA(sclk_fimc2, "exynos4-fimc.2", "sclk_fimc2", "div_fimc2", + SRC_MASK_CAM, 8, CLK_SET_RATE_PARENT, 0, "sclk_fimc"), + GATE_DA(sclk_fimc3, "exynos4-fimc.3", "sclk_fimc3", "div_fimc3", + SRC_MASK_CAM, 12, CLK_SET_RATE_PARENT, 0, "sclk_fimc"), + GATE_DA(sclk_csis0, "s5p-mipi-csis.0", "sclk_csis0", "div_csis0", + SRC_MASK_CAM, 24, CLK_SET_RATE_PARENT, 0, "sclk_csis"), + GATE_DA(sclk_csis1, "s5p-mipi-csis.1", "sclk_csis1", "div_csis1", + SRC_MASK_CAM, 28, CLK_SET_RATE_PARENT, 0, "sclk_csis"), + GATE_DA(sclk_fimd0, "exynos4-fb.0", "sclk_fimd0", "div_fimd0", + SRC_MASK_LCD0, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimd"), + GATE_DA(sclk_mmc0, "exynos4-sdhci.0", "sclk_mmc0", "div_mmc_pre0", + SRC_MASK_FSYS, 0, CLK_SET_RATE_PARENT, 0, + "mmc_busclk.2"), + GATE_DA(sclk_mmc1, "exynos4-sdhci.1", "sclk_mmc1", "div_mmc_pre1", + SRC_MASK_FSYS, 4, CLK_SET_RATE_PARENT, 0, + "mmc_busclk.2"), + GATE_DA(sclk_mmc2, "exynos4-sdhci.2", "sclk_mmc2", "div_mmc_pre2", + SRC_MASK_FSYS, 8, CLK_SET_RATE_PARENT, 0, + "mmc_busclk.2"), + GATE_DA(sclk_mmc3, "exynos4-sdhci.3", "sclk_mmc3", "div_mmc_pre3", + SRC_MASK_FSYS, 12, CLK_SET_RATE_PARENT, 0, + "mmc_busclk.2"), + GATE_DA(sclk_mmc4, NULL, "sclk_mmc4", "div_mmc_pre4", + SRC_MASK_FSYS, 16, CLK_SET_RATE_PARENT, 0, "ciu"), + GATE_DA(sclk_uart0, "exynos4210-uart.0", "uclk0", "div_uart0", + SRC_MASK_PERIL0, 0, CLK_SET_RATE_PARENT, + 0, "clk_uart_baud0"), + GATE_DA(sclk_uart1, "exynos4210-uart.1", "uclk1", "div_uart1", + SRC_MASK_PERIL0, 4, CLK_SET_RATE_PARENT, + 0, "clk_uart_baud0"), + GATE_DA(sclk_uart2, "exynos4210-uart.2", "uclk2", "div_uart2", + SRC_MASK_PERIL0, 8, CLK_SET_RATE_PARENT, + 0, "clk_uart_baud0"), + GATE_DA(sclk_uart3, "exynos4210-uart.3", "uclk3", "div_uart3", + SRC_MASK_PERIL0, 12, CLK_SET_RATE_PARENT, + 0, "clk_uart_baud0"), + GATE_DA(sclk_uart4, "exynos4210-uart.4", "uclk4", "div_uart4", + SRC_MASK_PERIL0, 16, CLK_SET_RATE_PARENT, + 0, "clk_uart_baud0"), + GATE(sclk_audio2, "sclk_audio2", "div_audio2", SRC_MASK_PERIL1, 4, + CLK_SET_RATE_PARENT, 0), + GATE_DA(sclk_spi0, "exynos4210-spi.0", "sclk_spi0", "div_spi_pre0", + SRC_MASK_PERIL1, 16, CLK_SET_RATE_PARENT, + 0, "spi_busclk0"), + GATE_DA(sclk_spi1, "exynos4210-spi.1", "sclk_spi1", "div_spi_pre1", + SRC_MASK_PERIL1, 20, CLK_SET_RATE_PARENT, + 0, "spi_busclk0"), + GATE_DA(sclk_spi2, "exynos4210-spi.2", "sclk_spi2", "div_spi_pre2", + SRC_MASK_PERIL1, 24, CLK_SET_RATE_PARENT, + 0, "spi_busclk0"), + GATE_DA(fimc0, "exynos4-fimc.0", "fimc0", "aclk160", + GATE_IP_CAM, 0, 0, 0, "fimc"), + GATE_DA(fimc1, "exynos4-fimc.1", "fimc1", "aclk160", + GATE_IP_CAM, 1, 0, 0, "fimc"), + GATE_DA(fimc2, "exynos4-fimc.2", "fimc2", "aclk160", + GATE_IP_CAM, 2, 0, 0, "fimc"), + GATE_DA(fimc3, "exynos4-fimc.3", "fimc3", "aclk160", + GATE_IP_CAM, 3, 0, 0, "fimc"), + GATE_DA(csis0, "s5p-mipi-csis.0", "csis0", "aclk160", + GATE_IP_CAM, 4, 0, 0, "fimc"), + GATE_DA(csis1, "s5p-mipi-csis.1", "csis1", "aclk160", + GATE_IP_CAM, 5, 0, 0, "fimc"), + GATE_DA(smmu_fimc0, "exynos-sysmmu.5", "smmu_fimc0", "aclk160", + GATE_IP_CAM, 7, 0, 0, "sysmmu"), + GATE_DA(smmu_fimc1, "exynos-sysmmu.6", "smmu_fimc1", "aclk160", + GATE_IP_CAM, 8, 0, 0, "sysmmu"), + GATE_DA(smmu_fimc2, "exynos-sysmmu.7", "smmu_fimc2", "aclk160", + GATE_IP_CAM, 9, 0, 0, "sysmmu"), + GATE_DA(smmu_fimc3, "exynos-sysmmu.8", "smmu_fimc3", "aclk160", + GATE_IP_CAM, 10, 0, 0, "sysmmu"), + GATE_DA(smmu_jpeg, "exynos-sysmmu.3", "smmu_jpeg", "aclk160", + GATE_IP_CAM, 11, 0, 0, "sysmmu"), + GATE(pixelasyncm0, "pxl_async0", "aclk160", GATE_IP_CAM, 17, 0, 0), + GATE(pixelasyncm1, "pxl_async1", "aclk160", GATE_IP_CAM, 18, 0, 0), + GATE_DA(smmu_tv, "exynos-sysmmu.2", "smmu_tv", "aclk160", + GATE_IP_TV, 4, 0, 0, "sysmmu"), + GATE_DA(mfc, "s5p-mfc", "mfc", "aclk100", GATE_IP_MFC, 0, 0, 0, "mfc"), + GATE_DA(smmu_mfcl, "exynos-sysmmu.0", "smmu_mfcl", "aclk100", + GATE_IP_MFC, 1, 0, 0, "sysmmu"), + GATE_DA(smmu_mfcr, "exynos-sysmmu.1", "smmu_mfcr", "aclk100", + GATE_IP_MFC, 2, 0, 0, "sysmmu"), + GATE_DA(fimd0, "exynos4-fb.0", "fimd0", "aclk160", + GATE_IP_LCD0, 0, 0, 0, "fimd"), + GATE_DA(smmu_fimd0, "exynos-sysmmu.10", "smmu_fimd0", "aclk160", + GATE_IP_LCD0, 4, 0, 0, "sysmmu"), + GATE_DA(pdma0, "dma-pl330.0", "pdma0", "aclk133", + GATE_IP_FSYS, 0, 0, 0, "dma"), + GATE_DA(pdma1, "dma-pl330.1", "pdma1", "aclk133", + GATE_IP_FSYS, 1, 0, 0, "dma"), + GATE_DA(sdmmc0, "exynos4-sdhci.0", "sdmmc0", "aclk133", + GATE_IP_FSYS, 5, 0, 0, "hsmmc"), + GATE_DA(sdmmc1, "exynos4-sdhci.1", "sdmmc1", "aclk133", + GATE_IP_FSYS, 6, 0, 0, "hsmmc"), + GATE_DA(sdmmc2, "exynos4-sdhci.2", "sdmmc2", "aclk133", + GATE_IP_FSYS, 7, 0, 0, "hsmmc"), + GATE_DA(sdmmc3, "exynos4-sdhci.3", "sdmmc3", "aclk133", + GATE_IP_FSYS, 8, 0, 0, "hsmmc"), + GATE_DA(uart0, "exynos4210-uart.0", "uart0", "aclk100", + GATE_IP_PERIL, 0, 0, 0, "uart"), + GATE_DA(uart1, "exynos4210-uart.1", "uart1", "aclk100", + GATE_IP_PERIL, 1, 0, 0, "uart"), + GATE_DA(uart2, "exynos4210-uart.2", "uart2", "aclk100", + GATE_IP_PERIL, 2, 0, 0, "uart"), + GATE_DA(uart3, "exynos4210-uart.3", "uart3", "aclk100", + GATE_IP_PERIL, 3, 0, 0, "uart"), + GATE_DA(uart4, "exynos4210-uart.4", "uart4", "aclk100", + GATE_IP_PERIL, 4, 0, 0, "uart"), + GATE_DA(i2c0, "s3c2440-i2c.0", "i2c0", "aclk100", + GATE_IP_PERIL, 6, 0, 0, "i2c"), + GATE_DA(i2c1, "s3c2440-i2c.1", "i2c1", "aclk100", + GATE_IP_PERIL, 7, 0, 0, "i2c"), + GATE_DA(i2c2, "s3c2440-i2c.2", "i2c2", "aclk100", + GATE_IP_PERIL, 8, 0, 0, "i2c"), + GATE_DA(i2c3, "s3c2440-i2c.3", "i2c3", "aclk100", + GATE_IP_PERIL, 9, 0, 0, "i2c"), + GATE_DA(i2c4, "s3c2440-i2c.4", "i2c4", "aclk100", + GATE_IP_PERIL, 10, 0, 0, "i2c"), + GATE_DA(i2c5, "s3c2440-i2c.5", "i2c5", "aclk100", + GATE_IP_PERIL, 11, 0, 0, "i2c"), + GATE_DA(i2c6, "s3c2440-i2c.6", "i2c6", "aclk100", + GATE_IP_PERIL, 12, 0, 0, "i2c"), + GATE_DA(i2c7, "s3c2440-i2c.7", "i2c7", "aclk100", + GATE_IP_PERIL, 13, 0, 0, "i2c"), + GATE_DA(i2c_hdmi, "s3c2440-hdmiphy-i2c", "i2c-hdmi", "aclk100", + GATE_IP_PERIL, 14, 0, 0, "i2c"), + GATE_DA(spi0, "exynos4210-spi.0", "spi0", "aclk100", + GATE_IP_PERIL, 16, 0, 0, "spi"), + GATE_DA(spi1, "exynos4210-spi.1", "spi1", "aclk100", + GATE_IP_PERIL, 17, 0, 0, "spi"), + GATE_DA(spi2, "exynos4210-spi.2", "spi2", "aclk100", + GATE_IP_PERIL, 18, 0, 0, "spi"), + GATE_DA(i2s1, "samsung-i2s.1", "i2s1", "aclk100", + GATE_IP_PERIL, 20, 0, 0, "iis"), + GATE_DA(i2s2, "samsung-i2s.2", "i2s2", "aclk100", + GATE_IP_PERIL, 21, 0, 0, "iis"), + GATE_DA(pcm1, "samsung-pcm.1", "pcm1", "aclk100", + GATE_IP_PERIL, 22, 0, 0, "pcm"), + GATE_DA(pcm2, "samsung-pcm.2", "pcm2", "aclk100", + GATE_IP_PERIL, 23, 0, 0, "pcm"), + GATE_DA(spdif, "samsung-spdif", "spdif", "aclk100", + GATE_IP_PERIL, 26, 0, 0, "spdif"), + GATE_DA(ac97, "samsung-ac97", "ac97", "aclk100", + GATE_IP_PERIL, 27, 0, 0, "ac97"), +}; + +/* list of gate clocks supported in exynos4210 soc */ +struct samsung_gate_clock exynos4210_gate_clks[] __initdata = { + GATE(tvenc, "tvenc", "aclk160", GATE_IP_TV, 2, 0, 0), + GATE(g2d, "g2d", "aclk200", E4210_GATE_IP_IMAGE, 0, 0, 0), + GATE(rotator, "rotator", "aclk200", E4210_GATE_IP_IMAGE, 1, 0, 0), + GATE(mdma, "mdma", "aclk200", E4210_GATE_IP_IMAGE, 2, 0, 0), + GATE(smmu_g2d, "smmu_g2d", "aclk200", E4210_GATE_IP_IMAGE, 3, 0, 0), + GATE(smmu_mdma, "smmu_mdma", "aclk200", E4210_GATE_IP_IMAGE, 5, 0, 0), + GATE(pcie_phy, "pcie_phy", "aclk133", GATE_IP_FSYS, 2, 0, 0), + GATE(sata_phy, "sata_phy", "aclk133", GATE_IP_FSYS, 3, 0, 0), + GATE(sata, "sata", "aclk133", GATE_IP_FSYS, 10, 0, 0), + GATE(pcie, "pcie", "aclk133", GATE_IP_FSYS, 14, 0, 0), + GATE(smmu_pcie, "smmu_pcie", "aclk133", GATE_IP_FSYS, 18, 0, 0), + GATE(modemif, "modemif", "aclk100", GATE_IP_PERIL, 28, 0, 0), + GATE(chipid, "chipid", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0), + GATE(sysreg, "sysreg", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0), + GATE(hdmi_cec, "hdmi_cec", "aclk100", E4210_GATE_IP_PERIR, 11, 0, 0), + GATE(smmu_rotator, "smmu_rotator", "aclk200", + E4210_GATE_IP_IMAGE, 4, 0, 0), + GATE(sclk_mipi1, "sclk_mipi1", "div_mipi_pre1", + E4210_SRC_MASK_LCD1, 12, CLK_SET_RATE_PARENT, 0), + GATE(sclk_sata, "sclk_sata", "div_sata", + SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0), + GATE(sclk_mixer, "sclk_mixer", "mout_mixer", SRC_MASK_TV, 4, 0, 0), + GATE(sclk_dac, "sclk_dac", "mout_dac", SRC_MASK_TV, 8, 0, 0), + GATE_A(tsadc, "tsadc", "aclk100", GATE_IP_PERIL, 15, 0, 0, "adc"), + GATE_A(mct, "mct", "aclk100", E4210_GATE_IP_PERIR, 13, 0, 0, "mct"), + GATE_A(wdt, "watchdog", "aclk100", E4210_GATE_IP_PERIR, 14, 0, 0, "watchdog"), + GATE_A(rtc, "rtc", "aclk100", E4210_GATE_IP_PERIR, 15, 0, 0, "rtc"), + GATE_A(keyif, "keyif", "aclk100", E4210_GATE_IP_PERIR, 16, 0, 0, "keypad"), + GATE_DA(sclk_fimd1, "exynos4-fb.1", "sclk_fimd1", "div_fimd1", + E4210_SRC_MASK_LCD1, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimd"), +}; + +/* list of gate clocks supported in exynos4x12 soc */ +struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = { + GATE(audss, "audss", "sclk_epll", E4X12_GATE_IP_MAUDIO, 0, 0, 0), + GATE(mdnie0, "mdnie0", "aclk160", GATE_IP_LCD0, 2, 0, 0), + GATE(rotator, "rotator", "aclk200", E4X12_GATE_IP_IMAGE, 1, 0, 0), + GATE(mdma2, "mdma2", "aclk200", E4X12_GATE_IP_IMAGE, 2, 0, 0), + GATE(smmu_mdma, "smmu_mdma", "aclk200", E4X12_GATE_IP_IMAGE, 5, 0, 0), + GATE(mipi_hsi, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0), + GATE(chipid, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0), + GATE(sysreg, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1, 0, 0), + GATE(hdmi_cec, "hdmi_cec", "aclk100", E4X12_GATE_IP_PERIR, 11, 0, 0), + GATE(sclk_mdnie0, "sclk_mdnie0", "div_mdnie0", + SRC_MASK_LCD0, 4, CLK_SET_RATE_PARENT, 0), + GATE(sclk_mdnie_pwm0, "sclk_mdnie_pwm0", "div_mdnie_pwm_pre0", + SRC_MASK_LCD0, 8, CLK_SET_RATE_PARENT, 0), + GATE(sclk_mipihsi, "sclk_mipihsi", "div_mipihsi", + SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0), + GATE(smmu_rotator, "smmu_rotator", "aclk200", + E4X12_GATE_IP_IMAGE, 4, 0, 0), + GATE_A(mct, "mct", "aclk100", E4X12_GATE_IP_PERIR, 13, 0, 0, "mct"), + GATE_A(rtc, "rtc", "aclk100", E4X12_GATE_IP_PERIR, 15, 0, 0, "rtc"), + GATE_A(keyif, "keyif", "aclk100", + E4X12_GATE_IP_PERIR, 16, 0, 0, "keypad"), + GATE(sclk_pwm_isp, "sclk_pwm_isp", "div_pwm_isp", + E4X12_SRC_MASK_ISP, 0, CLK_SET_RATE_PARENT, 0), + GATE(sclk_spi0_isp, "sclk_spi0_isp", "div_spi0_isp_pre", + E4X12_SRC_MASK_ISP, 4, CLK_SET_RATE_PARENT, 0), + GATE(sclk_spi1_isp, "sclk_spi1_isp", "div_spi1_isp_pre", + E4X12_SRC_MASK_ISP, 8, CLK_SET_RATE_PARENT, 0), + GATE(sclk_uart_isp, "sclk_uart_isp", "div_uart_isp", + E4X12_SRC_MASK_ISP, 12, CLK_SET_RATE_PARENT, 0), + GATE(pwm_isp_sclk, "pwm_isp_sclk", "sclk_pwm_isp", + E4X12_GATE_IP_ISP, 0, 0, 0), + GATE(spi0_isp_sclk, "spi0_isp_sclk", "sclk_spi0_isp", + E4X12_GATE_IP_ISP, 1, 0, 0), + GATE(spi1_isp_sclk, "spi1_isp_sclk", "sclk_spi1_isp", + E4X12_GATE_IP_ISP, 2, 0, 0), + GATE(uart_isp_sclk, "uart_isp_sclk", "sclk_uart_isp", + E4X12_GATE_IP_ISP, 3, 0, 0), + GATE_A(wdt, "watchdog", "aclk100", + E4X12_GATE_IP_PERIR, 14, 0, 0, "watchdog"), + GATE_DA(pcm0, "samsung-pcm.0", "pcm0", "aclk100", + E4X12_GATE_IP_MAUDIO, 2, 0, 0, "pcm"), + GATE_DA(i2s0, "samsung-i2s.0", "i2s0", "aclk100", + E4X12_GATE_IP_MAUDIO, 3, 0, 0, "iis"), + GATE(fimc_isp, "isp", "aclk200", E4X12_GATE_ISP0, 0, + CLK_IGNORE_UNUSED, 0), + GATE(fimc_drc, "drc", "aclk200", E4X12_GATE_ISP0, 1, + CLK_IGNORE_UNUSED, 0), + GATE(fimc_fd, "fd", "aclk200", E4X12_GATE_ISP0, 2, + CLK_IGNORE_UNUSED, 0), + GATE(fimc_lite0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, + CLK_IGNORE_UNUSED, 0), + GATE(fimc_lite1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, + CLK_IGNORE_UNUSED, 0), + GATE(mcuisp, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, + CLK_IGNORE_UNUSED, 0), + GATE(gicisp, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, + CLK_IGNORE_UNUSED, 0), + GATE(smmu_isp, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, + CLK_IGNORE_UNUSED, 0), + GATE(smmu_drc, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, + CLK_IGNORE_UNUSED, 0), + GATE(smmu_fd, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, + CLK_IGNORE_UNUSED, 0), + GATE(smmu_lite0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11, + CLK_IGNORE_UNUSED, 0), + GATE(smmu_lite1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12, + CLK_IGNORE_UNUSED, 0), + GATE(ppmuispmx, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20, + CLK_IGNORE_UNUSED, 0), + GATE(ppmuispx, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21, + CLK_IGNORE_UNUSED, 0), + GATE(mcuctl_isp, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23, + CLK_IGNORE_UNUSED, 0), + GATE(mpwm_isp, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24, + CLK_IGNORE_UNUSED, 0), + GATE(i2c0_isp, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25, + CLK_IGNORE_UNUSED, 0), + GATE(i2c1_isp, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26, + CLK_IGNORE_UNUSED, 0), + GATE(mtcadc_isp, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27, + CLK_IGNORE_UNUSED, 0), + GATE(pwm_isp, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, + CLK_IGNORE_UNUSED, 0), + GATE(wdt_isp, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, + CLK_IGNORE_UNUSED, 0), + GATE(uart_isp, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31, + CLK_IGNORE_UNUSED, 0), + GATE(asyncaxim, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0, + CLK_IGNORE_UNUSED, 0), + GATE(smmu_ispcx, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4, + CLK_IGNORE_UNUSED, 0), + GATE(spi0_isp, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12, + CLK_IGNORE_UNUSED, 0), + GATE(spi1_isp, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, + CLK_IGNORE_UNUSED, 0), +}; + +#ifdef CONFIG_OF +static struct of_device_id exynos4_clk_ids[] __initdata = { + { .compatible = "samsung,exynos4210-clock", + .data = (void *)EXYNOS4210, }, + { .compatible = "samsung,exynos4412-clock", + .data = (void *)EXYNOS4X12, }, + { }, +}; +#endif + +/* + * The parent of the fin_pll clock is selected by the XOM[0] bit. This bit + * resides in chipid register space, outside of the clock controller memory + * mapped space. So to determine the parent of fin_pll clock, the chipid + * controller is first remapped and the value of XOM[0] bit is read to + * determine the parent clock. + */ +static void __init exynos4_clk_register_finpll(void) +{ + struct samsung_fixed_rate_clock fclk; + struct device_node *np; + struct clk *clk; + void __iomem *chipid_base = S5P_VA_CHIPID; + unsigned long xom, finpll_f = 24000000; + char *parent_name; + + np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-chipid"); + if (np) + chipid_base = of_iomap(np, 0); + + if (chipid_base) { + xom = readl(chipid_base + 8); + parent_name = xom & 1 ? "xusbxti" : "xxti"; + clk = clk_get(NULL, parent_name); + if (IS_ERR(clk)) { + pr_err("%s: failed to lookup parent clock %s, assuming " + "fin_pll clock frequency is 24MHz\n", __func__, + parent_name); + } else { + finpll_f = clk_get_rate(clk); + } + } else { + pr_err("%s: failed to map chipid registers, assuming " + "fin_pll clock frequency is 24MHz\n", __func__); + } + + fclk.id = fin_pll; + fclk.name = "fin_pll"; + fclk.parent_name = NULL; + fclk.flags = CLK_IS_ROOT; + fclk.fixed_rate = finpll_f; + samsung_clk_register_fixed_rate(&fclk, 1); + + if (np) + iounmap(chipid_base); +} + +/* + * This function allows non-dt platforms to specify the clock speed of the + * xxti and xusbxti clocks. These clocks are then registered with the specified + * clock speed. + */ +void __init exynos4_clk_register_fixed_ext(unsigned long xxti_f, + unsigned long xusbxti_f) +{ + exynos4_fixed_rate_ext_clks[0].fixed_rate = xxti_f; + exynos4_fixed_rate_ext_clks[1].fixed_rate = xusbxti_f; + samsung_clk_register_fixed_rate(exynos4_fixed_rate_ext_clks, + ARRAY_SIZE(exynos4_fixed_rate_ext_clks)); +} + +static __initdata struct of_device_id ext_clk_match[] = { + { .compatible = "samsung,clock-xxti", .data = (void *)0, }, + { .compatible = "samsung,clock-xusbxti", .data = (void *)1, }, + {}, +}; + +/* register exynos4 clocks */ +void __init exynos4_clk_init(struct device_node *np) +{ + void __iomem *reg_base; + struct clk *apll, *mpll, *epll, *vpll; + u32 exynos4_soc; + + if (np) { + const struct of_device_id *match; + match = of_match_node(exynos4_clk_ids, np); + exynos4_soc = (u32)match->data; + + reg_base = of_iomap(np, 0); + if (!reg_base) + panic("%s: failed to map registers\n", __func__); + } else { + reg_base = S5P_VA_CMU; + if (soc_is_exynos4210()) + exynos4_soc = EXYNOS4210; + else if (soc_is_exynos4212() || soc_is_exynos4412()) + exynos4_soc = EXYNOS4X12; + else + panic("%s: unable to determine soc\n", __func__); + } + + if (exynos4_soc == EXYNOS4210) + samsung_clk_init(np, reg_base, nr_clks, + exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs), + exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save)); + else + samsung_clk_init(np, reg_base, nr_clks, + exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs), + exynos4x12_clk_save, ARRAY_SIZE(exynos4x12_clk_save)); + + if (np) + samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks, + ARRAY_SIZE(exynos4_fixed_rate_ext_clks), + ext_clk_match); + + exynos4_clk_register_finpll(); + + if (exynos4_soc == EXYNOS4210) { + apll = samsung_clk_register_pll45xx("fout_apll", "fin_pll", + reg_base + APLL_CON0, pll_4508); + mpll = samsung_clk_register_pll45xx("fout_mpll", "fin_pll", + reg_base + E4210_MPLL_CON0, pll_4508); + epll = samsung_clk_register_pll46xx("fout_epll", "fin_pll", + reg_base + EPLL_CON0, pll_4600); + vpll = samsung_clk_register_pll46xx("fout_vpll", "mout_vpllsrc", + reg_base + VPLL_CON0, pll_4650c); + } else { + apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll", + reg_base + APLL_CON0); + mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll", + reg_base + E4X12_MPLL_CON0); + epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll", + reg_base + EPLL_CON0); + vpll = samsung_clk_register_pll36xx("fout_vpll", "fin_pll", + reg_base + VPLL_CON0); + } + + samsung_clk_add_lookup(apll, fout_apll); + samsung_clk_add_lookup(mpll, fout_mpll); + samsung_clk_add_lookup(epll, fout_epll); + samsung_clk_add_lookup(vpll, fout_vpll); + + samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks, + ARRAY_SIZE(exynos4_fixed_rate_clks)); + samsung_clk_register_mux(exynos4_mux_clks, + ARRAY_SIZE(exynos4_mux_clks)); + samsung_clk_register_div(exynos4_div_clks, + ARRAY_SIZE(exynos4_div_clks)); + samsung_clk_register_gate(exynos4_gate_clks, + ARRAY_SIZE(exynos4_gate_clks)); + + if (exynos4_soc == EXYNOS4210) { + samsung_clk_register_fixed_rate(exynos4210_fixed_rate_clks, + ARRAY_SIZE(exynos4210_fixed_rate_clks)); + samsung_clk_register_mux(exynos4210_mux_clks, + ARRAY_SIZE(exynos4210_mux_clks)); + samsung_clk_register_div(exynos4210_div_clks, + ARRAY_SIZE(exynos4210_div_clks)); + samsung_clk_register_gate(exynos4210_gate_clks, + ARRAY_SIZE(exynos4210_gate_clks)); + } else { + samsung_clk_register_mux(exynos4x12_mux_clks, + ARRAY_SIZE(exynos4x12_mux_clks)); + samsung_clk_register_div(exynos4x12_div_clks, + ARRAY_SIZE(exynos4x12_div_clks)); + samsung_clk_register_gate(exynos4x12_gate_clks, + ARRAY_SIZE(exynos4x12_gate_clks)); + } + + pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n" + "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n", + exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", + _get_rate("sclk_apll"), _get_rate("sclk_mpll"), + _get_rate("sclk_epll"), _get_rate("sclk_vpll"), + _get_rate("arm_clk")); +} +CLK_OF_DECLARE(exynos4210_clk, "samsung,exynos4210-clock", exynos4_clk_init); +CLK_OF_DECLARE(exynos4412_clk, "samsung,exynos4412-clock", exynos4_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c new file mode 100644 index 000000000000..7290faa518d2 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -0,0 +1,523 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2013 Linaro Ltd. + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * 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. + * + * Common Clock Framework support for Exynos5250 SoC. +*/ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <plat/cpu.h> +#include "clk.h" +#include "clk-pll.h" + +#define SRC_CPU 0x200 +#define DIV_CPU0 0x500 +#define SRC_CORE1 0x4204 +#define SRC_TOP0 0x10210 +#define SRC_TOP2 0x10218 +#define SRC_GSCL 0x10220 +#define SRC_DISP1_0 0x1022c +#define SRC_MAU 0x10240 +#define SRC_FSYS 0x10244 +#define SRC_GEN 0x10248 +#define SRC_PERIC0 0x10250 +#define SRC_PERIC1 0x10254 +#define SRC_MASK_GSCL 0x10320 +#define SRC_MASK_DISP1_0 0x1032c +#define SRC_MASK_MAU 0x10334 +#define SRC_MASK_FSYS 0x10340 +#define SRC_MASK_GEN 0x10344 +#define SRC_MASK_PERIC0 0x10350 +#define SRC_MASK_PERIC1 0x10354 +#define DIV_TOP0 0x10510 +#define DIV_TOP1 0x10514 +#define DIV_GSCL 0x10520 +#define DIV_DISP1_0 0x1052c +#define DIV_GEN 0x1053c +#define DIV_MAU 0x10544 +#define DIV_FSYS0 0x10548 +#define DIV_FSYS1 0x1054c +#define DIV_FSYS2 0x10550 +#define DIV_PERIC0 0x10558 +#define DIV_PERIC1 0x1055c +#define DIV_PERIC2 0x10560 +#define DIV_PERIC3 0x10564 +#define DIV_PERIC4 0x10568 +#define DIV_PERIC5 0x1056c +#define GATE_IP_GSCL 0x10920 +#define GATE_IP_MFC 0x1092c +#define GATE_IP_GEN 0x10934 +#define GATE_IP_FSYS 0x10944 +#define GATE_IP_PERIC 0x10950 +#define GATE_IP_PERIS 0x10960 +#define SRC_CDREX 0x20200 +#define PLL_DIV2_SEL 0x20a24 +#define GATE_IP_DISP1 0x10928 + +/* + * Let each supported clock get a unique id. This id is used to lookup the clock + * for device tree based platforms. The clocks are categorized into three + * sections: core, sclk gate and bus interface gate clocks. + * + * When adding a new clock to this list, it is advised to choose a clock + * category and add it to the end of that category. That is because the the + * device tree source file is referring to these ids and any change in the + * sequence number of existing clocks will require corresponding change in the + * device tree files. This limitation would go away when pre-processor support + * for dtc would be available. + */ +enum exynos5250_clks { + none, + + /* core clocks */ + fin_pll, + + /* gate for special clocks (sclk) */ + sclk_cam_bayer = 128, sclk_cam0, sclk_cam1, sclk_gscl_wa, sclk_gscl_wb, + sclk_fimd1, sclk_mipi1, sclk_dp, sclk_hdmi, sclk_pixel, sclk_audio0, + sclk_mmc0, sclk_mmc1, sclk_mmc2, sclk_mmc3, sclk_sata, sclk_usb3, + sclk_jpeg, sclk_uart0, sclk_uart1, sclk_uart2, sclk_uart3, sclk_pwm, + sclk_audio1, sclk_audio2, sclk_spdif, sclk_spi0, sclk_spi1, sclk_spi2, + + /* gate clocks */ + gscl0 = 256, gscl1, gscl2, gscl3, gscl_wa, gscl_wb, smmu_gscl0, + smmu_gscl1, smmu_gscl2, smmu_gscl3, mfc, smmu_mfcl, smmu_mfcr, rotator, + jpeg, mdma1, smmu_rotator, smmu_jpeg, smmu_mdma1, pdma0, pdma1, sata, + usbotg, mipi_hsi, sdmmc0, sdmmc1, sdmmc2, sdmmc3, sromc, usb2, usb3, + sata_phyctrl, sata_phyi2c, uart0, uart1, uart2, uart3, uart4, i2c0, + i2c1, i2c2, i2c3, i2c4, i2c5, i2c6, i2c7, i2c_hdmi, adc, spi0, spi1, + spi2, i2s1, i2s2, pcm1, pcm2, pwm, spdif, ac97, hsi2c0, hsi2c1, hsi2c2, + hsi2c3, chipid, sysreg, pmu, cmu_top, cmu_core, cmu_mem, tzpc0, tzpc1, + tzpc2, tzpc3, tzpc4, tzpc5, tzpc6, tzpc7, tzpc8, tzpc9, hdmi_cec, mct, + wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi, + + nr_clks, +}; + +/* + * list of controller registers to be saved and restored during a + * suspend/resume cycle. + */ +static __initdata unsigned long exynos5250_clk_regs[] = { + SRC_CPU, + DIV_CPU0, + SRC_CORE1, + SRC_TOP0, + SRC_TOP2, + SRC_GSCL, + SRC_DISP1_0, + SRC_MAU, + SRC_FSYS, + SRC_GEN, + SRC_PERIC0, + SRC_PERIC1, + SRC_MASK_GSCL, + SRC_MASK_DISP1_0, + SRC_MASK_MAU, + SRC_MASK_FSYS, + SRC_MASK_GEN, + SRC_MASK_PERIC0, + SRC_MASK_PERIC1, + DIV_TOP0, + DIV_TOP1, + DIV_GSCL, + DIV_DISP1_0, + DIV_GEN, + DIV_MAU, + DIV_FSYS0, + DIV_FSYS1, + DIV_FSYS2, + DIV_PERIC0, + DIV_PERIC1, + DIV_PERIC2, + DIV_PERIC3, + DIV_PERIC4, + DIV_PERIC5, + GATE_IP_GSCL, + GATE_IP_MFC, + GATE_IP_GEN, + GATE_IP_FSYS, + GATE_IP_PERIC, + GATE_IP_PERIS, + SRC_CDREX, + PLL_DIV2_SEL, + GATE_IP_DISP1, +}; + +/* list of all parent clock list */ +PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; +PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", }; +PNAME(mout_mpll_fout_p) = { "fout_mplldiv2", "fout_mpll" }; +PNAME(mout_mpll_p) = { "fin_pll", "mout_mpll_fout" }; +PNAME(mout_bpll_fout_p) = { "fout_bplldiv2", "fout_bpll" }; +PNAME(mout_bpll_p) = { "fin_pll", "mout_bpll_fout" }; +PNAME(mout_vpllsrc_p) = { "fin_pll", "sclk_hdmi27m" }; +PNAME(mout_vpll_p) = { "mout_vpllsrc", "fout_vpll" }; +PNAME(mout_cpll_p) = { "fin_pll", "fout_cpll" }; +PNAME(mout_epll_p) = { "fin_pll", "fout_epll" }; +PNAME(mout_mpll_user_p) = { "fin_pll", "sclk_mpll" }; +PNAME(mout_bpll_user_p) = { "fin_pll", "sclk_bpll" }; +PNAME(mout_aclk166_p) = { "sclk_cpll", "sclk_mpll_user" }; +PNAME(mout_aclk200_p) = { "sclk_mpll_user", "sclk_bpll_user" }; +PNAME(mout_hdmi_p) = { "div_hdmi_pixel", "sclk_hdmiphy" }; +PNAME(mout_usb3_p) = { "sclk_mpll_user", "sclk_cpll" }; +PNAME(mout_group1_p) = { "fin_pll", "fin_pll", "sclk_hdmi27m", + "sclk_dptxphy", "sclk_uhostphy", "sclk_hdmiphy", + "sclk_mpll_user", "sclk_epll", "sclk_vpll", + "sclk_cpll" }; +PNAME(mout_audio0_p) = { "cdclk0", "fin_pll", "sclk_hdmi27m", "sclk_dptxphy", + "sclk_uhostphy", "sclk_hdmiphy", + "sclk_mpll_user", "sclk_epll", "sclk_vpll", + "sclk_cpll" }; +PNAME(mout_audio1_p) = { "cdclk1", "fin_pll", "sclk_hdmi27m", "sclk_dptxphy", + "sclk_uhostphy", "sclk_hdmiphy", + "sclk_mpll_user", "sclk_epll", "sclk_vpll", + "sclk_cpll" }; +PNAME(mout_audio2_p) = { "cdclk2", "fin_pll", "sclk_hdmi27m", "sclk_dptxphy", + "sclk_uhostphy", "sclk_hdmiphy", + "sclk_mpll_user", "sclk_epll", "sclk_vpll", + "sclk_cpll" }; +PNAME(mout_spdif_p) = { "sclk_audio0", "sclk_audio1", "sclk_audio2", + "spdif_extclk" }; + +/* fixed rate clocks generated outside the soc */ +struct samsung_fixed_rate_clock exynos5250_fixed_rate_ext_clks[] __initdata = { + FRATE(fin_pll, "fin_pll", NULL, CLK_IS_ROOT, 0), +}; + +/* fixed rate clocks generated inside the soc */ +struct samsung_fixed_rate_clock exynos5250_fixed_rate_clks[] __initdata = { + FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000), + FRATE(none, "sclk_hdmi27m", NULL, CLK_IS_ROOT, 27000000), + FRATE(none, "sclk_dptxphy", NULL, CLK_IS_ROOT, 24000000), + FRATE(none, "sclk_uhostphy", NULL, CLK_IS_ROOT, 48000000), +}; + +struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = { + FFACTOR(none, "fout_mplldiv2", "fout_mpll", 1, 2, 0), + FFACTOR(none, "fout_bplldiv2", "fout_bpll", 1, 2, 0), +}; + +struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { + MUX(none, "mout_apll", mout_apll_p, SRC_CPU, 0, 1), + MUX(none, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1), + MUX(none, "mout_mpll_fout", mout_mpll_fout_p, PLL_DIV2_SEL, 4, 1), + MUX(none, "sclk_mpll", mout_mpll_p, SRC_CORE1, 8, 1), + MUX(none, "mout_bpll_fout", mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1), + MUX(none, "sclk_bpll", mout_bpll_p, SRC_CDREX, 0, 1), + MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP2, 0, 1), + MUX(none, "sclk_vpll", mout_vpll_p, SRC_TOP2, 16, 1), + MUX(none, "sclk_epll", mout_epll_p, SRC_TOP2, 12, 1), + MUX(none, "sclk_cpll", mout_cpll_p, SRC_TOP2, 8, 1), + MUX(none, "sclk_mpll_user", mout_mpll_user_p, SRC_TOP2, 20, 1), + MUX(none, "sclk_bpll_user", mout_bpll_user_p, SRC_TOP2, 24, 1), + MUX(none, "mout_aclk166", mout_aclk166_p, SRC_TOP0, 8, 1), + MUX(none, "mout_aclk333", mout_aclk166_p, SRC_TOP0, 16, 1), + MUX(none, "mout_aclk200", mout_aclk200_p, SRC_TOP0, 12, 1), + MUX(none, "mout_cam_bayer", mout_group1_p, SRC_GSCL, 12, 4), + MUX(none, "mout_cam0", mout_group1_p, SRC_GSCL, 16, 4), + MUX(none, "mout_cam1", mout_group1_p, SRC_GSCL, 20, 4), + MUX(none, "mout_gscl_wa", mout_group1_p, SRC_GSCL, 24, 4), + MUX(none, "mout_gscl_wb", mout_group1_p, SRC_GSCL, 28, 4), + MUX(none, "mout_fimd1", mout_group1_p, SRC_DISP1_0, 0, 4), + MUX(none, "mout_mipi1", mout_group1_p, SRC_DISP1_0, 12, 4), + MUX(none, "mout_dp", mout_group1_p, SRC_DISP1_0, 16, 4), + MUX(none, "mout_hdmi", mout_hdmi_p, SRC_DISP1_0, 20, 1), + MUX(none, "mout_audio0", mout_audio0_p, SRC_MAU, 0, 4), + MUX(none, "mout_mmc0", mout_group1_p, SRC_FSYS, 0, 4), + MUX(none, "mout_mmc1", mout_group1_p, SRC_FSYS, 4, 4), + MUX(none, "mout_mmc2", mout_group1_p, SRC_FSYS, 8, 4), + MUX(none, "mout_mmc3", mout_group1_p, SRC_FSYS, 12, 4), + MUX(none, "mout_sata", mout_aclk200_p, SRC_FSYS, 24, 1), + MUX(none, "mout_usb3", mout_usb3_p, SRC_FSYS, 28, 1), + MUX(none, "mout_jpeg", mout_group1_p, SRC_GEN, 0, 4), + MUX(none, "mout_uart0", mout_group1_p, SRC_PERIC0, 0, 4), + MUX(none, "mout_uart1", mout_group1_p, SRC_PERIC0, 4, 4), + MUX(none, "mout_uart2", mout_group1_p, SRC_PERIC0, 8, 4), + MUX(none, "mout_uart3", mout_group1_p, SRC_PERIC0, 12, 4), + MUX(none, "mout_pwm", mout_group1_p, SRC_PERIC0, 24, 4), + MUX(none, "mout_audio1", mout_audio1_p, SRC_PERIC1, 0, 4), + MUX(none, "mout_audio2", mout_audio2_p, SRC_PERIC1, 4, 4), + MUX(none, "mout_spdif", mout_spdif_p, SRC_PERIC1, 8, 2), + MUX(none, "mout_spi0", mout_group1_p, SRC_PERIC1, 16, 4), + MUX(none, "mout_spi1", mout_group1_p, SRC_PERIC1, 20, 4), + MUX(none, "mout_spi2", mout_group1_p, SRC_PERIC1, 24, 4), +}; + +struct samsung_div_clock exynos5250_div_clks[] __initdata = { + DIV(none, "div_arm", "mout_cpu", DIV_CPU0, 0, 3), + DIV(none, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3), + DIV(none, "aclk66_pre", "sclk_mpll_user", DIV_TOP1, 24, 3), + DIV(none, "aclk66", "aclk66_pre", DIV_TOP0, 0, 3), + DIV(none, "aclk266", "sclk_mpll_user", DIV_TOP0, 16, 3), + DIV(none, "aclk166", "mout_aclk166", DIV_TOP0, 8, 3), + DIV(none, "aclk333", "mout_aclk333", DIV_TOP0, 20, 3), + DIV(none, "aclk200", "mout_aclk200", DIV_TOP0, 12, 3), + DIV(none, "div_cam_bayer", "mout_cam_bayer", DIV_GSCL, 12, 4), + DIV(none, "div_cam0", "mout_cam0", DIV_GSCL, 16, 4), + DIV(none, "div_cam1", "mout_cam1", DIV_GSCL, 20, 4), + DIV(none, "div_gscl_wa", "mout_gscl_wa", DIV_GSCL, 24, 4), + DIV(none, "div_gscl_wb", "mout_gscl_wb", DIV_GSCL, 28, 4), + DIV(none, "div_fimd1", "mout_fimd1", DIV_DISP1_0, 0, 4), + DIV(none, "div_mipi1", "mout_mipi1", DIV_DISP1_0, 16, 4), + DIV(none, "div_dp", "mout_dp", DIV_DISP1_0, 24, 4), + DIV(none, "div_jpeg", "mout_jpeg", DIV_GEN, 4, 4), + DIV(none, "div_audio0", "mout_audio0", DIV_MAU, 0, 4), + DIV(none, "div_pcm0", "sclk_audio0", DIV_MAU, 4, 8), + DIV(none, "div_sata", "mout_sata", DIV_FSYS0, 20, 4), + DIV(none, "div_usb3", "mout_usb3", DIV_FSYS0, 24, 4), + DIV(none, "div_mmc0", "mout_mmc0", DIV_FSYS1, 8, 8), + DIV(none, "div_mmc1", "mout_mmc1", DIV_FSYS1, 24, 8), + DIV(none, "div_mmc2", "mout_mmc2", DIV_FSYS2, 8, 8), + DIV(none, "div_mmc3", "mout_mmc3", DIV_FSYS2, 24, 8), + DIV(none, "div_uart0", "mout_uart0", DIV_PERIC0, 0, 4), + DIV(none, "div_uart1", "mout_uart1", DIV_PERIC0, 4, 4), + DIV(none, "div_uart2", "mout_uart2", DIV_PERIC0, 8, 4), + DIV(none, "div_uart3", "mout_uart3", DIV_PERIC0, 12, 4), + DIV(none, "div_spi0", "mout_spi0", DIV_PERIC1, 0, 4), + DIV(none, "div_spi1", "mout_spi1", DIV_PERIC1, 16, 4), + DIV(none, "div_spi2", "mout_spi2", DIV_PERIC2, 0, 4), + DIV(none, "div_pwm", "mout_pwm", DIV_PERIC3, 0, 4), + DIV(none, "div_audio1", "mout_audio1", DIV_PERIC4, 0, 4), + DIV(none, "div_pcm1", "sclk_audio1", DIV_PERIC4, 4, 8), + DIV(none, "div_audio2", "mout_audio2", DIV_PERIC4, 16, 4), + DIV(none, "div_pcm2", "sclk_audio2", DIV_PERIC4, 20, 8), + DIV(none, "div_i2s1", "sclk_audio1", DIV_PERIC5, 0, 6), + DIV(none, "div_i2s2", "sclk_audio2", DIV_PERIC5, 8, 6), + DIV(sclk_pixel, "div_hdmi_pixel", "sclk_vpll", DIV_DISP1_0, 28, 4), + DIV_A(none, "armclk", "div_arm", DIV_CPU0, 28, 3, "armclk"), + DIV_F(none, "div_mipi1_pre", "div_mipi1", + DIV_DISP1_0, 20, 4, CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_mmc_pre0", "div_mmc0", + DIV_FSYS1, 8, 8, CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_mmc_pre1", "div_mmc1", + DIV_FSYS1, 24, 8, CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_mmc_pre2", "div_mmc2", + DIV_FSYS2, 8, 8, CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_mmc_pre3", "div_mmc3", + DIV_FSYS2, 24, 8, CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_spi_pre0", "div_spi0", + DIV_PERIC1, 8, 8, CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_spi_pre1", "div_spi1", + DIV_PERIC1, 24, 8, CLK_SET_RATE_PARENT, 0), + DIV_F(none, "div_spi_pre2", "div_spi2", + DIV_PERIC2, 8, 8, CLK_SET_RATE_PARENT, 0), +}; + +struct samsung_gate_clock exynos5250_gate_clks[] __initdata = { + GATE(gscl0, "gscl0", "none", GATE_IP_GSCL, 0, 0, 0), + GATE(gscl1, "gscl1", "none", GATE_IP_GSCL, 1, 0, 0), + GATE(gscl2, "gscl2", "aclk266", GATE_IP_GSCL, 2, 0, 0), + GATE(gscl3, "gscl3", "aclk266", GATE_IP_GSCL, 3, 0, 0), + GATE(gscl_wa, "gscl_wa", "div_gscl_wa", GATE_IP_GSCL, 5, 0, 0), + GATE(gscl_wb, "gscl_wb", "div_gscl_wb", GATE_IP_GSCL, 6, 0, 0), + GATE(smmu_gscl0, "smmu_gscl0", "aclk266", GATE_IP_GSCL, 7, 0, 0), + GATE(smmu_gscl1, "smmu_gscl1", "aclk266", GATE_IP_GSCL, 8, 0, 0), + GATE(smmu_gscl2, "smmu_gscl2", "aclk266", GATE_IP_GSCL, 9, 0, 0), + GATE(smmu_gscl3, "smmu_gscl3", "aclk266", GATE_IP_GSCL, 10, 0, 0), + GATE(mfc, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0), + GATE(smmu_mfcl, "smmu_mfcl", "aclk333", GATE_IP_MFC, 1, 0, 0), + GATE(smmu_mfcr, "smmu_mfcr", "aclk333", GATE_IP_MFC, 2, 0, 0), + GATE(rotator, "rotator", "aclk266", GATE_IP_GEN, 1, 0, 0), + GATE(jpeg, "jpeg", "aclk166", GATE_IP_GEN, 2, 0, 0), + GATE(mdma1, "mdma1", "aclk266", GATE_IP_GEN, 4, 0, 0), + GATE(smmu_rotator, "smmu_rotator", "aclk266", GATE_IP_GEN, 6, 0, 0), + GATE(smmu_jpeg, "smmu_jpeg", "aclk166", GATE_IP_GEN, 7, 0, 0), + GATE(smmu_mdma1, "smmu_mdma1", "aclk266", GATE_IP_GEN, 9, 0, 0), + GATE(pdma0, "pdma0", "aclk200", GATE_IP_FSYS, 1, 0, 0), + GATE(pdma1, "pdma1", "aclk200", GATE_IP_FSYS, 2, 0, 0), + GATE(sata, "sata", "aclk200", GATE_IP_FSYS, 6, 0, 0), + GATE(usbotg, "usbotg", "aclk200", GATE_IP_FSYS, 7, 0, 0), + GATE(mipi_hsi, "mipi_hsi", "aclk200", GATE_IP_FSYS, 8, 0, 0), + GATE(sdmmc0, "sdmmc0", "aclk200", GATE_IP_FSYS, 12, 0, 0), + GATE(sdmmc1, "sdmmc1", "aclk200", GATE_IP_FSYS, 13, 0, 0), + GATE(sdmmc2, "sdmmc2", "aclk200", GATE_IP_FSYS, 14, 0, 0), + GATE(sdmmc3, "sdmmc3", "aclk200", GATE_IP_FSYS, 15, 0, 0), + GATE(sromc, "sromc", "aclk200", GATE_IP_FSYS, 17, 0, 0), + GATE(usb2, "usb2", "aclk200", GATE_IP_FSYS, 18, 0, 0), + GATE(usb3, "usb3", "aclk200", GATE_IP_FSYS, 19, 0, 0), + GATE(sata_phyctrl, "sata_phyctrl", "aclk200", GATE_IP_FSYS, 24, 0, 0), + GATE(sata_phyi2c, "sata_phyi2c", "aclk200", GATE_IP_FSYS, 25, 0, 0), + GATE(uart0, "uart0", "aclk66", GATE_IP_PERIC, 0, 0, 0), + GATE(uart1, "uart1", "aclk66", GATE_IP_PERIC, 1, 0, 0), + GATE(uart2, "uart2", "aclk66", GATE_IP_PERIC, 2, 0, 0), + GATE(uart3, "uart3", "aclk66", GATE_IP_PERIC, 3, 0, 0), + GATE(uart4, "uart4", "aclk66", GATE_IP_PERIC, 4, 0, 0), + GATE(i2c0, "i2c0", "aclk66", GATE_IP_PERIC, 6, 0, 0), + GATE(i2c1, "i2c1", "aclk66", GATE_IP_PERIC, 7, 0, 0), + GATE(i2c2, "i2c2", "aclk66", GATE_IP_PERIC, 8, 0, 0), + GATE(i2c3, "i2c3", "aclk66", GATE_IP_PERIC, 9, 0, 0), + GATE(i2c4, "i2c4", "aclk66", GATE_IP_PERIC, 10, 0, 0), + GATE(i2c5, "i2c5", "aclk66", GATE_IP_PERIC, 11, 0, 0), + GATE(i2c6, "i2c6", "aclk66", GATE_IP_PERIC, 12, 0, 0), + GATE(i2c7, "i2c7", "aclk66", GATE_IP_PERIC, 13, 0, 0), + GATE(i2c_hdmi, "i2c_hdmi", "aclk66", GATE_IP_PERIC, 14, 0, 0), + GATE(adc, "adc", "aclk66", GATE_IP_PERIC, 15, 0, 0), + GATE(spi0, "spi0", "aclk66", GATE_IP_PERIC, 16, 0, 0), + GATE(spi1, "spi1", "aclk66", GATE_IP_PERIC, 17, 0, 0), + GATE(spi2, "spi2", "aclk66", GATE_IP_PERIC, 18, 0, 0), + GATE(i2s1, "i2s1", "aclk66", GATE_IP_PERIC, 20, 0, 0), + GATE(i2s2, "i2s2", "aclk66", GATE_IP_PERIC, 21, 0, 0), + GATE(pcm1, "pcm1", "aclk66", GATE_IP_PERIC, 22, 0, 0), + GATE(pcm2, "pcm2", "aclk66", GATE_IP_PERIC, 23, 0, 0), + GATE(pwm, "pwm", "aclk66", GATE_IP_PERIC, 24, 0, 0), + GATE(spdif, "spdif", "aclk66", GATE_IP_PERIC, 26, 0, 0), + GATE(ac97, "ac97", "aclk66", GATE_IP_PERIC, 27, 0, 0), + GATE(hsi2c0, "hsi2c0", "aclk66", GATE_IP_PERIC, 28, 0, 0), + GATE(hsi2c1, "hsi2c1", "aclk66", GATE_IP_PERIC, 29, 0, 0), + GATE(hsi2c2, "hsi2c2", "aclk66", GATE_IP_PERIC, 30, 0, 0), + GATE(hsi2c3, "hsi2c3", "aclk66", GATE_IP_PERIC, 31, 0, 0), + GATE(chipid, "chipid", "aclk66", GATE_IP_PERIS, 0, 0, 0), + GATE(sysreg, "sysreg", "aclk66", GATE_IP_PERIS, 1, 0, 0), + GATE(pmu, "pmu", "aclk66", GATE_IP_PERIS, 2, 0, 0), + GATE(tzpc0, "tzpc0", "aclk66", GATE_IP_PERIS, 6, 0, 0), + GATE(tzpc1, "tzpc1", "aclk66", GATE_IP_PERIS, 7, 0, 0), + GATE(tzpc2, "tzpc2", "aclk66", GATE_IP_PERIS, 8, 0, 0), + GATE(tzpc3, "tzpc3", "aclk66", GATE_IP_PERIS, 9, 0, 0), + GATE(tzpc4, "tzpc4", "aclk66", GATE_IP_PERIS, 10, 0, 0), + GATE(tzpc5, "tzpc5", "aclk66", GATE_IP_PERIS, 11, 0, 0), + GATE(tzpc6, "tzpc6", "aclk66", GATE_IP_PERIS, 12, 0, 0), + GATE(tzpc7, "tzpc7", "aclk66", GATE_IP_PERIS, 13, 0, 0), + GATE(tzpc8, "tzpc8", "aclk66", GATE_IP_PERIS, 14, 0, 0), + GATE(tzpc9, "tzpc9", "aclk66", GATE_IP_PERIS, 15, 0, 0), + GATE(hdmi_cec, "hdmi_cec", "aclk66", GATE_IP_PERIS, 16, 0, 0), + GATE(mct, "mct", "aclk66", GATE_IP_PERIS, 18, 0, 0), + GATE(wdt, "wdt", "aclk66", GATE_IP_PERIS, 19, 0, 0), + GATE(rtc, "rtc", "aclk66", GATE_IP_PERIS, 20, 0, 0), + GATE(tmu, "tmu", "aclk66", GATE_IP_PERIS, 21, 0, 0), + GATE(cmu_top, "cmu_top", "aclk66", + GATE_IP_PERIS, 3, CLK_IGNORE_UNUSED, 0), + GATE(cmu_core, "cmu_core", "aclk66", + GATE_IP_PERIS, 4, CLK_IGNORE_UNUSED, 0), + GATE(cmu_mem, "cmu_mem", "aclk66", + GATE_IP_PERIS, 5, CLK_IGNORE_UNUSED, 0), + GATE(sclk_cam_bayer, "sclk_cam_bayer", "div_cam_bayer", + SRC_MASK_GSCL, 12, CLK_SET_RATE_PARENT, 0), + GATE(sclk_cam0, "sclk_cam0", "div_cam0", + SRC_MASK_GSCL, 16, CLK_SET_RATE_PARENT, 0), + GATE(sclk_cam1, "sclk_cam1", "div_cam1", + SRC_MASK_GSCL, 20, CLK_SET_RATE_PARENT, 0), + GATE(sclk_gscl_wa, "sclk_gscl_wa", "div_gscl_wa", + SRC_MASK_GSCL, 24, CLK_SET_RATE_PARENT, 0), + GATE(sclk_gscl_wb, "sclk_gscl_wb", "div_gscl_wb", + SRC_MASK_GSCL, 28, CLK_SET_RATE_PARENT, 0), + GATE(sclk_fimd1, "sclk_fimd1", "div_fimd1", + SRC_MASK_DISP1_0, 0, CLK_SET_RATE_PARENT, 0), + GATE(sclk_mipi1, "sclk_mipi1", "div_mipi1", + SRC_MASK_DISP1_0, 12, CLK_SET_RATE_PARENT, 0), + GATE(sclk_dp, "sclk_dp", "div_dp", + SRC_MASK_DISP1_0, 16, CLK_SET_RATE_PARENT, 0), + GATE(sclk_hdmi, "sclk_hdmi", "mout_hdmi", + SRC_MASK_DISP1_0, 20, 0, 0), + GATE(sclk_audio0, "sclk_audio0", "div_audio0", + SRC_MASK_MAU, 0, CLK_SET_RATE_PARENT, 0), + GATE(sclk_mmc0, "sclk_mmc0", "div_mmc0", + SRC_MASK_FSYS, 0, CLK_SET_RATE_PARENT, 0), + GATE(sclk_mmc1, "sclk_mmc1", "div_mmc1", + SRC_MASK_FSYS, 4, CLK_SET_RATE_PARENT, 0), + GATE(sclk_mmc2, "sclk_mmc2", "div_mmc2", + SRC_MASK_FSYS, 8, CLK_SET_RATE_PARENT, 0), + GATE(sclk_mmc3, "sclk_mmc3", "div_mmc3", + SRC_MASK_FSYS, 12, CLK_SET_RATE_PARENT, 0), + GATE(sclk_sata, "sclk_sata", "div_sata", + SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0), + GATE(sclk_usb3, "sclk_usb3", "div_usb3", + SRC_MASK_FSYS, 28, CLK_SET_RATE_PARENT, 0), + GATE(sclk_jpeg, "sclk_jpeg", "div_jpeg", + SRC_MASK_GEN, 0, CLK_SET_RATE_PARENT, 0), + GATE(sclk_uart0, "sclk_uart0", "div_uart0", + SRC_MASK_PERIC0, 0, CLK_SET_RATE_PARENT, 0), + GATE(sclk_uart1, "sclk_uart1", "div_uart1", + SRC_MASK_PERIC0, 4, CLK_SET_RATE_PARENT, 0), + GATE(sclk_uart2, "sclk_uart2", "div_uart2", + SRC_MASK_PERIC0, 8, CLK_SET_RATE_PARENT, 0), + GATE(sclk_uart3, "sclk_uart3", "div_uart3", + SRC_MASK_PERIC0, 12, CLK_SET_RATE_PARENT, 0), + GATE(sclk_pwm, "sclk_pwm", "div_pwm", + SRC_MASK_PERIC0, 24, CLK_SET_RATE_PARENT, 0), + GATE(sclk_audio1, "sclk_audio1", "div_audio1", + SRC_MASK_PERIC1, 0, CLK_SET_RATE_PARENT, 0), + GATE(sclk_audio2, "sclk_audio2", "div_audio2", + SRC_MASK_PERIC1, 4, CLK_SET_RATE_PARENT, 0), + GATE(sclk_spdif, "sclk_spdif", "mout_spdif", + SRC_MASK_PERIC1, 4, 0, 0), + GATE(sclk_spi0, "sclk_spi0", "div_spi_pre0", + SRC_MASK_PERIC1, 16, CLK_SET_RATE_PARENT, 0), + GATE(sclk_spi1, "sclk_spi1", "div_spi_pre1", + SRC_MASK_PERIC1, 20, CLK_SET_RATE_PARENT, 0), + GATE(sclk_spi2, "sclk_spi2", "div_spi_pre2", + SRC_MASK_PERIC1, 24, CLK_SET_RATE_PARENT, 0), + GATE(fimd1, "fimd1", "aclk200", GATE_IP_DISP1, 0, 0, 0), + GATE(mie1, "mie1", "aclk200", GATE_IP_DISP1, 1, 0, 0), + GATE(dsim0, "dsim0", "aclk200", GATE_IP_DISP1, 3, 0, 0), + GATE(dp, "dp", "aclk200", GATE_IP_DISP1, 4, 0, 0), + GATE(mixer, "mixer", "aclk200", GATE_IP_DISP1, 5, 0, 0), + GATE(hdmi, "hdmi", "aclk200", GATE_IP_DISP1, 6, 0, 0), +}; + +static __initdata struct of_device_id ext_clk_match[] = { + { .compatible = "samsung,clock-xxti", .data = (void *)0, }, + { }, +}; + +/* register exynox5250 clocks */ +void __init exynos5250_clk_init(struct device_node *np) +{ + void __iomem *reg_base; + struct clk *apll, *mpll, *epll, *vpll, *bpll, *gpll, *cpll; + + if (np) { + reg_base = of_iomap(np, 0); + if (!reg_base) + panic("%s: failed to map registers\n", __func__); + } else { + panic("%s: unable to determine soc\n", __func__); + } + + samsung_clk_init(np, reg_base, nr_clks, + exynos5250_clk_regs, ARRAY_SIZE(exynos5250_clk_regs), + NULL, 0); + samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks, + ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), + ext_clk_match); + + apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll", + reg_base + 0x100); + mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll", + reg_base + 0x4100); + bpll = samsung_clk_register_pll35xx("fout_bpll", "fin_pll", + reg_base + 0x20110); + gpll = samsung_clk_register_pll35xx("fout_gpll", "fin_pll", + reg_base + 0x10150); + cpll = samsung_clk_register_pll35xx("fout_cpll", "fin_pll", + reg_base + 0x10120); + epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll", + reg_base + 0x10130); + vpll = samsung_clk_register_pll36xx("fout_vpll", "mout_vpllsrc", + reg_base + 0x10140); + + samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks, + ARRAY_SIZE(exynos5250_fixed_rate_clks)); + samsung_clk_register_fixed_factor(exynos5250_fixed_factor_clks, + ARRAY_SIZE(exynos5250_fixed_factor_clks)); + samsung_clk_register_mux(exynos5250_mux_clks, + ARRAY_SIZE(exynos5250_mux_clks)); + samsung_clk_register_div(exynos5250_div_clks, + ARRAY_SIZE(exynos5250_div_clks)); + samsung_clk_register_gate(exynos5250_gate_clks, + ARRAY_SIZE(exynos5250_gate_clks)); + + pr_info("Exynos5250: clock setup completed, armclk=%ld\n", + _get_rate("armclk")); +} +CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c new file mode 100644 index 000000000000..a0a094c06f19 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5440.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * 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. + * + * Common Clock Framework support for Exynos5440 SoC. +*/ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <plat/cpu.h> +#include "clk.h" +#include "clk-pll.h" + +#define CLKEN_OV_VAL 0xf8 +#define CPU_CLK_STATUS 0xfc +#define MISC_DOUT1 0x558 + +/* + * Let each supported clock get a unique id. This id is used to lookup the clock + * for device tree based platforms. + */ +enum exynos5440_clks { + none, xtal, arm_clk, + + spi_baud = 16, pb0_250, pr0_250, pr1_250, b_250, b_125, b_200, sata, + usb, gmac0, cs250, pb0_250_o, pr0_250_o, pr1_250_o, b_250_o, b_125_o, + b_200_o, sata_o, usb_o, gmac0_o, cs250_o, + + nr_clks, +}; + +/* parent clock name list */ +PNAME(mout_armclk_p) = { "cplla", "cpllb" }; +PNAME(mout_spi_p) = { "div125", "div200" }; + +/* fixed rate clocks generated outside the soc */ +struct samsung_fixed_rate_clock exynos5440_fixed_rate_ext_clks[] __initdata = { + FRATE(none, "xtal", NULL, CLK_IS_ROOT, 0), +}; + +/* fixed rate clocks */ +struct samsung_fixed_rate_clock exynos5440_fixed_rate_clks[] __initdata = { + FRATE(none, "ppll", NULL, CLK_IS_ROOT, 1000000000), + FRATE(none, "usb_phy0", NULL, CLK_IS_ROOT, 60000000), + FRATE(none, "usb_phy1", NULL, CLK_IS_ROOT, 60000000), + FRATE(none, "usb_ohci12", NULL, CLK_IS_ROOT, 12000000), + FRATE(none, "usb_ohci48", NULL, CLK_IS_ROOT, 48000000), +}; + +/* fixed factor clocks */ +struct samsung_fixed_factor_clock exynos5440_fixed_factor_clks[] __initdata = { + FFACTOR(none, "div250", "ppll", 1, 4, 0), + FFACTOR(none, "div200", "ppll", 1, 5, 0), + FFACTOR(none, "div125", "div250", 1, 2, 0), +}; + +/* mux clocks */ +struct samsung_mux_clock exynos5440_mux_clks[] __initdata = { + MUX(none, "mout_spi", mout_spi_p, MISC_DOUT1, 5, 1), + MUX_A(arm_clk, "arm_clk", mout_armclk_p, + CPU_CLK_STATUS, 0, 1, "armclk"), +}; + +/* divider clocks */ +struct samsung_div_clock exynos5440_div_clks[] __initdata = { + DIV(spi_baud, "div_spi", "mout_spi", MISC_DOUT1, 3, 2), +}; + +/* gate clocks */ +struct samsung_gate_clock exynos5440_gate_clks[] __initdata = { + GATE(pb0_250, "pb0_250", "div250", CLKEN_OV_VAL, 3, 0, 0), + GATE(pr0_250, "pr0_250", "div250", CLKEN_OV_VAL, 4, 0, 0), + GATE(pr1_250, "pr1_250", "div250", CLKEN_OV_VAL, 5, 0, 0), + GATE(b_250, "b_250", "div250", CLKEN_OV_VAL, 9, 0, 0), + GATE(b_125, "b_125", "div125", CLKEN_OV_VAL, 10, 0, 0), + GATE(b_200, "b_200", "div200", CLKEN_OV_VAL, 11, 0, 0), + GATE(sata, "sata", "div200", CLKEN_OV_VAL, 12, 0, 0), + GATE(usb, "usb", "div200", CLKEN_OV_VAL, 13, 0, 0), + GATE(gmac0, "gmac0", "div200", CLKEN_OV_VAL, 14, 0, 0), + GATE(cs250, "cs250", "div250", CLKEN_OV_VAL, 19, 0, 0), + GATE(pb0_250_o, "pb0_250_o", "pb0_250", CLKEN_OV_VAL, 3, 0, 0), + GATE(pr0_250_o, "pr0_250_o", "pr0_250", CLKEN_OV_VAL, 4, 0, 0), + GATE(pr1_250_o, "pr1_250_o", "pr1_250", CLKEN_OV_VAL, 5, 0, 0), + GATE(b_250_o, "b_250_o", "b_250", CLKEN_OV_VAL, 9, 0, 0), + GATE(b_125_o, "b_125_o", "b_125", CLKEN_OV_VAL, 10, 0, 0), + GATE(b_200_o, "b_200_o", "b_200", CLKEN_OV_VAL, 11, 0, 0), + GATE(sata_o, "sata_o", "sata", CLKEN_OV_VAL, 12, 0, 0), + GATE(usb_o, "usb_o", "usb", CLKEN_OV_VAL, 13, 0, 0), + GATE(gmac0_o, "gmac0_o", "gmac", CLKEN_OV_VAL, 14, 0, 0), + GATE(cs250_o, "cs250_o", "cs250", CLKEN_OV_VAL, 19, 0, 0), +}; + +static __initdata struct of_device_id ext_clk_match[] = { + { .compatible = "samsung,clock-xtal", .data = (void *)0, }, + {}, +}; + +/* register exynos5440 clocks */ +void __init exynos5440_clk_init(struct device_node *np) +{ + void __iomem *reg_base; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: failed to map clock controller registers," + " aborting clock initialization\n", __func__); + return; + } + + samsung_clk_init(np, reg_base, nr_clks, NULL, 0, NULL, 0); + samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks, + ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match); + + samsung_clk_register_pll2550x("cplla", "xtal", reg_base + 0x1c, 0x10); + samsung_clk_register_pll2550x("cpllb", "xtal", reg_base + 0x20, 0x10); + + samsung_clk_register_fixed_rate(exynos5440_fixed_rate_clks, + ARRAY_SIZE(exynos5440_fixed_rate_clks)); + samsung_clk_register_fixed_factor(exynos5440_fixed_factor_clks, + ARRAY_SIZE(exynos5440_fixed_factor_clks)); + samsung_clk_register_mux(exynos5440_mux_clks, + ARRAY_SIZE(exynos5440_mux_clks)); + samsung_clk_register_div(exynos5440_div_clks, + ARRAY_SIZE(exynos5440_div_clks)); + samsung_clk_register_gate(exynos5440_gate_clks, + ARRAY_SIZE(exynos5440_gate_clks)); + + pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("armclk")); + pr_info("exynos5440 clock initialization complete\n"); +} +CLK_OF_DECLARE(exynos5440_clk, "samsung,exynos5440-clock", exynos5440_clk_init); diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c new file mode 100644 index 000000000000..89135f6be116 --- /dev/null +++ b/drivers/clk/samsung/clk-pll.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2013 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains the utility functions to register the pll clocks. +*/ + +#include <linux/errno.h> +#include "clk.h" +#include "clk-pll.h" + +/* + * PLL35xx Clock Type + */ + +#define PLL35XX_MDIV_MASK (0x3FF) +#define PLL35XX_PDIV_MASK (0x3F) +#define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_MDIV_SHIFT (16) +#define PLL35XX_PDIV_SHIFT (8) +#define PLL35XX_SDIV_SHIFT (0) + +struct samsung_clk_pll35xx { + struct clk_hw hw; + const void __iomem *con_reg; +}; + +#define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw) + +static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw); + u32 mdiv, pdiv, sdiv, pll_con; + u64 fvco = parent_rate; + + pll_con = __raw_readl(pll->con_reg); + mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK; + pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK; + sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned long)fvco; +} + +static const struct clk_ops samsung_pll35xx_clk_ops = { + .recalc_rate = samsung_pll35xx_recalc_rate, +}; + +struct clk * __init samsung_clk_register_pll35xx(const char *name, + const char *pname, const void __iomem *con_reg) +{ + struct samsung_clk_pll35xx *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) { + pr_err("%s: could not allocate pll clk %s\n", __func__, name); + return NULL; + } + + init.name = name; + init.ops = &samsung_pll35xx_clk_ops; + init.flags = CLK_GET_RATE_NOCACHE; + init.parent_names = &pname; + init.num_parents = 1; + + pll->hw.init = &init; + pll->con_reg = con_reg; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register pll clock %s\n", __func__, + name); + kfree(pll); + } + + if (clk_register_clkdev(clk, name, NULL)) + pr_err("%s: failed to register lookup for %s", __func__, name); + + return clk; +} + +/* + * PLL36xx Clock Type + */ + +#define PLL36XX_KDIV_MASK (0xFFFF) +#define PLL36XX_MDIV_MASK (0x1FF) +#define PLL36XX_PDIV_MASK (0x3F) +#define PLL36XX_SDIV_MASK (0x7) +#define PLL36XX_MDIV_SHIFT (16) +#define PLL36XX_PDIV_SHIFT (8) +#define PLL36XX_SDIV_SHIFT (0) + +struct samsung_clk_pll36xx { + struct clk_hw hw; + const void __iomem *con_reg; +}; + +#define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw) + +static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw); + u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1; + u64 fvco = parent_rate; + + pll_con0 = __raw_readl(pll->con_reg); + pll_con1 = __raw_readl(pll->con_reg + 4); + mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK; + pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK; + sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK; + kdiv = pll_con1 & PLL36XX_KDIV_MASK; + + fvco *= (mdiv << 16) + kdiv; + do_div(fvco, (pdiv << sdiv)); + fvco >>= 16; + + return (unsigned long)fvco; +} + +static const struct clk_ops samsung_pll36xx_clk_ops = { + .recalc_rate = samsung_pll36xx_recalc_rate, +}; + +struct clk * __init samsung_clk_register_pll36xx(const char *name, + const char *pname, const void __iomem *con_reg) +{ + struct samsung_clk_pll36xx *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) { + pr_err("%s: could not allocate pll clk %s\n", __func__, name); + return NULL; + } + + init.name = name; + init.ops = &samsung_pll36xx_clk_ops; + init.flags = CLK_GET_RATE_NOCACHE; + init.parent_names = &pname; + init.num_parents = 1; + + pll->hw.init = &init; + pll->con_reg = con_reg; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register pll clock %s\n", __func__, + name); + kfree(pll); + } + + if (clk_register_clkdev(clk, name, NULL)) + pr_err("%s: failed to register lookup for %s", __func__, name); + + return clk; +} + +/* + * PLL45xx Clock Type + */ + +#define PLL45XX_MDIV_MASK (0x3FF) +#define PLL45XX_PDIV_MASK (0x3F) +#define PLL45XX_SDIV_MASK (0x7) +#define PLL45XX_MDIV_SHIFT (16) +#define PLL45XX_PDIV_SHIFT (8) +#define PLL45XX_SDIV_SHIFT (0) + +struct samsung_clk_pll45xx { + struct clk_hw hw; + enum pll45xx_type type; + const void __iomem *con_reg; +}; + +#define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw) + +static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw); + u32 mdiv, pdiv, sdiv, pll_con; + u64 fvco = parent_rate; + + pll_con = __raw_readl(pll->con_reg); + mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK; + pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK; + sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK; + + if (pll->type == pll_4508) + sdiv = sdiv - 1; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned long)fvco; +} + +static const struct clk_ops samsung_pll45xx_clk_ops = { + .recalc_rate = samsung_pll45xx_recalc_rate, +}; + +struct clk * __init samsung_clk_register_pll45xx(const char *name, + const char *pname, const void __iomem *con_reg, + enum pll45xx_type type) +{ + struct samsung_clk_pll45xx *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) { + pr_err("%s: could not allocate pll clk %s\n", __func__, name); + return NULL; + } + + init.name = name; + init.ops = &samsung_pll45xx_clk_ops; + init.flags = CLK_GET_RATE_NOCACHE; + init.parent_names = &pname; + init.num_parents = 1; + + pll->hw.init = &init; + pll->con_reg = con_reg; + pll->type = type; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register pll clock %s\n", __func__, + name); + kfree(pll); + } + + if (clk_register_clkdev(clk, name, NULL)) + pr_err("%s: failed to register lookup for %s", __func__, name); + + return clk; +} + +/* + * PLL46xx Clock Type + */ + +#define PLL46XX_MDIV_MASK (0x1FF) +#define PLL46XX_PDIV_MASK (0x3F) +#define PLL46XX_SDIV_MASK (0x7) +#define PLL46XX_MDIV_SHIFT (16) +#define PLL46XX_PDIV_SHIFT (8) +#define PLL46XX_SDIV_SHIFT (0) + +#define PLL46XX_KDIV_MASK (0xFFFF) +#define PLL4650C_KDIV_MASK (0xFFF) +#define PLL46XX_KDIV_SHIFT (0) + +struct samsung_clk_pll46xx { + struct clk_hw hw; + enum pll46xx_type type; + const void __iomem *con_reg; +}; + +#define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw) + +static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw); + u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift; + u64 fvco = parent_rate; + + pll_con0 = __raw_readl(pll->con_reg); + pll_con1 = __raw_readl(pll->con_reg + 4); + mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK; + pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK; + sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK; + kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK : + pll_con1 & PLL46XX_KDIV_MASK; + + shift = pll->type == pll_4600 ? 16 : 10; + fvco *= (mdiv << shift) + kdiv; + do_div(fvco, (pdiv << sdiv)); + fvco >>= shift; + + return (unsigned long)fvco; +} + +static const struct clk_ops samsung_pll46xx_clk_ops = { + .recalc_rate = samsung_pll46xx_recalc_rate, +}; + +struct clk * __init samsung_clk_register_pll46xx(const char *name, + const char *pname, const void __iomem *con_reg, + enum pll46xx_type type) +{ + struct samsung_clk_pll46xx *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) { + pr_err("%s: could not allocate pll clk %s\n", __func__, name); + return NULL; + } + + init.name = name; + init.ops = &samsung_pll46xx_clk_ops; + init.flags = CLK_GET_RATE_NOCACHE; + init.parent_names = &pname; + init.num_parents = 1; + + pll->hw.init = &init; + pll->con_reg = con_reg; + pll->type = type; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register pll clock %s\n", __func__, + name); + kfree(pll); + } + + if (clk_register_clkdev(clk, name, NULL)) + pr_err("%s: failed to register lookup for %s", __func__, name); + + return clk; +} + +/* + * PLL2550x Clock Type + */ + +#define PLL2550X_R_MASK (0x1) +#define PLL2550X_P_MASK (0x3F) +#define PLL2550X_M_MASK (0x3FF) +#define PLL2550X_S_MASK (0x7) +#define PLL2550X_R_SHIFT (20) +#define PLL2550X_P_SHIFT (14) +#define PLL2550X_M_SHIFT (4) +#define PLL2550X_S_SHIFT (0) + +struct samsung_clk_pll2550x { + struct clk_hw hw; + const void __iomem *reg_base; + unsigned long offset; +}; + +#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw) + +static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw); + u32 r, p, m, s, pll_stat; + u64 fvco = parent_rate; + + pll_stat = __raw_readl(pll->reg_base + pll->offset * 3); + r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK; + if (!r) + return 0; + p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK; + m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK; + s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK; + + fvco *= m; + do_div(fvco, (p << s)); + + return (unsigned long)fvco; +} + +static const struct clk_ops samsung_pll2550x_clk_ops = { + .recalc_rate = samsung_pll2550x_recalc_rate, +}; + +struct clk * __init samsung_clk_register_pll2550x(const char *name, + const char *pname, const void __iomem *reg_base, + const unsigned long offset) +{ + struct samsung_clk_pll2550x *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) { + pr_err("%s: could not allocate pll clk %s\n", __func__, name); + return NULL; + } + + init.name = name; + init.ops = &samsung_pll2550x_clk_ops; + init.flags = CLK_GET_RATE_NOCACHE; + init.parent_names = &pname; + init.num_parents = 1; + + pll->hw.init = &init; + pll->reg_base = reg_base; + pll->offset = offset; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register pll clock %s\n", __func__, + name); + kfree(pll); + } + + if (clk_register_clkdev(clk, name, NULL)) + pr_err("%s: failed to register lookup for %s", __func__, name); + + return clk; +} diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h new file mode 100644 index 000000000000..f33786e9a78b --- /dev/null +++ b/drivers/clk/samsung/clk-pll.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2013 Linaro Ltd. + * + * 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. + * + * Common Clock Framework support for all PLL's in Samsung platforms +*/ + +#ifndef __SAMSUNG_CLK_PLL_H +#define __SAMSUNG_CLK_PLL_H + +enum pll45xx_type { + pll_4500, + pll_4502, + pll_4508 +}; + +enum pll46xx_type { + pll_4600, + pll_4650, + pll_4650c, +}; + +extern struct clk * __init samsung_clk_register_pll35xx(const char *name, + const char *pname, const void __iomem *con_reg); +extern struct clk * __init samsung_clk_register_pll36xx(const char *name, + const char *pname, const void __iomem *con_reg); +extern struct clk * __init samsung_clk_register_pll45xx(const char *name, + const char *pname, const void __iomem *con_reg, + enum pll45xx_type type); +extern struct clk * __init samsung_clk_register_pll46xx(const char *name, + const char *pname, const void __iomem *con_reg, + enum pll46xx_type type); +extern struct clk * __init samsung_clk_register_pll2550x(const char *name, + const char *pname, const void __iomem *reg_base, + const unsigned long offset); + +#endif /* __SAMSUNG_CLK_PLL_H */ diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c new file mode 100644 index 000000000000..cd3c40ab50f3 --- /dev/null +++ b/drivers/clk/samsung/clk.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2013 Linaro Ltd. + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file includes utility functions to register clocks to common + * clock framework for Samsung platforms. +*/ + +#include <linux/syscore_ops.h> +#include "clk.h" + +static DEFINE_SPINLOCK(lock); +static struct clk **clk_table; +static void __iomem *reg_base; +#ifdef CONFIG_OF +static struct clk_onecell_data clk_data; +#endif + +#ifdef CONFIG_PM_SLEEP +static struct samsung_clk_reg_dump *reg_dump; +static unsigned long nr_reg_dump; + +static int samsung_clk_suspend(void) +{ + struct samsung_clk_reg_dump *rd = reg_dump; + unsigned long i; + + for (i = 0; i < nr_reg_dump; i++, rd++) + rd->value = __raw_readl(reg_base + rd->offset); + + return 0; +} + +static void samsung_clk_resume(void) +{ + struct samsung_clk_reg_dump *rd = reg_dump; + unsigned long i; + + for (i = 0; i < nr_reg_dump; i++, rd++) + __raw_writel(rd->value, reg_base + rd->offset); +} + +static struct syscore_ops samsung_clk_syscore_ops = { + .suspend = samsung_clk_suspend, + .resume = samsung_clk_resume, +}; +#endif /* CONFIG_PM_SLEEP */ + +/* setup the essentials required to support clock lookup using ccf */ +void __init samsung_clk_init(struct device_node *np, void __iomem *base, + unsigned long nr_clks, unsigned long *rdump, + unsigned long nr_rdump, unsigned long *soc_rdump, + unsigned long nr_soc_rdump) +{ + reg_base = base; + +#ifdef CONFIG_PM_SLEEP + if (rdump && nr_rdump) { + unsigned int idx; + reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump) + * (nr_rdump + nr_soc_rdump), GFP_KERNEL); + if (!reg_dump) { + pr_err("%s: memory alloc for register dump failed\n", + __func__); + return; + } + + for (idx = 0; idx < nr_rdump; idx++) + reg_dump[idx].offset = rdump[idx]; + for (idx = 0; idx < nr_soc_rdump; idx++) + reg_dump[nr_rdump + idx].offset = soc_rdump[idx]; + nr_reg_dump = nr_rdump + nr_soc_rdump; + register_syscore_ops(&samsung_clk_syscore_ops); + } +#endif + + clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); + if (!clk_table) + panic("could not allocate clock lookup table\n"); + + if (!np) + return; + +#ifdef CONFIG_OF + clk_data.clks = clk_table; + clk_data.clk_num = nr_clks; + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +#endif +} + +/* add a clock instance to the clock lookup table used for dt based lookup */ +void samsung_clk_add_lookup(struct clk *clk, unsigned int id) +{ + if (clk_table && id) + clk_table[id] = clk; +} + +/* register a list of aliases */ +void __init samsung_clk_register_alias(struct samsung_clock_alias *list, + unsigned int nr_clk) +{ + struct clk *clk; + unsigned int idx, ret; + + if (!clk_table) { + pr_err("%s: clock table missing\n", __func__); + return; + } + + for (idx = 0; idx < nr_clk; idx++, list++) { + if (!list->id) { + pr_err("%s: clock id missing for index %d\n", __func__, + idx); + continue; + } + + clk = clk_table[list->id]; + if (!clk) { + pr_err("%s: failed to find clock %d\n", __func__, + list->id); + continue; + } + + ret = clk_register_clkdev(clk, list->alias, list->dev_name); + if (ret) + pr_err("%s: failed to register lookup %s\n", + __func__, list->alias); + } +} + +/* register a list of fixed clocks */ +void __init samsung_clk_register_fixed_rate( + struct samsung_fixed_rate_clock *list, unsigned int nr_clk) +{ + struct clk *clk; + unsigned int idx, ret; + + for (idx = 0; idx < nr_clk; idx++, list++) { + clk = clk_register_fixed_rate(NULL, list->name, + list->parent_name, list->flags, list->fixed_rate); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + list->name); + continue; + } + + samsung_clk_add_lookup(clk, list->id); + + /* + * Unconditionally add a clock lookup for the fixed rate clocks. + * There are not many of these on any of Samsung platforms. + */ + ret = clk_register_clkdev(clk, list->name, NULL); + if (ret) + pr_err("%s: failed to register clock lookup for %s", + __func__, list->name); + } +} + +/* register a list of fixed factor clocks */ +void __init samsung_clk_register_fixed_factor( + struct samsung_fixed_factor_clock *list, unsigned int nr_clk) +{ + struct clk *clk; + unsigned int idx; + + for (idx = 0; idx < nr_clk; idx++, list++) { + clk = clk_register_fixed_factor(NULL, list->name, + list->parent_name, list->flags, list->mult, list->div); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + list->name); + continue; + } + + samsung_clk_add_lookup(clk, list->id); + } +} + +/* register a list of mux clocks */ +void __init samsung_clk_register_mux(struct samsung_mux_clock *list, + unsigned int nr_clk) +{ + struct clk *clk; + unsigned int idx, ret; + + for (idx = 0; idx < nr_clk; idx++, list++) { + clk = clk_register_mux(NULL, list->name, list->parent_names, + list->num_parents, list->flags, reg_base + list->offset, + list->shift, list->width, list->mux_flags, &lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + list->name); + continue; + } + + samsung_clk_add_lookup(clk, list->id); + + /* register a clock lookup only if a clock alias is specified */ + if (list->alias) { + ret = clk_register_clkdev(clk, list->alias, + list->dev_name); + if (ret) + pr_err("%s: failed to register lookup %s\n", + __func__, list->alias); + } + } +} + +/* register a list of div clocks */ +void __init samsung_clk_register_div(struct samsung_div_clock *list, + unsigned int nr_clk) +{ + struct clk *clk; + unsigned int idx, ret; + + for (idx = 0; idx < nr_clk; idx++, list++) { + if (list->table) + clk = clk_register_divider_table(NULL, list->name, + list->parent_name, list->flags, + reg_base + list->offset, list->shift, + list->width, list->div_flags, + list->table, &lock); + else + clk = clk_register_divider(NULL, list->name, + list->parent_name, list->flags, + reg_base + list->offset, list->shift, + list->width, list->div_flags, &lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + list->name); + continue; + } + + samsung_clk_add_lookup(clk, list->id); + + /* register a clock lookup only if a clock alias is specified */ + if (list->alias) { + ret = clk_register_clkdev(clk, list->alias, + list->dev_name); + if (ret) + pr_err("%s: failed to register lookup %s\n", + __func__, list->alias); + } + } +} + +/* register a list of gate clocks */ +void __init samsung_clk_register_gate(struct samsung_gate_clock *list, + unsigned int nr_clk) +{ + struct clk *clk; + unsigned int idx, ret; + + for (idx = 0; idx < nr_clk; idx++, list++) { + clk = clk_register_gate(NULL, list->name, list->parent_name, + list->flags, reg_base + list->offset, + list->bit_idx, list->gate_flags, &lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + list->name); + continue; + } + + /* register a clock lookup only if a clock alias is specified */ + if (list->alias) { + ret = clk_register_clkdev(clk, list->alias, + list->dev_name); + if (ret) + pr_err("%s: failed to register lookup %s\n", + __func__, list->alias); + } + + samsung_clk_add_lookup(clk, list->id); + } +} + +/* + * obtain the clock speed of all external fixed clock sources from device + * tree and register it + */ +#ifdef CONFIG_OF +void __init samsung_clk_of_register_fixed_ext( + struct samsung_fixed_rate_clock *fixed_rate_clk, + unsigned int nr_fixed_rate_clk, + struct of_device_id *clk_matches) +{ + const struct of_device_id *match; + struct device_node *np; + u32 freq; + + for_each_matching_node_and_match(np, clk_matches, &match) { + if (of_property_read_u32(np, "clock-frequency", &freq)) + continue; + fixed_rate_clk[(u32)match->data].fixed_rate = freq; + } + samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk); +} +#endif + +/* utility function to get the rate of a specified clock */ +unsigned long _get_rate(const char *clk_name) +{ + struct clk *clk; + unsigned long rate; + + clk = clk_get(NULL, clk_name); + if (IS_ERR(clk)) { + pr_err("%s: could not find clock %s\n", __func__, clk_name); + return 0; + } + rate = clk_get_rate(clk); + clk_put(clk); + return rate; +} diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h new file mode 100644 index 000000000000..10b2111f0c0f --- /dev/null +++ b/drivers/clk/samsung/clk.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2013 Linaro Ltd. + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * 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. + * + * Common Clock Framework support for all Samsung platforms +*/ + +#ifndef __SAMSUNG_CLK_H +#define __SAMSUNG_CLK_H + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <mach/map.h> + +/** + * struct samsung_clock_alias: information about mux clock + * @id: platform specific id of the clock. + * @dev_name: name of the device to which this clock belongs. + * @alias: optional clock alias name to be assigned to this clock. + */ +struct samsung_clock_alias { + unsigned int id; + const char *dev_name; + const char *alias; +}; + +#define ALIAS(_id, dname, a) \ + { \ + .id = _id, \ + .dev_name = dname, \ + .alias = a, \ + } + +/** + * struct samsung_fixed_rate_clock: information about fixed-rate clock + * @id: platform specific id of the clock. + * @name: name of this fixed-rate clock. + * @parent_name: optional parent clock name. + * @flags: optional fixed-rate clock flags. + * @fixed-rate: fixed clock rate of this clock. + */ +struct samsung_fixed_rate_clock { + unsigned int id; + char *name; + const char *parent_name; + unsigned long flags; + unsigned long fixed_rate; +}; + +#define FRATE(_id, cname, pname, f, frate) \ + { \ + .id = _id, \ + .name = cname, \ + .parent_name = pname, \ + .flags = f, \ + .fixed_rate = frate, \ + } + +/* + * struct samsung_fixed_factor_clock: information about fixed-factor clock + * @id: platform specific id of the clock. + * @name: name of this fixed-factor clock. + * @parent_name: parent clock name. + * @mult: fixed multiplication factor. + * @div: fixed division factor. + * @flags: optional fixed-factor clock flags. + */ +struct samsung_fixed_factor_clock { + unsigned int id; + char *name; + const char *parent_name; + unsigned long mult; + unsigned long div; + unsigned long flags; +}; + +#define FFACTOR(_id, cname, pname, m, d, f) \ + { \ + .id = _id, \ + .name = cname, \ + .parent_name = pname, \ + .mult = m, \ + .div = d, \ + .flags = f, \ + } + +/** + * struct samsung_mux_clock: information about mux clock + * @id: platform specific id of the clock. + * @dev_name: name of the device to which this clock belongs. + * @name: name of this mux clock. + * @parent_names: array of pointer to parent clock names. + * @num_parents: number of parents listed in @parent_names. + * @flags: optional flags for basic clock. + * @offset: offset of the register for configuring the mux. + * @shift: starting bit location of the mux control bit-field in @reg. + * @width: width of the mux control bit-field in @reg. + * @mux_flags: flags for mux-type clock. + * @alias: optional clock alias name to be assigned to this clock. + */ +struct samsung_mux_clock { + unsigned int id; + const char *dev_name; + const char *name; + const char **parent_names; + u8 num_parents; + unsigned long flags; + unsigned long offset; + u8 shift; + u8 width; + u8 mux_flags; + const char *alias; +}; + +#define __MUX(_id, dname, cname, pnames, o, s, w, f, mf, a) \ + { \ + .id = _id, \ + .dev_name = dname, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .offset = o, \ + .shift = s, \ + .width = w, \ + .mux_flags = mf, \ + .alias = a, \ + } + +#define MUX(_id, cname, pnames, o, s, w) \ + __MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, NULL) + +#define MUX_A(_id, cname, pnames, o, s, w, a) \ + __MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, a) + +#define MUX_F(_id, cname, pnames, o, s, w, f, mf) \ + __MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL) + +/** + * @id: platform specific id of the clock. + * struct samsung_div_clock: information about div clock + * @dev_name: name of the device to which this clock belongs. + * @name: name of this div clock. + * @parent_name: name of the parent clock. + * @flags: optional flags for basic clock. + * @offset: offset of the register for configuring the div. + * @shift: starting bit location of the div control bit-field in @reg. + * @div_flags: flags for div-type clock. + * @alias: optional clock alias name to be assigned to this clock. + */ +struct samsung_div_clock { + unsigned int id; + const char *dev_name; + const char *name; + const char *parent_name; + unsigned long flags; + unsigned long offset; + u8 shift; + u8 width; + u8 div_flags; + const char *alias; + struct clk_div_table *table; +}; + +#define __DIV(_id, dname, cname, pname, o, s, w, f, df, a, t) \ + { \ + .id = _id, \ + .dev_name = dname, \ + .name = cname, \ + .parent_name = pname, \ + .flags = f, \ + .offset = o, \ + .shift = s, \ + .width = w, \ + .div_flags = df, \ + .alias = a, \ + .table = t, \ + } + +#define DIV(_id, cname, pname, o, s, w) \ + __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, NULL, NULL) + +#define DIV_A(_id, cname, pname, o, s, w, a) \ + __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, a, NULL) + +#define DIV_F(_id, cname, pname, o, s, w, f, df) \ + __DIV(_id, NULL, cname, pname, o, s, w, f, df, NULL, NULL) + +#define DIV_T(_id, cname, pname, o, s, w, t) \ + __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, NULL, t) + +/** + * struct samsung_gate_clock: information about gate clock + * @id: platform specific id of the clock. + * @dev_name: name of the device to which this clock belongs. + * @name: name of this gate clock. + * @parent_name: name of the parent clock. + * @flags: optional flags for basic clock. + * @offset: offset of the register for configuring the gate. + * @bit_idx: bit index of the gate control bit-field in @reg. + * @gate_flags: flags for gate-type clock. + * @alias: optional clock alias name to be assigned to this clock. + */ +struct samsung_gate_clock { + unsigned int id; + const char *dev_name; + const char *name; + const char *parent_name; + unsigned long flags; + unsigned long offset; + u8 bit_idx; + u8 gate_flags; + const char *alias; +}; + +#define __GATE(_id, dname, cname, pname, o, b, f, gf, a) \ + { \ + .id = _id, \ + .dev_name = dname, \ + .name = cname, \ + .parent_name = pname, \ + .flags = f, \ + .offset = o, \ + .bit_idx = b, \ + .gate_flags = gf, \ + .alias = a, \ + } + +#define GATE(_id, cname, pname, o, b, f, gf) \ + __GATE(_id, NULL, cname, pname, o, b, f, gf, NULL) + +#define GATE_A(_id, cname, pname, o, b, f, gf, a) \ + __GATE(_id, NULL, cname, pname, o, b, f, gf, a) + +#define GATE_D(_id, dname, cname, pname, o, b, f, gf) \ + __GATE(_id, dname, cname, pname, o, b, f, gf, NULL) + +#define GATE_DA(_id, dname, cname, pname, o, b, f, gf, a) \ + __GATE(_id, dname, cname, pname, o, b, f, gf, a) + +#define PNAME(x) static const char *x[] __initdata + +/** + * struct samsung_clk_reg_dump: register dump of clock controller registers. + * @offset: clock register offset from the controller base address. + * @value: the value to be register at offset. + */ +struct samsung_clk_reg_dump { + u32 offset; + u32 value; +}; + +extern void __init samsung_clk_init(struct device_node *np, void __iomem *base, + unsigned long nr_clks, unsigned long *rdump, + unsigned long nr_rdump, unsigned long *soc_rdump, + unsigned long nr_soc_rdump); +extern void __init samsung_clk_of_register_fixed_ext( + struct samsung_fixed_rate_clock *fixed_rate_clk, + unsigned int nr_fixed_rate_clk, + struct of_device_id *clk_matches); + +extern void samsung_clk_add_lookup(struct clk *clk, unsigned int id); + +extern void samsung_clk_register_alias(struct samsung_clock_alias *list, + unsigned int nr_clk); +extern void __init samsung_clk_register_fixed_rate( + struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk); +extern void __init samsung_clk_register_fixed_factor( + struct samsung_fixed_factor_clock *list, unsigned int nr_clk); +extern void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list, + unsigned int nr_clk); +extern void __init samsung_clk_register_div(struct samsung_div_clock *clk_list, + unsigned int nr_clk); +extern void __init samsung_clk_register_gate( + struct samsung_gate_clock *clk_list, unsigned int nr_clk); + +extern unsigned long _get_rate(const char *clk_name); + +#endif /* __SAMSUNG_CLK_H */ diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c index 82abea366b78..35e7e2698e10 100644 --- a/drivers/clk/spear/spear1340_clock.c +++ b/drivers/clk/spear/spear1340_clock.c @@ -960,47 +960,47 @@ void __init spear1340_clk_init(void) SPEAR1340_SPDIF_IN_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "d0100000.spdif-in"); - clk = clk_register_gate(NULL, "acp_clk", "acp_mclk", 0, + clk = clk_register_gate(NULL, "acp_clk", "ahb_clk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "acp_clk"); - clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0, + clk = clk_register_gate(NULL, "plgpio_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "e2800000.gpio"); - clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0, + clk = clk_register_gate(NULL, "video_dec_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "video_dec"); - clk = clk_register_gate(NULL, "video_enc_clk", "video_enc_mclk", 0, + clk = clk_register_gate(NULL, "video_enc_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_ENC_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "video_enc"); - clk = clk_register_gate(NULL, "video_in_clk", "video_in_mclk", 0, + clk = clk_register_gate(NULL, "video_in_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_IN_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "spear_vip"); - clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0, + clk = clk_register_gate(NULL, "cam0_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "d0200000.cam0"); - clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0, + clk = clk_register_gate(NULL, "cam1_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "d0300000.cam1"); - clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0, + clk = clk_register_gate(NULL, "cam2_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "d0400000.cam2"); - clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0, + clk = clk_register_gate(NULL, "cam3_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "d0500000.cam3"); diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile new file mode 100644 index 000000000000..b5bac917612c --- /dev/null +++ b/drivers/clk/sunxi/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for sunxi specific clk +# + +obj-y += clk-sunxi.o clk-factors.o diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c new file mode 100644 index 000000000000..88523f91d9b7 --- /dev/null +++ b/drivers/clk/sunxi/clk-factors.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2013 Emilio López <emilio@elopez.com.ar> + * + * 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. + * + * Adjustable factor-based clock implementation + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h> + +#include <linux/delay.h> + +#include "clk-factors.h" + +/* + * DOC: basic adjustable factor-based clock that cannot gate + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is adjustable. + * clk->rate = (parent->rate * N * (K + 1) >> P) / (M + 1) + * parent - fixed parent. No clk_set_parent support + */ + +struct clk_factors { + struct clk_hw hw; + void __iomem *reg; + struct clk_factors_config *config; + void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p); + spinlock_t *lock; +}; + +#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) + +#define SETMASK(len, pos) (((-1U) >> (31-len)) << (pos)) +#define CLRMASK(len, pos) (~(SETMASK(len, pos))) +#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) + +#define FACTOR_SET(bit, len, reg, val) \ + (((reg) & CLRMASK(len, bit)) | (val << (bit))) + +static unsigned long clk_factors_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u8 n = 1, k = 0, p = 0, m = 0; + u32 reg; + unsigned long rate; + struct clk_factors *factors = to_clk_factors(hw); + struct clk_factors_config *config = factors->config; + + /* Fetch the register value */ + reg = readl(factors->reg); + + /* Get each individual factor if applicable */ + if (config->nwidth != SUNXI_FACTORS_NOT_APPLICABLE) + n = FACTOR_GET(config->nshift, config->nwidth, reg); + if (config->kwidth != SUNXI_FACTORS_NOT_APPLICABLE) + k = FACTOR_GET(config->kshift, config->kwidth, reg); + if (config->mwidth != SUNXI_FACTORS_NOT_APPLICABLE) + m = FACTOR_GET(config->mshift, config->mwidth, reg); + if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE) + p = FACTOR_GET(config->pshift, config->pwidth, reg); + + /* Calculate the rate */ + rate = (parent_rate * n * (k + 1) >> p) / (m + 1); + + return rate; +} + +static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_factors *factors = to_clk_factors(hw); + factors->get_factors((u32 *)&rate, (u32)*parent_rate, + NULL, NULL, NULL, NULL); + + return rate; +} + +static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + u8 n, k, m, p; + u32 reg; + struct clk_factors *factors = to_clk_factors(hw); + struct clk_factors_config *config = factors->config; + unsigned long flags = 0; + + factors->get_factors((u32 *)&rate, (u32)parent_rate, &n, &k, &m, &p); + + if (factors->lock) + spin_lock_irqsave(factors->lock, flags); + + /* Fetch the register value */ + reg = readl(factors->reg); + + /* Set up the new factors - macros do not do anything if width is 0 */ + reg = FACTOR_SET(config->nshift, config->nwidth, reg, n); + reg = FACTOR_SET(config->kshift, config->kwidth, reg, k); + reg = FACTOR_SET(config->mshift, config->mwidth, reg, m); + reg = FACTOR_SET(config->pshift, config->pwidth, reg, p); + + /* Apply them now */ + writel(reg, factors->reg); + + /* delay 500us so pll stabilizes */ + __delay((rate >> 20) * 500 / 2); + + if (factors->lock) + spin_unlock_irqrestore(factors->lock, flags); + + return 0; +} + +static const struct clk_ops clk_factors_ops = { + .recalc_rate = clk_factors_recalc_rate, + .round_rate = clk_factors_round_rate, + .set_rate = clk_factors_set_rate, +}; + +/** + * clk_register_factors - register a factors clock with + * the clock framework + * @dev: device registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @reg: register address to adjust factors + * @config: shift and width of factors n, k, m and p + * @get_factors: function to calculate the factors for a given frequency + * @lock: shared register lock for this clock + */ +struct clk *clk_register_factors(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, void __iomem *reg, + struct clk_factors_config *config, + void (*get_factors)(u32 *rate, u32 parent, + u8 *n, u8 *k, u8 *m, u8 *p), + spinlock_t *lock) +{ + struct clk_factors *factors; + struct clk *clk; + struct clk_init_data init; + + /* allocate the factors */ + factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); + if (!factors) { + pr_err("%s: could not allocate factors clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &clk_factors_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_factors assignments */ + factors->reg = reg; + factors->config = config; + factors->lock = lock; + factors->hw.init = &init; + factors->get_factors = get_factors; + + /* register the clock */ + clk = clk_register(dev, &factors->hw); + + if (IS_ERR(clk)) + kfree(factors); + + return clk; +} diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h new file mode 100644 index 000000000000..f49851cc4380 --- /dev/null +++ b/drivers/clk/sunxi/clk-factors.h @@ -0,0 +1,27 @@ +#ifndef __MACH_SUNXI_CLK_FACTORS_H +#define __MACH_SUNXI_CLK_FACTORS_H + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> + +#define SUNXI_FACTORS_NOT_APPLICABLE (0) + +struct clk_factors_config { + u8 nshift; + u8 nwidth; + u8 kshift; + u8 kwidth; + u8 mshift; + u8 mwidth; + u8 pshift; + u8 pwidth; +}; + +struct clk *clk_register_factors(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, void __iomem *reg, + struct clk_factors_config *config, + void (*get_factors) (u32 *rate, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p), + spinlock_t *lock); +#endif diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c new file mode 100644 index 000000000000..d528a2496690 --- /dev/null +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -0,0 +1,362 @@ +/* + * Copyright 2013 Emilio López + * + * Emilio López <emilio@elopez.com.ar> + * + * 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. + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/sunxi.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include "clk-factors.h" + +static DEFINE_SPINLOCK(clk_lock); + +/** + * sunxi_osc_clk_setup() - Setup function for gatable oscillator + */ + +#define SUNXI_OSC24M_GATE 0 + +static void __init sunxi_osc_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + const char *parent; + void *reg; + + reg = of_iomap(node, 0); + + parent = of_clk_get_parent_name(node, 0); + + clk = clk_register_gate(NULL, clk_name, parent, CLK_IGNORE_UNUSED, + reg, SUNXI_OSC24M_GATE, 0, &clk_lock); + + if (clk) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + } +} + + + +/** + * sunxi_get_pll1_factors() - calculates n, k, m, p factors for PLL1 + * PLL1 rate is calculated as follows + * rate = (parent_rate * n * (k + 1) >> p) / (m + 1); + * parent_rate is always 24Mhz + */ + +static void sunxi_get_pll1_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + u8 div; + + /* Normalize value to a 6M multiple */ + div = *freq / 6000000; + *freq = 6000000 * div; + + /* we were called to round the frequency, we can now return */ + if (n == NULL) + return; + + /* m is always zero for pll1 */ + *m = 0; + + /* k is 1 only on these cases */ + if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000) + *k = 1; + else + *k = 0; + + /* p will be 3 for divs under 10 */ + if (div < 10) + *p = 3; + + /* p will be 2 for divs between 10 - 20 and odd divs under 32 */ + else if (div < 20 || (div < 32 && (div & 1))) + *p = 2; + + /* p will be 1 for even divs under 32, divs under 40 and odd pairs + * of divs between 40-62 */ + else if (div < 40 || (div < 64 && (div & 2))) + *p = 1; + + /* any other entries have p = 0 */ + else + *p = 0; + + /* calculate a suitable n based on k and p */ + div <<= *p; + div /= (*k + 1); + *n = div / 4; +} + + + +/** + * sunxi_get_apb1_factors() - calculates m, p factors for APB1 + * APB1 rate is calculated as follows + * rate = (parent_rate >> p) / (m + 1); + */ + +static void sunxi_get_apb1_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + u8 calcm, calcp; + + if (parent_rate < *freq) + *freq = parent_rate; + + parent_rate = (parent_rate + (*freq - 1)) / *freq; + + /* Invalid rate! */ + if (parent_rate > 32) + return; + + if (parent_rate <= 4) + calcp = 0; + else if (parent_rate <= 8) + calcp = 1; + else if (parent_rate <= 16) + calcp = 2; + else + calcp = 3; + + calcm = (parent_rate >> calcp) - 1; + + *freq = (parent_rate >> calcp) / (calcm + 1); + + /* we were called to round the frequency, we can now return */ + if (n == NULL) + return; + + *m = calcm; + *p = calcp; +} + + + +/** + * sunxi_factors_clk_setup() - Setup function for factor clocks + */ + +struct factors_data { + struct clk_factors_config *table; + void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); +}; + +static struct clk_factors_config pll1_config = { + .nshift = 8, + .nwidth = 5, + .kshift = 4, + .kwidth = 2, + .mshift = 0, + .mwidth = 2, + .pshift = 16, + .pwidth = 2, +}; + +static struct clk_factors_config apb1_config = { + .mshift = 0, + .mwidth = 5, + .pshift = 16, + .pwidth = 2, +}; + +static const __initconst struct factors_data pll1_data = { + .table = &pll1_config, + .getter = sunxi_get_pll1_factors, +}; + +static const __initconst struct factors_data apb1_data = { + .table = &apb1_config, + .getter = sunxi_get_apb1_factors, +}; + +static void __init sunxi_factors_clk_setup(struct device_node *node, + struct factors_data *data) +{ + struct clk *clk; + const char *clk_name = node->name; + const char *parent; + void *reg; + + reg = of_iomap(node, 0); + + parent = of_clk_get_parent_name(node, 0); + + clk = clk_register_factors(NULL, clk_name, parent, CLK_IGNORE_UNUSED, + reg, data->table, data->getter, &clk_lock); + + if (clk) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + } +} + + + +/** + * sunxi_mux_clk_setup() - Setup function for muxes + */ + +#define SUNXI_MUX_GATE_WIDTH 2 + +struct mux_data { + u8 shift; +}; + +static const __initconst struct mux_data cpu_data = { + .shift = 16, +}; + +static const __initconst struct mux_data apb1_mux_data = { + .shift = 24, +}; + +static void __init sunxi_mux_clk_setup(struct device_node *node, + struct mux_data *data) +{ + struct clk *clk; + const char *clk_name = node->name; + const char **parents = kmalloc(sizeof(char *) * 5, GFP_KERNEL); + void *reg; + int i = 0; + + reg = of_iomap(node, 0); + + while (i < 5 && (parents[i] = of_clk_get_parent_name(node, i)) != NULL) + i++; + + clk = clk_register_mux(NULL, clk_name, parents, i, 0, reg, + data->shift, SUNXI_MUX_GATE_WIDTH, + 0, &clk_lock); + + if (clk) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + } +} + + + +/** + * sunxi_divider_clk_setup() - Setup function for simple divider clocks + */ + +#define SUNXI_DIVISOR_WIDTH 2 + +struct div_data { + u8 shift; + u8 pow; +}; + +static const __initconst struct div_data axi_data = { + .shift = 0, + .pow = 0, +}; + +static const __initconst struct div_data ahb_data = { + .shift = 4, + .pow = 1, +}; + +static const __initconst struct div_data apb0_data = { + .shift = 8, + .pow = 1, +}; + +static void __init sunxi_divider_clk_setup(struct device_node *node, + struct div_data *data) +{ + struct clk *clk; + const char *clk_name = node->name; + const char *clk_parent; + void *reg; + + reg = of_iomap(node, 0); + + clk_parent = of_clk_get_parent_name(node, 0); + + clk = clk_register_divider(NULL, clk_name, clk_parent, 0, + reg, data->shift, SUNXI_DIVISOR_WIDTH, + data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0, + &clk_lock); + if (clk) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + } +} + + +/* Matches for of_clk_init */ +static const __initconst struct of_device_id clk_match[] = { + {.compatible = "fixed-clock", .data = of_fixed_clk_setup,}, + {.compatible = "allwinner,sun4i-osc-clk", .data = sunxi_osc_clk_setup,}, + {} +}; + +/* Matches for factors clocks */ +static const __initconst struct of_device_id clk_factors_match[] = { + {.compatible = "allwinner,sun4i-pll1-clk", .data = &pll1_data,}, + {.compatible = "allwinner,sun4i-apb1-clk", .data = &apb1_data,}, + {} +}; + +/* Matches for divider clocks */ +static const __initconst struct of_device_id clk_div_match[] = { + {.compatible = "allwinner,sun4i-axi-clk", .data = &axi_data,}, + {.compatible = "allwinner,sun4i-ahb-clk", .data = &ahb_data,}, + {.compatible = "allwinner,sun4i-apb0-clk", .data = &apb0_data,}, + {} +}; + +/* Matches for mux clocks */ +static const __initconst struct of_device_id clk_mux_match[] = { + {.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_data,}, + {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,}, + {} +}; + +static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match, + void *function) +{ + struct device_node *np; + const struct div_data *data; + const struct of_device_id *match; + void (*setup_function)(struct device_node *, const void *) = function; + + for_each_matching_node(np, clk_match) { + match = of_match_node(clk_match, np); + data = match->data; + setup_function(np, data); + } +} + +void __init sunxi_init_clocks(void) +{ + /* Register all the simple sunxi clocks on DT */ + of_clk_init(clk_match); + + /* Register factor clocks */ + of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup); + + /* Register divider clocks */ + of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup); + + /* Register mux clocks */ + of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); +} diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 2b41b0f4f731..f49fac2d193a 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -9,3 +9,4 @@ obj-y += clk-super.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index 6dd533251e7b..bafee9895a24 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -41,7 +41,9 @@ static DEFINE_SPINLOCK(periph_ref_lock); #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)) +#define periph_clk_to_bit(gate) (1 << (gate->clk_num % 32)) + +#define LVL2_CLK_GATE_OVRE 0x554 /* Peripheral gate clock ops */ static int clk_periph_is_enabled(struct clk_hw *hw) @@ -83,6 +85,13 @@ static int clk_periph_enable(struct clk_hw *hw) } } + if (gate->flags & TEGRA_PERIPH_WAR_1005168) { + writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE); + udelay(1); + writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE); + } + spin_unlock_irqrestore(&periph_ref_lock, flags); return 0; diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index 788486e6331a..b2309d37a963 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -16,6 +16,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/err.h> @@ -128,6 +129,7 @@ void tegra_periph_reset_deassert(struct clk *c) tegra_periph_reset(gate, 0); } +EXPORT_SYMBOL(tegra_periph_reset_deassert); void tegra_periph_reset_assert(struct clk *c) { @@ -147,6 +149,7 @@ void tegra_periph_reset_assert(struct clk *c) tegra_periph_reset(gate, 1); } +EXPORT_SYMBOL(tegra_periph_reset_assert); const struct clk_ops tegra_clk_periph_ops = { .get_parent = clk_periph_get_parent, @@ -170,14 +173,15 @@ const struct clk_ops tegra_clk_periph_nodiv_ops = { 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) + void __iomem *clk_base, u32 offset, bool div, + unsigned long flags) { 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.flags = flags; init.parent_names = parent_names; init.num_parents = num_parents; @@ -202,10 +206,10 @@ static struct clk *_tegra_clk_register_periph(const char *name, 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) + u32 offset, unsigned long flags) { return _tegra_clk_register_periph(name, parent_names, num_parents, - periph, clk_base, offset, true); + periph, clk_base, offset, true, flags); } struct clk *tegra_clk_register_periph_nodiv(const char *name, @@ -214,5 +218,5 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name, u32 offset) { return _tegra_clk_register_periph(name, parent_names, num_parents, - periph, clk_base, offset, false); + periph, clk_base, offset, false, CLK_SET_RATE_PARENT); } diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 165f24734c1b..17c2cc086eb4 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012, 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, @@ -79,6 +79,48 @@ #define PLLE_SS_CTRL 0x68 #define PLLE_SS_DISABLE (7 << 10) +#define PLLE_AUX_PLLP_SEL BIT(2) +#define PLLE_AUX_ENABLE_SWCTL BIT(4) +#define PLLE_AUX_SEQ_ENABLE BIT(24) +#define PLLE_AUX_PLLRE_SEL BIT(28) + +#define PLLE_MISC_PLLE_PTS BIT(8) +#define PLLE_MISC_IDDQ_SW_VALUE BIT(13) +#define PLLE_MISC_IDDQ_SW_CTRL BIT(14) +#define PLLE_MISC_VREG_BG_CTRL_SHIFT 4 +#define PLLE_MISC_VREG_BG_CTRL_MASK (3 << PLLE_MISC_VREG_BG_CTRL_SHIFT) +#define PLLE_MISC_VREG_CTRL_SHIFT 2 +#define PLLE_MISC_VREG_CTRL_MASK (2 << PLLE_MISC_VREG_CTRL_SHIFT) + +#define PLLCX_MISC_STROBE BIT(31) +#define PLLCX_MISC_RESET BIT(30) +#define PLLCX_MISC_SDM_DIV_SHIFT 28 +#define PLLCX_MISC_SDM_DIV_MASK (0x3 << PLLCX_MISC_SDM_DIV_SHIFT) +#define PLLCX_MISC_FILT_DIV_SHIFT 26 +#define PLLCX_MISC_FILT_DIV_MASK (0x3 << PLLCX_MISC_FILT_DIV_SHIFT) +#define PLLCX_MISC_ALPHA_SHIFT 18 +#define PLLCX_MISC_DIV_LOW_RANGE \ + ((0x1 << PLLCX_MISC_SDM_DIV_SHIFT) | \ + (0x1 << PLLCX_MISC_FILT_DIV_SHIFT)) +#define PLLCX_MISC_DIV_HIGH_RANGE \ + ((0x2 << PLLCX_MISC_SDM_DIV_SHIFT) | \ + (0x2 << PLLCX_MISC_FILT_DIV_SHIFT)) +#define PLLCX_MISC_COEF_LOW_RANGE \ + ((0x14 << PLLCX_MISC_KA_SHIFT) | (0x38 << PLLCX_MISC_KB_SHIFT)) +#define PLLCX_MISC_KA_SHIFT 2 +#define PLLCX_MISC_KB_SHIFT 9 +#define PLLCX_MISC_DEFAULT (PLLCX_MISC_COEF_LOW_RANGE | \ + (0x19 << PLLCX_MISC_ALPHA_SHIFT) | \ + PLLCX_MISC_DIV_LOW_RANGE | \ + PLLCX_MISC_RESET) +#define PLLCX_MISC1_DEFAULT 0x000d2308 +#define PLLCX_MISC2_DEFAULT 0x30211200 +#define PLLCX_MISC3_DEFAULT 0x200 + +#define PMC_PLLM_WB0_OVERRIDE 0x1dc +#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0 +#define PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK BIT(27) + #define PMC_SATA_PWRGT 0x1ac #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) @@ -101,6 +143,24 @@ #define divn_max(p) (divn_mask(p)) #define divp_max(p) (1 << (divp_mask(p))) + +#ifdef CONFIG_ARCH_TEGRA_114_SOC +/* PLLXC has 4-bit PDIV, but entry 15 is not allowed in h/w */ +#define PLLXC_PDIV_MAX 14 + +/* non-monotonic mapping below is not a typo */ +static u8 pllxc_p[PLLXC_PDIV_MAX + 1] = { + /* PDIV: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ + /* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32 +}; + +#define PLLCX_PDIV_MAX 7 +static u8 pllcx_p[PLLCX_PDIV_MAX + 1] = { + /* PDIV: 0, 1, 2, 3, 4, 5, 6, 7 */ + /* p: */ 1, 2, 3, 4, 6, 8, 12, 16 +}; +#endif + static void clk_pll_enable_lock(struct tegra_clk_pll *pll) { u32 val; @@ -108,25 +168,36 @@ static void clk_pll_enable_lock(struct tegra_clk_pll *pll) if (!(pll->flags & TEGRA_PLL_USE_LOCK)) return; + if (!(pll->flags & TEGRA_PLL_HAS_LOCK_ENABLE)) + 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) +static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll) { int i; - u32 val; + u32 val, lock_mask; + void __iomem *lock_addr; if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { udelay(pll->params->lock_delay); return 0; } + lock_addr = pll->clk_base; + if (pll->flags & TEGRA_PLL_LOCK_MISC) + lock_addr += pll->params->misc_reg; + else + lock_addr += pll->params->base_reg; + + lock_mask = pll->params->lock_mask; + for (i = 0; i < pll->params->lock_delay; i++) { val = readl_relaxed(lock_addr); - if (val & BIT(lock_bit_idx)) { + if ((val & lock_mask) == lock_mask) { udelay(PLL_POST_LOCK_DELAY); return 0; } @@ -155,7 +226,7 @@ static int clk_pll_is_enabled(struct clk_hw *hw) return val & PLL_BASE_ENABLE ? 1 : 0; } -static int _clk_pll_enable(struct clk_hw *hw) +static void _clk_pll_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); u32 val; @@ -163,7 +234,8 @@ static int _clk_pll_enable(struct clk_hw *hw) clk_pll_enable_lock(pll); val = pll_readl_base(pll); - val &= ~PLL_BASE_BYPASS; + if (pll->flags & TEGRA_PLL_BYPASS) + val &= ~PLL_BASE_BYPASS; val |= PLL_BASE_ENABLE; pll_writel_base(val, pll); @@ -172,11 +244,6 @@ static int _clk_pll_enable(struct clk_hw *hw) 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) @@ -185,7 +252,9 @@ static void _clk_pll_disable(struct clk_hw *hw) u32 val; val = pll_readl_base(pll); - val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); + if (pll->flags & TEGRA_PLL_BYPASS) + val &= ~PLL_BASE_BYPASS; + val &= ~PLL_BASE_ENABLE; pll_writel_base(val, pll); if (pll->flags & TEGRA_PLLM) { @@ -204,7 +273,9 @@ static int clk_pll_enable(struct clk_hw *hw) if (pll->lock) spin_lock_irqsave(pll->lock, flags); - ret = _clk_pll_enable(hw); + _clk_pll_enable(hw); + + ret = clk_pll_wait_for_lock(pll); if (pll->lock) spin_unlock_irqrestore(pll->lock, flags); @@ -241,8 +312,6 @@ static int _get_table_rate(struct clk_hw *hw, 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; @@ -257,6 +326,7 @@ 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); + struct pdiv_map *p_tohw = pll->params->pdiv_tohw; unsigned long cfreq; u32 p_div = 0; @@ -290,88 +360,119 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, 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) { + (1 << p_div) > 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; } + if (p_tohw) { + p_div = 1 << p_div; + while (p_tohw->pdiv) { + if (p_div <= p_tohw->pdiv) { + cfg->p = p_tohw->hw_val; + break; + } + p_tohw++; + } + if (!p_tohw->pdiv) + return -EINVAL; + } else + cfg->p = p_div; + return 0; } -static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, - unsigned long rate) +static void _update_pll_mnp(struct tegra_clk_pll *pll, + struct tegra_clk_pll_freq_table *cfg) { - 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; + u32 val; - if (pll->lock) - spin_lock_irqsave(pll->lock, flags); + val = pll_readl_base(pll); - 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; + (cfg->p << pll->divp_shift)); + + pll_writel_base(val, pll); +} + +static void _get_pll_mnp(struct tegra_clk_pll *pll, + struct tegra_clk_pll_freq_table *cfg) +{ + u32 val; + + val = pll_readl_base(pll); + + cfg->m = (val >> pll->divm_shift) & (divm_mask(pll)); + cfg->n = (val >> pll->divn_shift) & (divn_mask(pll)); + cfg->p = (val >> pll->divp_shift) & (divp_mask(pll)); +} + +static void _update_pll_cpcon(struct tegra_clk_pll *pll, + struct tegra_clk_pll_freq_table *cfg, + unsigned long rate) +{ + u32 val; + + 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 |= 1 << PLL_MISC_LFCON_SHIFT; + } else if (pll->flags & TEGRA_PLL_SET_DCCON) { + val &= ~(1 << PLL_MISC_DCCON_SHIFT); + if (rate >= (pll->params->vco_max >> 1)) + val |= 1 << PLL_MISC_DCCON_SHIFT; } + pll_writel_misc(val, pll); +} + +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); + int state, ret = 0; + state = clk_pll_is_enabled(hw); - if (state) { + 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); - } + _update_pll_mnp(pll, cfg); - if (pll->lock) - spin_unlock_irqrestore(pll->lock, flags); + if (pll->flags & TEGRA_PLL_HAS_CPCON) + _update_pll_cpcon(pll, cfg, rate); - if (state) - clk_pll_enable(hw); + if (state) { + _clk_pll_enable(hw); + ret = clk_pll_wait_for_lock(pll); + } - return 0; + return ret; } 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; + struct tegra_clk_pll_freq_table cfg, old_cfg; + unsigned long flags = 0; + int ret = 0; if (pll->flags & TEGRA_PLL_FIXED) { if (rate != pll->fixed_rate) { @@ -387,7 +488,18 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, _calc_rate(hw, &cfg, rate, parent_rate)) return -EINVAL; - return _program_pll(hw, &cfg, rate); + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _get_pll_mnp(pll, &old_cfg); + + if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p) + ret = _program_pll(hw, &cfg, rate); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; } static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -409,7 +521,7 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; output_rate *= cfg.n; - do_div(output_rate, cfg.m * cfg.p); + do_div(output_rate, cfg.m * (1 << cfg.p)); return output_rate; } @@ -418,11 +530,15 @@ 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; + struct tegra_clk_pll_freq_table cfg; + struct pdiv_map *p_tohw = pll->params->pdiv_tohw; + u32 val; u64 rate = parent_rate; + int pdiv; + + val = pll_readl_base(pll); - if (val & PLL_BASE_BYPASS) + if ((pll->flags & TEGRA_PLL_BYPASS) && (val & PLL_BASE_BYPASS)) return parent_rate; if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) { @@ -435,16 +551,29 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, return pll->fixed_rate; } - divp = (val >> pll->divp_shift) & (divp_mask(pll)); - if (pll->flags & TEGRA_PLLU) - divp ^= 1; + _get_pll_mnp(pll, &cfg); - divn = (val >> pll->divn_shift) & (divn_mask(pll)); - divm = (val >> pll->divm_shift) & (divm_mask(pll)); - divm *= (1 << divp); + if (p_tohw) { + while (p_tohw->pdiv) { + if (cfg.p == p_tohw->hw_val) { + pdiv = p_tohw->pdiv; + break; + } + p_tohw++; + } + + if (!p_tohw->pdiv) { + WARN_ON(1); + pdiv = 1; + } + } else + pdiv = 1 << cfg.p; + + cfg.m *= pdiv; + + rate *= cfg.n; + do_div(rate, cfg.m); - rate *= divn; - do_div(rate, divm); return rate; } @@ -538,8 +667,8 @@ static int clk_plle_enable(struct clk_hw *hw) 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); + clk_pll_wait_for_lock(pll); + return 0; } @@ -577,28 +706,531 @@ const struct clk_ops tegra_clk_plle_ops = { .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) +#ifdef CONFIG_ARCH_TEGRA_114_SOC + +static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, + unsigned long parent_rate) +{ + if (parent_rate > pll_params->cf_max) + return 2; + else + return 1; +} + +static int clk_pll_iddq_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + + u32 val; + int ret; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + val = pll_readl(pll->params->iddq_reg, pll); + val &= ~BIT(pll->params->iddq_bit_idx); + pll_writel(val, pll->params->iddq_reg, pll); + udelay(2); + + _clk_pll_enable(hw); + + ret = clk_pll_wait_for_lock(pll); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return 0; +} + +static void clk_pll_iddq_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + u32 val; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pll_disable(hw); + + val = pll_readl(pll->params->iddq_reg, pll); + val |= BIT(pll->params->iddq_bit_idx); + pll_writel(val, pll->params->iddq_reg, pll); + udelay(2); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} + +static int _calc_dynamic_ramp_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 int p; + + if (!rate) + return -EINVAL; + + p = DIV_ROUND_UP(pll->params->vco_min, rate); + cfg->m = _pll_fixed_mdiv(pll->params, parent_rate); + cfg->p = p; + cfg->output_rate = rate * cfg->p; + cfg->n = cfg->output_rate * cfg->m / parent_rate; + + if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max) + return -EINVAL; + + return 0; +} + +static int _pll_ramp_calc_pll(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); + int err = 0; + + err = _get_table_rate(hw, cfg, rate, parent_rate); + if (err < 0) + err = _calc_dynamic_ramp_rate(hw, cfg, rate, parent_rate); + else if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) { + WARN_ON(1); + err = -EINVAL; + goto out; + } + + if (!cfg->p || (cfg->p > pll->params->max_p)) + err = -EINVAL; + +out: + return err; +} + +static int clk_pllxc_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, old_cfg; + unsigned long flags = 0; + int ret = 0; + u8 old_p; + + ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate); + if (ret < 0) + return ret; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _get_pll_mnp(pll, &old_cfg); + + old_p = pllxc_p[old_cfg.p]; + if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_p != cfg.p) { + cfg.p -= 1; + ret = _program_pll(hw, &cfg, rate); + } + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_pll_freq_table cfg; + int ret = 0; + u64 output_rate = *prate; + + ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate); + if (ret < 0) + return ret; + + output_rate *= cfg.n; + do_div(output_rate, cfg.m * cfg.p); + + return output_rate; +} + +static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_pll_freq_table cfg; + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + int state, ret = 0; + u32 val; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + state = clk_pll_is_enabled(hw); + if (state) { + if (rate != clk_get_rate(hw->clk)) { + pr_err("%s: Cannot change active PLLM\n", __func__); + ret = -EINVAL; + goto out; + } + goto out; + } + + ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate); + if (ret < 0) + goto out; + + cfg.p -= 1; + + val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE); + if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) { + val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE_2); + val = cfg.p ? (val | PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK) : + (val & ~PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK); + writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE_2); + + val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE); + val &= ~(divn_mask(pll) | divm_mask(pll)); + val |= (cfg.m << pll->divm_shift) | (cfg.n << pll->divn_shift); + writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE); + } else + _update_pll_mnp(pll, &cfg); + + +out: + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static void _pllcx_strobe(struct tegra_clk_pll *pll) +{ + u32 val; + + val = pll_readl_misc(pll); + val |= PLLCX_MISC_STROBE; + pll_writel_misc(val, pll); + udelay(2); + + val &= ~PLLCX_MISC_STROBE; + pll_writel_misc(val, pll); +} + +static int clk_pllc_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + int ret = 0; + unsigned long flags = 0; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pll_enable(hw); + udelay(2); + + val = pll_readl_misc(pll); + val &= ~PLLCX_MISC_RESET; + pll_writel_misc(val, pll); + udelay(2); + + _pllcx_strobe(pll); + + ret = clk_pll_wait_for_lock(pll); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static void _clk_pllc_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + _clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val |= PLLCX_MISC_RESET; + pll_writel_misc(val, pll); + udelay(2); +} + +static void clk_pllc_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_pllc_disable(hw); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} + +static int _pllcx_update_dynamic_coef(struct tegra_clk_pll *pll, + unsigned long input_rate, u32 n) +{ + u32 val, n_threshold; + + switch (input_rate) { + case 12000000: + n_threshold = 70; + break; + case 13000000: + case 26000000: + n_threshold = 71; + break; + case 16800000: + n_threshold = 55; + break; + case 19200000: + n_threshold = 48; + break; + default: + pr_err("%s: Unexpected reference rate %lu\n", + __func__, input_rate); + return -EINVAL; + } + + val = pll_readl_misc(pll); + val &= ~(PLLCX_MISC_SDM_DIV_MASK | PLLCX_MISC_FILT_DIV_MASK); + val |= n <= n_threshold ? + PLLCX_MISC_DIV_LOW_RANGE : PLLCX_MISC_DIV_HIGH_RANGE; + pll_writel_misc(val, pll); + + return 0; +} + +static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_pll_freq_table cfg; + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + int state, ret = 0; + u32 val; + u16 old_m, old_n; + u8 old_p; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate); + if (ret < 0) + goto out; + + val = pll_readl_base(pll); + old_m = (val >> pll->divm_shift) & (divm_mask(pll)); + old_n = (val >> pll->divn_shift) & (divn_mask(pll)); + old_p = pllcx_p[(val >> pll->divp_shift) & (divp_mask(pll))]; + + if (cfg.m != old_m) { + WARN_ON(1); + goto out; + } + + if (old_n == cfg.n && old_p == cfg.p) + goto out; + + cfg.p -= 1; + + state = clk_pll_is_enabled(hw); + if (state) + _clk_pllc_disable(hw); + + ret = _pllcx_update_dynamic_coef(pll, parent_rate, cfg.n); + if (ret < 0) + goto out; + + _update_pll_mnp(pll, &cfg); + + if (state) + ret = clk_pllc_enable(hw); + +out: + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static long _pllre_calc_rate(struct tegra_clk_pll *pll, + struct tegra_clk_pll_freq_table *cfg, + unsigned long rate, unsigned long parent_rate) +{ + u16 m, n; + u64 output_rate = parent_rate; + + m = _pll_fixed_mdiv(pll->params, parent_rate); + n = rate * m / parent_rate; + + output_rate *= n; + do_div(output_rate, m); + + if (cfg) { + cfg->m = m; + cfg->n = n; + } + + return output_rate; +} +static int clk_pllre_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_clk_pll_freq_table cfg, old_cfg; + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + int state, ret = 0; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _pllre_calc_rate(pll, &cfg, rate, parent_rate); + _get_pll_mnp(pll, &old_cfg); + cfg.p = old_cfg.p; + + if (cfg.m != old_cfg.m || cfg.n != old_cfg.n) { + state = clk_pll_is_enabled(hw); + if (state) + _clk_pll_disable(hw); + + _update_pll_mnp(pll, &cfg); + + if (state) { + _clk_pll_enable(hw); + ret = clk_pll_wait_for_lock(pll); + } + } + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static unsigned long clk_pllre_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_clk_pll_freq_table cfg; + struct tegra_clk_pll *pll = to_clk_pll(hw); + u64 rate = parent_rate; + + _get_pll_mnp(pll, &cfg); + + rate *= cfg.n; + do_div(rate, cfg.m); + + return rate; +} + +static long clk_pllre_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + + return _pllre_calc_rate(pll, NULL, rate, *prate); +} + +static int clk_plle_tegra114_enable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct tegra_clk_pll_freq_table sel; + u32 val; + int ret; + unsigned long flags = 0; + unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); + + if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + return -EINVAL; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + val = pll_readl_base(pll); + val &= ~BIT(29); /* Disable lock override */ + pll_writel_base(val, pll); + + val = pll_readl(pll->params->aux_reg, pll); + val |= PLLE_AUX_ENABLE_SWCTL; + val &= ~PLLE_AUX_SEQ_ENABLE; + pll_writel(val, pll->params->aux_reg, pll); + udelay(1); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_LOCK_ENABLE; + val |= PLLE_MISC_IDDQ_SW_CTRL; + val &= ~PLLE_MISC_IDDQ_SW_VALUE; + val |= PLLE_MISC_PLLE_PTS; + val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK; + pll_writel_misc(val, pll); + udelay(5); + + val = pll_readl(PLLE_SS_CTRL, pll); + val |= PLLE_SS_DISABLE; + pll_writel(val, PLLE_SS_CTRL, pll); + + 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.cpcon << PLLE_BASE_DIVCML_SHIFT; + pll_writel_base(val, pll); + udelay(1); + + _clk_pll_enable(hw); + ret = clk_pll_wait_for_lock(pll); + + if (ret < 0) + goto out; + + /* TODO: enable hw control of xusb brick pll */ + +out: + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); + + return ret; +} + +static void clk_plle_tegra114_disable(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + u32 val; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + + _clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE; + pll_writel_misc(val, pll); + udelay(1); + + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} +#endif + +static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base, + void __iomem *pmc, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) { 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; @@ -615,34 +1247,336 @@ static struct clk *_tegra_clk_register_pll(const char *name, pll->divm_shift = PLL_BASE_DIVM_SHIFT; pll->divm_width = PLL_BASE_DIVM_WIDTH; + return pll; +} + +static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll, + const char *name, const char *parent_name, unsigned long flags, + const struct clk_ops *ops) +{ + struct clk_init_data init; + + init.name = name; + init.ops = ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + /* 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; + return clk_register(NULL, &pll->hw); } 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_params *pll_params, u32 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 tegra_clk_pll *pll; + struct clk *clk; + + pll_flags |= TEGRA_PLL_BYPASS; + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pll_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; } 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_params *pll_params, u32 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); + struct tegra_clk_pll *pll; + struct clk *clk; + + pll_flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS; + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_plle_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +#ifdef CONFIG_ARCH_TEGRA_114_SOC +const struct clk_ops tegra_clk_pllxc_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_iddq_enable, + .disable = clk_pll_iddq_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_ramp_round_rate, + .set_rate = clk_pllxc_set_rate, +}; + +const struct clk_ops tegra_clk_pllm_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_iddq_enable, + .disable = clk_pll_iddq_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_ramp_round_rate, + .set_rate = clk_pllm_set_rate, +}; + +const struct clk_ops tegra_clk_pllc_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pllc_enable, + .disable = clk_pllc_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_ramp_round_rate, + .set_rate = clk_pllc_set_rate, +}; + +const struct clk_ops tegra_clk_pllre_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_iddq_enable, + .disable = clk_pll_iddq_disable, + .recalc_rate = clk_pllre_recalc_rate, + .round_rate = clk_pllre_round_rate, + .set_rate = clk_pllre_set_rate, +}; + +const struct clk_ops tegra_clk_plle_tegra114_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_plle_tegra114_enable, + .disable = clk_plle_tegra114_disable, + .recalc_rate = clk_pll_recalc_rate, +}; + + +struct clk *tegra_clk_register_pllxc(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, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + + if (!pll_params->pdiv_tohw) + return ERR_PTR(-EINVAL); + + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllxc_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_pllre(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, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock, unsigned long parent_rate) +{ + u32 val; + struct tegra_clk_pll *pll; + struct clk *clk; + + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + /* program minimum rate by default */ + + val = pll_readl_base(pll); + if (val & PLL_BASE_ENABLE) + WARN_ON(val & pll_params->iddq_bit_idx); + else { + int m; + + m = _pll_fixed_mdiv(pll_params, parent_rate); + val = m << PLL_BASE_DIVM_SHIFT; + val |= (pll_params->vco_min / parent_rate) + << PLL_BASE_DIVN_SHIFT; + pll_writel_base(val, pll); + } + + /* disable lock override */ + + val = pll_readl_misc(pll); + val &= ~BIT(29); + pll_writel_misc(val, pll); + + pll_flags |= TEGRA_PLL_LOCK_MISC; + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllre_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_pllm(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, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + + if (!pll_params->pdiv_tohw) + return ERR_PTR(-EINVAL); + + pll_flags |= TEGRA_PLL_BYPASS; + pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllm_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_pllc(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, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock) +{ + struct clk *parent, *clk; + struct pdiv_map *p_tohw = pll_params->pdiv_tohw; + struct tegra_clk_pll *pll; + struct tegra_clk_pll_freq_table cfg; + unsigned long parent_rate; + + if (!p_tohw) + return ERR_PTR(-EINVAL); + + parent = __clk_lookup(parent_name); + if (IS_ERR(parent)) { + WARN(1, "parent clk %s of %s must be registered first\n", + name, parent_name); + return ERR_PTR(-EINVAL); + } + + pll_flags |= TEGRA_PLL_BYPASS; + pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, + freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + parent_rate = __clk_get_rate(parent); + + /* + * Most of PLLC register fields are shadowed, and can not be read + * directly from PLL h/w. Hence, actual PLLC boot state is unknown. + * Initialize PLL to default state: disabled, reset; shadow registers + * loaded with default parameters; dividers are preset for half of + * minimum VCO rate (the latter assured that shadowed divider settings + * are within supported range). + */ + + cfg.m = _pll_fixed_mdiv(pll_params, parent_rate); + cfg.n = cfg.m * pll_params->vco_min / parent_rate; + + while (p_tohw->pdiv) { + if (p_tohw->pdiv == 2) { + cfg.p = p_tohw->hw_val; + break; + } + p_tohw++; + } + + if (!p_tohw->pdiv) { + WARN_ON(1); + return ERR_PTR(-EINVAL); + } + + pll_writel_base(0, pll); + _update_pll_mnp(pll, &cfg); + + pll_writel_misc(PLLCX_MISC_DEFAULT, pll); + pll_writel(PLLCX_MISC1_DEFAULT, pll_params->ext_misc_reg[0], pll); + pll_writel(PLLCX_MISC2_DEFAULT, pll_params->ext_misc_reg[1], pll); + pll_writel(PLLCX_MISC3_DEFAULT, pll_params->ext_misc_reg[2], pll); + + _pllcx_update_dynamic_coef(pll, parent_rate, cfg.n); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllc_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + +struct clk *tegra_clk_register_plle_tegra114(const char *name, + const char *parent_name, + void __iomem *clk_base, unsigned long flags, + unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock) +{ + struct tegra_clk_pll *pll; + struct clk *clk; + u32 val, val_aux; + + pll = _tegra_init_pll(clk_base, NULL, fixed_rate, pll_params, + TEGRA_PLL_HAS_LOCK_ENABLE, freq_table, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + /* ensure parent is set to pll_re_vco */ + + val = pll_readl_base(pll); + val_aux = pll_readl(pll_params->aux_reg, pll); + + if (val & PLL_BASE_ENABLE) { + if (!(val_aux & PLLE_AUX_PLLRE_SEL)) + WARN(1, "pll_e enabled with unsupported parent %s\n", + (val & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : "pll_ref"); + } else { + val_aux |= PLLE_AUX_PLLRE_SEL; + pll_writel(val, pll_params->aux_reg, pll); + } + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_plle_tegra114_ops); + if (IS_ERR(clk)) + kfree(pll); + + return clk; } +#endif diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c new file mode 100644 index 000000000000..d78e16ee161c --- /dev/null +++ b/drivers/clk/tegra/clk-tegra114.c @@ -0,0 +1,2085 @@ +/* + * Copyright (c) 2012, 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/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/delay.h> +#include <linux/clk/tegra.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_X 0x28C +#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_X 0x280 +#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_SET_X 0x284 +#define CLK_OUT_ENB_CLR_X 0x288 +#define CLK_OUT_ENB_NUM 6 + +#define PLLC_BASE 0x80 +#define PLLC_MISC2 0x88 +#define PLLC_MISC 0x8c +#define PLLC2_BASE 0x4e8 +#define PLLC2_MISC 0x4ec +#define PLLC3_BASE 0x4fc +#define PLLC3_MISC 0x500 +#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 PLLX_MISC2 0x514 +#define PLLX_MISC3 0x518 +#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 PLLRE_BASE 0x4c4 +#define PLLRE_MISC 0x4c8 + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLC_MISC_LOCK_ENABLE 24 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLE_MISC_LOCK_ENABLE 9 +#define PLLRE_MISC_LOCK_ENABLE 30 + +#define PLLC_IDDQ_BIT 26 +#define PLLX_IDDQ_BIT 3 +#define PLLRE_IDDQ_BIT 16 + +#define PLL_BASE_LOCK BIT(27) +#define PLLE_MISC_LOCK BIT(11) +#define PLLRE_MISC_LOCK BIT(24) +#define PLLCX_BASE_LOCK (BIT(26)|BIT(27)) + +#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 AUDIO_SYNC_DOUBLER 0x49c + +#define PMC_CLK_OUT_CNTRL 0x1a8 +#define PMC_DPD_PADS_ORIDE 0x1c +#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 +#define PMC_CTRL 0 +#define PMC_CTRL_BLINK_ENB 7 + +#define OSC_CTRL 0x50 +#define OSC_CTRL_OSC_FREQ_SHIFT 28 +#define OSC_CTRL_PLL_REF_DIV_SHIFT 26 + +#define PLLXC_SW_MAX_P 6 + +#define CCLKG_BURST_POLICY 0x368 +#define CCLKLP_BURST_POLICY 0x370 +#define SCLK_BURST_POLICY 0x028 +#define SYSTEM_CLK_RATE 0x030 + +#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_PLLU_POWERUP BIT(17) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) +#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) + +#define UTMIPLL_HW_PWRDN_CFG0 0x52c +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24) +#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4) +#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) + +#define CLK_SOURCE_I2S0 0x1d8 +#define CLK_SOURCE_I2S1 0x100 +#define CLK_SOURCE_I2S2 0x104 +#define CLK_SOURCE_NDFLASH 0x160 +#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_ADX 0x638 +#define CLK_SOURCE_AMX 0x63c +#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_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_TRACE 0x634 +#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_UARTA_DBG 0x178 +#define CLK_SOURCE_UARTB_DBG 0x17c +#define CLK_SOURCE_UARTC_DBG 0x1a0 +#define CLK_SOURCE_UARTD_DBG 0x1c0 +#define CLK_SOURCE_UARTE_DBG 0x1c4 +#define CLK_SOURCE_3D 0x158 +#define CLK_SOURCE_2D 0x15c +#define CLK_SOURCE_VI_SENSOR 0x1a8 +#define CLK_SOURCE_VI 0x148 +#define CLK_SOURCE_EPP 0x16c +#define CLK_SOURCE_MSENC 0x1f0 +#define CLK_SOURCE_TSEC 0x1f4 +#define CLK_SOURCE_HOST1X 0x180 +#define CLK_SOURCE_HDMI 0x18c +#define CLK_SOURCE_DISP1 0x138 +#define CLK_SOURCE_DISP2 0x13c +#define CLK_SOURCE_CILAB 0x614 +#define CLK_SOURCE_CILCD 0x618 +#define CLK_SOURCE_CILE 0x61c +#define CLK_SOURCE_DSIALP 0x620 +#define CLK_SOURCE_DSIBLP 0x624 +#define CLK_SOURCE_TSENSOR 0x3b8 +#define CLK_SOURCE_D_AUDIO 0x3d0 +#define CLK_SOURCE_DAM0 0x3d8 +#define CLK_SOURCE_DAM1 0x3dc +#define CLK_SOURCE_DAM2 0x3e0 +#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_SOC_THERM 0x644 +#define CLK_SOURCE_XUSB_HOST_SRC 0x600 +#define CLK_SOURCE_XUSB_FALCON_SRC 0x604 +#define CLK_SOURCE_XUSB_FS_SRC 0x608 +#define CLK_SOURCE_XUSB_SS_SRC 0x610 +#define CLK_SOURCE_XUSB_DEV_SRC 0x60c +#define CLK_SOURCE_EMC 0x19c + +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_d_lock); +static DEFINE_SPINLOCK(pll_d2_lock); +static DEFINE_SPINLOCK(pll_u_lock); +static DEFINE_SPINLOCK(pll_div_lock); +static DEFINE_SPINLOCK(pll_re_lock); +static DEFINE_SPINLOCK(clk_doubler_lock); +static DEFINE_SPINLOCK(clk_out_lock); +static DEFINE_SPINLOCK(sysrate_lock); + +static struct pdiv_map pllxc_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 3, .hw_val = 2 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 5, .hw_val = 4 }, + { .pdiv = 6, .hw_val = 5 }, + { .pdiv = 8, .hw_val = 6 }, + { .pdiv = 10, .hw_val = 7 }, + { .pdiv = 12, .hw_val = 8 }, + { .pdiv = 16, .hw_val = 9 }, + { .pdiv = 12, .hw_val = 10 }, + { .pdiv = 16, .hw_val = 11 }, + { .pdiv = 20, .hw_val = 12 }, + { .pdiv = 24, .hw_val = 13 }, + { .pdiv = 32, .hw_val = 14 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { + { 12000000, 624000000, 104, 0, 2}, + { 12000000, 600000000, 100, 0, 2}, + { 13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */ + { 16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */ + { 19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */ + { 26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params pll_c_params = { + .input_min = 12000000, + .input_max = 800000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 600000000, + .vco_max = 1400000000, + .base_reg = PLLC_BASE, + .misc_reg = PLLC_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLC_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLC_MISC, + .iddq_bit_idx = PLLC_IDDQ_BIT, + .max_p = PLLXC_SW_MAX_P, + .dyn_ramp_reg = PLLC_MISC2, + .stepa_shift = 17, + .stepb_shift = 9, + .pdiv_tohw = pllxc_p, +}; + +static struct pdiv_map pllc_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 8, .hw_val = 5 }, + { .pdiv = 16, .hw_val = 7 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = { + {12000000, 600000000, 100, 0, 2}, + {13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */ + {16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */ + {19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */ + {26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_c2_params = { + .input_min = 12000000, + .input_max = 48000000, + .cf_min = 12000000, + .cf_max = 19200000, + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC2_BASE, + .misc_reg = PLLC2_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .pdiv_tohw = pllc_p, + .ext_misc_reg[0] = 0x4f0, + .ext_misc_reg[1] = 0x4f4, + .ext_misc_reg[2] = 0x4f8, +}; + +static struct tegra_clk_pll_params pll_c3_params = { + .input_min = 12000000, + .input_max = 48000000, + .cf_min = 12000000, + .cf_max = 19200000, + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC3_BASE, + .misc_reg = PLLC3_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .pdiv_tohw = pllc_p, + .ext_misc_reg[0] = 0x504, + .ext_misc_reg[1] = 0x508, + .ext_misc_reg[2] = 0x50c, +}; + +static struct pdiv_map pllm_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { + {12000000, 800000000, 66, 0, 1}, /* actual: 792.0 MHz */ + {13000000, 800000000, 61, 0, 1}, /* actual: 793.0 MHz */ + {16800000, 800000000, 47, 0, 1}, /* actual: 789.6 MHz */ + {19200000, 800000000, 41, 0, 1}, /* actual: 787.2 MHz */ + {26000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_m_params = { + .input_min = 12000000, + .input_max = 500000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 400000000, + .vco_max = 1066000000, + .base_reg = PLLM_BASE, + .misc_reg = PLLM_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .max_p = 2, + .pdiv_tohw = pllm_p, +}; + +static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { + {12000000, 216000000, 432, 12, 1, 8}, + {13000000, 216000000, 432, 13, 1, 8}, + {16800000, 216000000, 360, 14, 1, 8}, + {19200000, 216000000, 360, 16, 1, 8}, + {26000000, 216000000, 432, 26, 1, 8}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_p_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 200000000, + .vco_max = 700000000, + .base_reg = PLLP_BASE, + .misc_reg = PLLP_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { + {9600000, 282240000, 147, 5, 0, 4}, + {9600000, 368640000, 192, 5, 0, 4}, + {9600000, 240000000, 200, 8, 0, 8}, + + {28800000, 282240000, 245, 25, 0, 8}, + {28800000, 368640000, 320, 25, 0, 8}, + {28800000, 240000000, 200, 24, 0, 8}, + {0, 0, 0, 0, 0, 0}, +}; + + +static struct tegra_clk_pll_params pll_a_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 200000000, + .vco_max = 700000000, + .base_reg = PLLA_BASE, + .misc_reg = PLLA_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { + {12000000, 216000000, 864, 12, 2, 12}, + {13000000, 216000000, 864, 13, 2, 12}, + {16800000, 216000000, 720, 14, 2, 12}, + {19200000, 216000000, 720, 16, 2, 12}, + {26000000, 216000000, 864, 26, 2, 12}, + + {12000000, 594000000, 594, 12, 0, 12}, + {13000000, 594000000, 594, 13, 0, 12}, + {16800000, 594000000, 495, 14, 0, 12}, + {19200000, 594000000, 495, 16, 0, 12}, + {26000000, 594000000, 594, 26, 0, 12}, + + {12000000, 1000000000, 1000, 12, 0, 12}, + {13000000, 1000000000, 1000, 13, 0, 12}, + {19200000, 1000000000, 625, 12, 0, 12}, + {26000000, 1000000000, 1000, 26, 0, 12}, + + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_d_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 500000000, + .vco_max = 1000000000, + .base_reg = PLLD_BASE, + .misc_reg = PLLD_MISC, + .lock_mask = 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 = 500000000, + .vco_max = 1000000000, + .base_reg = PLLD2_BASE, + .misc_reg = PLLD2_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, +}; + +static struct pdiv_map pllu_p[] = { + { .pdiv = 1, .hw_val = 1 }, + { .pdiv = 2, .hw_val = 0 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { + {12000000, 480000000, 960, 12, 0, 12}, + {13000000, 480000000, 960, 13, 0, 12}, + {16800000, 480000000, 400, 7, 0, 5}, + {19200000, 480000000, 200, 4, 0, 3}, + {26000000, 480000000, 960, 26, 0, 12}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_u_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 480000000, + .vco_max = 960000000, + .base_reg = PLLU_BASE, + .misc_reg = PLLU_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, + .pdiv_tohw = pllu_p, +}; + +static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { + /* 1 GHz */ + {12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */ + {13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */ + {16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */ + {19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */ + {26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */ + + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_x_params = { + .input_min = 12000000, + .input_max = 800000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 700000000, + .vco_max = 2400000000U, + .base_reg = PLLX_BASE, + .misc_reg = PLLX_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLX_MISC3, + .iddq_bit_idx = PLLX_IDDQ_BIT, + .max_p = PLLXC_SW_MAX_P, + .dyn_ramp_reg = PLLX_MISC2, + .stepa_shift = 16, + .stepb_shift = 24, + .pdiv_tohw = pllxc_p, +}; + +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + {336000000, 100000000, 100, 21, 16, 11}, + {312000000, 100000000, 200, 26, 24, 13}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 75000000, + .vco_min = 1600000000, + .vco_max = 2400000000U, + .base_reg = PLLE_BASE, + .misc_reg = PLLE_MISC, + .aux_reg = PLLE_AUX, + .lock_mask = PLLE_MISC_LOCK, + .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + +static struct tegra_clk_pll_params pll_re_vco_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 300000000, + .vco_max = 600000000, + .base_reg = PLLRE_BASE, + .misc_reg = PLLRE_MISC, + .lock_mask = PLLRE_MISC_LOCK, + .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLRE_MISC, + .iddq_bit_idx = PLLRE_IDDQ_BIT, +}; + +/* 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, +}; + +/* possible OSC frequencies in Hz */ +static unsigned long tegra114_input_freq[] = { + [0] = 13000000, + [1] = 16800000, + [4] = 19200000, + [5] = 38400000, + [8] = 12000000, + [9] = 48000000, + [12] = 260000000, +}; + +#define MASK(x) (BIT(x) - 1) + +#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id, \ + _parents##_idx, 0) + +#define TEGRA_INIT_DATA_MUX_FLAGS(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _gate_flags, _clk_id, flags)\ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id, \ + _parents##_idx, flags) + +#define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 29, MASK(3), 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags, _clk_id, \ + _parents##_idx, 0) + +#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_INT_FLAGS(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _gate_flags, _clk_id, flags)\ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, flags) + +#define TEGRA_INIT_DATA_INT8(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs,\ + _clk_num, periph_clk_enb_refcnt, 0, _clk_id, \ + _parents##_idx, 0) + +#define TEGRA_INIT_DATA_I2C(_name, _con_id, _dev_id, _parents, _offset,\ + _clk_num, _regs, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + 30, MASK(2), 0, 0, 16, 0, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, 0, _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ + _mux_shift, _mux_mask, _clk_num, _regs, \ + _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ + _mux_shift, _mux_mask, 0, 0, 0, 0, 0, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_XUSB(_name, _con_id, _dev_id, _parents, _offset, \ + _clk_num, _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset, \ + 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ + _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + _clk_id, _parents##_idx, 0) + +#define TEGRA_INIT_DATA_AUDIO(_name, _con_id, _dev_id, _offset, _clk_num,\ + _regs, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, mux_d_audio_clk, \ + _offset, 16, 0xE01F, 0, 0, 8, 1, 0, _regs, _clk_num, \ + periph_clk_enb_refcnt, _gate_flags , _clk_id, \ + mux_d_audio_clk_idx, 0) + +enum tegra114_clk { + rtc = 4, timer = 5, uarta = 6, sdmmc2 = 9, i2s1 = 11, i2c1 = 12, + ndflash = 13, sdmmc1 = 14, sdmmc4 = 15, pwm = 17, i2s2 = 18, epp = 19, + gr_2d = 21, usbd = 22, isp = 23, gr_3d = 24, disp2 = 26, disp1 = 27, + host1x = 28, vcp = 29, i2s0 = 30, apbdma = 34, kbc = 36, kfuse = 40, + sbc1 = 41, nor = 42, sbc2 = 44, sbc3 = 46, i2c5 = 47, dsia = 48, + mipi = 50, hdmi = 51, csi = 52, i2c2 = 54, uartc = 55, mipi_cal = 56, + emc, usb2, usb3, vde = 61, bsea = 62, bsev = 63, uartd = 65, + i2c3 = 67, sbc4 = 68, sdmmc3 = 69, owr = 71, csite = 73, + la = 76, trace = 77, soc_therm = 78, dtv = 79, ndspeed = 80, + i2cslow = 81, dsib = 82, tsec = 83, xusb_host = 89, msenc = 91, + csus = 92, mselect = 99, tsensor = 100, i2s3 = 101, i2s4 = 102, + i2c4 = 103, sbc5 = 104, sbc6 = 105, d_audio, apbif = 107, dam0, dam1, + dam2, hda2codec_2x = 111, audio0_2x = 113, audio1_2x, audio2_2x, + audio3_2x, audio4_2x, spdif_2x, actmon = 119, extern1 = 120, + extern2 = 121, extern3 = 122, hda = 125, se = 127, hda2hdmi = 128, + cilab = 144, cilcd = 145, cile = 146, dsialp = 147, dsiblp = 148, + dds = 150, dp2 = 152, amx = 153, adx = 154, xusb_ss = 156, uartb = 192, + vfir, spdif_in, spdif_out, vi, vi_sensor, fuse, fuse_burn, clk_32k, + clk_m, clk_m_div2, clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_c2, + pll_c3, 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_u_480M, pll_u_60M, pll_u_48M, pll_u_12M, pll_x, pll_x_out0, + pll_re_vco, pll_re_out, pll_e_out0, 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, + blink, xusb_host_src = 252, xusb_falcon_src, xusb_fs_src, xusb_ss_src, + xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp, + + /* Mux clocks */ + + audio0_mux = 300, audio1_mux, audio2_mux, audio3_mux, audio4_mux, + spdif_mux, clk_out_1_mux, clk_out_2_mux, clk_out_3_mux, dsia_mux, + dsib_mux, clk_max, +}; + +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}, +}; + +/* peripheral mux definitions */ + +#define MUX_I2S_SPDIF(_id) \ +static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \ + #_id, "pll_p",\ + "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(audio) + +#define mux_pllaout0_audio0_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio1_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio2_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio3_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio4_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio_2x_pllp_clkm_idx NULL + +static const char *mux_pllp_pllc_pllm_clkm[] = { + "pll_p", "pll_c", "pll_m", "clk_m" +}; +#define mux_pllp_pllc_pllm_clkm_idx NULL + +static const char *mux_pllp_pllc_pllm[] = { "pll_p", "pll_c", "pll_m" }; +#define mux_pllp_pllc_pllm_idx NULL + +static const char *mux_pllp_pllc_clk32_clkm[] = { + "pll_p", "pll_c", "clk_32k", "clk_m" +}; +#define mux_pllp_pllc_clk32_clkm_idx NULL + +static const char *mux_plla_pllc_pllp_clkm[] = { + "pll_a_out0", "pll_c", "pll_p", "clk_m" +}; +#define mux_plla_pllc_pllp_clkm_idx mux_pllp_pllc_pllm_clkm_idx + +static const char *mux_pllp_pllc2_c_c3_pllm_clkm[] = { + "pll_p", "pll_c2", "pll_c", "pll_c3", "pll_m", "clk_m" +}; +static u32 mux_pllp_pllc2_c_c3_pllm_clkm_idx[] = { + [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, +}; + +static const char *mux_pllp_clkm[] = { + "pll_p", "clk_m" +}; +static u32 mux_pllp_clkm_idx[] = { + [0] = 0, [1] = 3, +}; + +static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = { + "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0" +}; +#define mux_pllm_pllc2_c_c3_pllp_plla_idx mux_pllp_pllc2_c_c3_pllm_clkm_idx + +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" +}; +#define mux_pllp_pllm_plld_plla_pllc_plld2_clkm_idx NULL + +static const char *mux_pllm_pllc_pllp_plla[] = { + "pll_m", "pll_c", "pll_p", "pll_a_out0" +}; +#define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx + +static const char *mux_pllp_pllc_clkm[] = { + "pll_p", "pll_c", "pll_m" +}; +static u32 mux_pllp_pllc_clkm_idx[] = { + [0] = 0, [1] = 1, [2] = 3, +}; + +static const char *mux_pllp_pllc_clkm_clk32[] = { + "pll_p", "pll_c", "clk_m", "clk_32k" +}; +#define mux_pllp_pllc_clkm_clk32_idx NULL + +static const char *mux_plla_clk32_pllp_clkm_plle[] = { + "pll_a_out0", "clk_32k", "pll_p", "clk_m", "pll_e_out0" +}; +#define mux_plla_clk32_pllp_clkm_plle_idx NULL + +static const char *mux_clkm_pllp_pllc_pllre[] = { + "clk_m", "pll_p", "pll_c", "pll_re_out" +}; +static u32 mux_clkm_pllp_pllc_pllre_idx[] = { + [0] = 0, [1] = 1, [2] = 3, [3] = 5, +}; + +static const char *mux_clkm_48M_pllp_480M[] = { + "clk_m", "pll_u_48M", "pll_p", "pll_u_480M" +}; +#define mux_clkm_48M_pllp_480M_idx NULL + +static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = { + "clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref" +}; +static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = { + [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7, +}; + +static const char *mux_plld_out0_plld2_out0[] = { + "pll_d_out0", "pll_d2_out0", +}; +#define mux_plld_out0_plld2_out0_idx NULL + +static const char *mux_d_audio_clk[] = { + "pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync", + "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", +}; +static u32 mux_d_audio_clk_idx[] = { + [0] = 0, [1] = 0x8000, [2] = 0xc000, [3] = 0xE000, [4] = 0xE001, + [5] = 0xE002, [6] = 0xE003, [7] = 0xE004, [8] = 0xE005, [9] = 0xE007, +}; + +static const char *mux_pllmcp_clkm[] = { + "pll_m_out0", "pll_c_out0", "pll_p_out0", "clk_m", "pll_m_ud", +}; + +static const struct clk_div_table pll_re_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { .val = 4, .div = 5 }, + { .val = 5, .div = 6 }, + { .val = 0, .div = 0 }, +}; + +static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; + +static unsigned long osc_freq; +static unsigned long pll_ref_freq; + +static int __init tegra114_osc_clk_init(void __iomem *clk_base) +{ + struct clk *clk; + u32 val, pll_ref_div; + + val = readl_relaxed(clk_base + OSC_CTRL); + + osc_freq = tegra114_input_freq[val >> OSC_CTRL_OSC_FREQ_SHIFT]; + if (!osc_freq) { + WARN_ON(1); + return -EINVAL; + } + + /* clk_m */ + clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, + osc_freq); + clk_register_clkdev(clk, "clk_m", NULL); + clks[clk_m] = clk; + + /* pll_ref */ + val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; + pll_ref_div = 1 << val; + 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; + + pll_ref_freq = osc_freq / pll_ref_div; + + return 0; +} + +static void __init tegra114_fixed_clk_init(void __iomem *clk_base) +{ + 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; + +} + +static __init void tegra114_utmi_param_configure(void __iomem *clk_base) +{ + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { + if (osc_freq == utmi_parameters[i].osc_frequency) + break; + } + + if (i >= ARRAY_SIZE(utmi_parameters)) { + pr_err("%s: Unexpected oscillator freq %lu\n", __func__, + osc_freq); + return; + } + + reg = readl_relaxed(clk_base + 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; + + 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_POWERUP; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); + + /* Setup HW control of UTMIPLL */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET; + reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL; + reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); + + udelay(1); + + /* Setup SW override of UTMIPLL assuming USB2.0 + ports are assigned to USB2 */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL; + reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); + + udelay(1); + + /* Enable HW control UTMIPLL */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); +} + +static void __init _clip_vco_min(struct tegra_clk_pll_params *pll_params) +{ + pll_params->vco_min = + DIV_ROUND_UP(pll_params->vco_min, pll_ref_freq) * pll_ref_freq; +} + +static int __init _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params, + void __iomem *clk_base) +{ + u32 val; + u32 step_a, step_b; + + switch (pll_ref_freq) { + case 12000000: + case 13000000: + case 26000000: + step_a = 0x2B; + step_b = 0x0B; + break; + case 16800000: + step_a = 0x1A; + step_b = 0x09; + break; + case 19200000: + step_a = 0x12; + step_b = 0x08; + break; + default: + pr_err("%s: Unexpected reference rate %lu\n", + __func__, pll_ref_freq); + WARN_ON(1); + return -EINVAL; + } + + val = step_a << pll_params->stepa_shift; + val |= step_b << pll_params->stepb_shift; + writel_relaxed(val, clk_base + pll_params->dyn_ramp_reg); + + return 0; +} + +static void __init _init_iddq(struct tegra_clk_pll_params *pll_params, + void __iomem *clk_base) +{ + u32 val, val_iddq; + + val = readl_relaxed(clk_base + pll_params->base_reg); + val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg); + + if (val & BIT(30)) + WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx)); + else { + val_iddq |= BIT(pll_params->iddq_bit_idx); + writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg); + } +} + +static void __init tegra114_pll_init(void __iomem *clk_base, + void __iomem *pmc) +{ + u32 val; + struct clk *clk; + + /* PLLC */ + _clip_vco_min(&pll_c_params); + if (_setup_dynamic_ramp(&pll_c_params, clk_base) >= 0) { + _init_iddq(&pll_c_params, clk_base); + clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base, + pmc, 0, 0, &pll_c_params, 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; + } + + /* PLLC2 */ + _clip_vco_min(&pll_c2_params); + clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, 0, + &pll_c2_params, TEGRA_PLL_USE_LOCK, + pll_cx_freq_table, NULL); + clk_register_clkdev(clk, "pll_c2", NULL); + clks[pll_c2] = clk; + + /* PLLC3 */ + _clip_vco_min(&pll_c3_params); + clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, 0, + &pll_c3_params, TEGRA_PLL_USE_LOCK, + pll_cx_freq_table, NULL); + clk_register_clkdev(clk, "pll_c3", NULL); + clks[pll_c3] = clk; + + /* PLLP */ + clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc, 0, + 408000000, &pll_p_params, + TEGRA_PLL_FIXED | 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 */ + _clip_vco_min(&pll_m_params); + clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, + &pll_m_params, 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; + + /* PLLM_UD */ + clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", + CLK_SET_RATE_PARENT, 1, 1); + + /* PLLX */ + _clip_vco_min(&pll_x_params); + if (_setup_dynamic_ramp(&pll_x_params, clk_base) >= 0) { + _init_iddq(&pll_x_params, clk_base); + clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, + pmc, CLK_IGNORE_UNUSED, 0, &pll_x_params, + 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 */ + val = readl(clk_base + pll_u_params.base_reg); + val &= ~BIT(24); /* disable PLLU_OVERRIDE */ + writel(val, clk_base + pll_u_params.base_reg); + + clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc, 0, + 0, &pll_u_params, TEGRA_PLLU | + TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, pll_u_freq_table, &pll_u_lock); + clk_register_clkdev(clk, "pll_u", NULL); + clks[pll_u] = clk; + + tegra114_utmi_param_configure(clk_base); + + /* PLLU_480M */ + clk = clk_register_gate(NULL, "pll_u_480M", "pll_u", + CLK_SET_RATE_PARENT, clk_base + PLLU_BASE, + 22, 0, &pll_u_lock); + clk_register_clkdev(clk, "pll_u_480M", NULL); + clks[pll_u_480M] = clk; + + /* PLLU_60M */ + clk = clk_register_fixed_factor(NULL, "pll_u_60M", "pll_u", + CLK_SET_RATE_PARENT, 1, 8); + clk_register_clkdev(clk, "pll_u_60M", NULL); + clks[pll_u_60M] = clk; + + /* PLLU_48M */ + clk = clk_register_fixed_factor(NULL, "pll_u_48M", "pll_u", + CLK_SET_RATE_PARENT, 1, 10); + clk_register_clkdev(clk, "pll_u_48M", NULL); + clks[pll_u_48M] = clk; + + /* PLLU_12M */ + clk = clk_register_fixed_factor(NULL, "pll_u_12M", "pll_u", + CLK_SET_RATE_PARENT, 1, 40); + clk_register_clkdev(clk, "pll_u_12M", NULL); + clks[pll_u_12M] = clk; + + /* PLLD */ + clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 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, 0, + 0, &pll_d2_params, + TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, pll_d_freq_table, &pll_d2_lock); + 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, 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; + + /* PLLRE */ + _clip_vco_min(&pll_re_vco_params); + clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, + 0, 0, &pll_re_vco_params, TEGRA_PLL_USE_LOCK, + NULL, &pll_re_lock, pll_ref_freq); + clk_register_clkdev(clk, "pll_re_vco", NULL); + clks[pll_re_vco] = clk; + + clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0, + clk_base + PLLRE_BASE, 16, 4, 0, + pll_re_div_table, &pll_re_lock); + clk_register_clkdev(clk, "pll_re_out", NULL); + clks[pll_re_out] = clk; + + /* PLLE */ + clk = tegra_clk_register_plle_tegra114("pll_e_out0", "pll_re_vco", + clk_base, 0, 100000000, &pll_e_params, + pll_e_freq_table, NULL); + clk_register_clkdev(clk, "pll_e_out0", NULL); + clks[pll_e_out0] = 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 tegra114_audio_clk_init(void __iomem *clk_base) +{ + 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); + clks[audio0_mux] = clk; + 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); + clks[audio1_mux] = clk; + 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); + clks[audio2_mux] = clk; + 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); + clks[audio3_mux] = clk; + 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); + clks[audio4_mux] = clk; + 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); + clks[spdif_mux] = clk; + 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 tegra114_pmc_clk_init(void __iomem *pmc_base) +{ + 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); + clks[clk_out_2_mux] = clk; + 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); + clks[clk_out_3_mux] = clk; + 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 */ + 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 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 const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p", "pll_p_out4", "unused", + "unused", "pll_x" }; + +static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p", "pll_p_out4", "unused", + "unused", "pll_x", "pll_x_out0" }; + +static void __init tegra114_super_clk_init(void __iomem *clk_base) +{ + struct clk *clk; + + /* 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; + + /* 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, + 0, 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, + &sysrate_lock); + clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT | + CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, + 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); + 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, + &sysrate_lock); + clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT | + CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, + 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); + clk_register_clkdev(clk, "pclk", NULL); + clks[pclk] = clk; +} + +static struct tegra_periph_init_data tegra_periph_clk_list[] = { + TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0), + TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), + TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", mux_pllaout0_audio2_2x_pllp_clkm, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), + TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", mux_pllaout0_audio3_2x_pllp_clkm, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3), + TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4), + TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), + TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), + TEGRA_INIT_DATA_MUX("pwm", NULL, "pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, &periph_l_regs, TEGRA_PERIPH_ON_APB, pwm), + TEGRA_INIT_DATA_MUX("adx", NULL, "adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, &periph_w_regs, TEGRA_PERIPH_ON_APB, adx), + TEGRA_INIT_DATA_MUX("amx", NULL, "amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, &periph_w_regs, TEGRA_PERIPH_ON_APB, amx), + TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, TEGRA_PERIPH_ON_APB, hda), + TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, TEGRA_PERIPH_ON_APB, hda2codec_2x), + TEGRA_INIT_DATA_MUX("sbc1", NULL, "tegra11-spi.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), + TEGRA_INIT_DATA_MUX("sbc2", NULL, "tegra11-spi.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), + TEGRA_INIT_DATA_MUX("sbc3", NULL, "tegra11-spi.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), + TEGRA_INIT_DATA_MUX("sbc4", NULL, "tegra11-spi.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), + TEGRA_INIT_DATA_MUX("sbc5", NULL, "tegra11-spi.4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5), + TEGRA_INIT_DATA_MUX("sbc6", NULL, "tegra11-spi.5", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6), + TEGRA_INIT_DATA_MUX8("ndflash", NULL, "tegra_nand", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), + TEGRA_INIT_DATA_MUX8("ndspeed", NULL, "tegra_nand_speed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), + TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), + TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), + TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), + TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), + TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), + TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), + TEGRA_INIT_DATA_MUX_FLAGS("csite", NULL, "csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite, CLK_IGNORE_UNUSED), + TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la), + TEGRA_INIT_DATA_MUX("trace", NULL, "trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, &periph_u_regs, TEGRA_PERIPH_ON_APB, trace), + TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), + TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), + TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), + TEGRA_INIT_DATA_I2C("i2c1", "div-clk", "tegra11-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, i2c1), + TEGRA_INIT_DATA_I2C("i2c2", "div-clk", "tegra11-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, i2c2), + TEGRA_INIT_DATA_I2C("i2c3", "div-clk", "tegra11-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, i2c3), + TEGRA_INIT_DATA_I2C("i2c4", "div-clk", "tegra11-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, i2c4), + TEGRA_INIT_DATA_I2C("i2c5", "div-clk", "tegra11-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, i2c5), + TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta), + TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb), + TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc), + TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd), + TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, &periph_l_regs, 0, gr_3d), + TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr_2d), + TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), + TEGRA_INIT_DATA_INT8("vi", "vi", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), + TEGRA_INIT_DATA_INT8("epp", NULL, "epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), + TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_h_regs, TEGRA_PERIPH_WAR_1005168, msenc), + TEGRA_INIT_DATA_INT8("tsec", NULL, "tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, &periph_u_regs, 0, tsec), + TEGRA_INIT_DATA_INT8("host1x", NULL, "host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), + TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), + TEGRA_INIT_DATA_MUX("cilab", "cilab", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, &periph_w_regs, 0, cilab), + TEGRA_INIT_DATA_MUX("cilcd", "cilcd", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, &periph_w_regs, 0, cilcd), + TEGRA_INIT_DATA_MUX("cile", "cile", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, &periph_w_regs, 0, cile), + TEGRA_INIT_DATA_MUX("dsialp", "dsialp", "tegradc.0", mux_pllp_pllc_clkm, CLK_SOURCE_DSIALP, 147, &periph_w_regs, 0, dsialp), + TEGRA_INIT_DATA_MUX("dsiblp", "dsiblp", "tegradc.1", mux_pllp_pllc_clkm, CLK_SOURCE_DSIBLP, 148, &periph_w_regs, 0, dsiblp), + TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllp_pllc_clkm_clk32, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor), + TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon), + TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1), + TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2), + TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3), + TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow), + TEGRA_INIT_DATA_INT8("se", NULL, "se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, TEGRA_PERIPH_ON_APB, se), + TEGRA_INIT_DATA_INT_FLAGS("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect, CLK_IGNORE_UNUSED), + TEGRA_INIT_DATA_MUX8("soc_therm", NULL, "soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, &periph_u_regs, TEGRA_PERIPH_ON_APB, soc_therm), + TEGRA_INIT_DATA_XUSB("xusb_host_src", "host_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, &periph_w_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_host_src), + TEGRA_INIT_DATA_XUSB("xusb_falcon_src", "falcon_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_falcon_src), + TEGRA_INIT_DATA_XUSB("xusb_fs_src", "fs_src", "tegra_xhci", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_fs_src), + TEGRA_INIT_DATA_XUSB("xusb_ss_src", "ss_src", "tegra_xhci", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_ss_src), + TEGRA_INIT_DATA_XUSB("xusb_dev_src", "dev_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, &periph_u_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_dev_src), + TEGRA_INIT_DATA_AUDIO("d_audio", "d_audio", "tegra30-ahub", CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, TEGRA_PERIPH_ON_APB, d_audio), + TEGRA_INIT_DATA_AUDIO("dam0", NULL, "tegra30-dam.0", CLK_SOURCE_DAM0, 108, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam0), + TEGRA_INIT_DATA_AUDIO("dam1", NULL, "tegra30-dam.1", CLK_SOURCE_DAM1, 109, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam1), + TEGRA_INIT_DATA_AUDIO("dam2", NULL, "tegra30-dam.2", CLK_SOURCE_DAM2, 110, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam2), +}; + +static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { + TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, &periph_l_regs, 0, disp1), + TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, &periph_l_regs, 0, disp2), +}; + +static __init void tegra114_periph_clk_init(void __iomem *clk_base) +{ + struct tegra_periph_init_data *data; + struct clk *clk; + int i; + u32 val; + + /* apbdma */ + clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base, + 0, 34, &periph_h_regs, + periph_clk_enb_refcnt); + clks[apbdma] = clk; + + /* rtc */ + clk = tegra_clk_register_periph_gate("rtc", "clk_32k", + TEGRA_PERIPH_ON_APB | + 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; + + /* kbc */ + clk = tegra_clk_register_periph_gate("kbc", "clk_32k", + TEGRA_PERIPH_ON_APB | + TEGRA_PERIPH_NO_RESET, clk_base, + 0, 36, &periph_h_regs, + periph_clk_enb_refcnt); + clks[kbc] = 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; + + /* 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); + 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); + 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); + clks[fuse_burn] = clk; + + /* apbif */ + clk = tegra_clk_register_periph_gate("apbif", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 107, + &periph_v_regs, periph_clk_enb_refcnt); + 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); + clks[hda2hdmi] = clk; + + /* vcp */ + clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0, + 29, &periph_l_regs, + periph_clk_enb_refcnt); + 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); + 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); + clks[bsev] = clk; + + /* mipi-cal */ + clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base, + 0, 56, &periph_h_regs, + periph_clk_enb_refcnt); + clks[mipi_cal] = clk; + + /* usbd */ + clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, + 0, 22, &periph_l_regs, + periph_clk_enb_refcnt); + 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); + 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); + clks[usb3] = clk; + + /* csi */ + clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, + 0, 52, &periph_h_regs, + periph_clk_enb_refcnt); + 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); + clks[isp] = 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); + clks[csus] = clk; + + /* dds */ + clk = tegra_clk_register_periph_gate("dds", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 150, + &periph_w_regs, periph_clk_enb_refcnt); + clks[dds] = clk; + + /* dp2 */ + clk = tegra_clk_register_periph_gate("dp2", "clk_m", + TEGRA_PERIPH_ON_APB, clk_base, 0, 152, + &periph_w_regs, periph_clk_enb_refcnt); + clks[dp2] = 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); + clks[dtv] = clk; + + /* dsia */ + clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, + clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock); + clks[dsia_mux] = clk; + clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base, + 0, 48, &periph_h_regs, + periph_clk_enb_refcnt); + clks[dsia] = clk; + + /* dsib */ + clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0, + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, + clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock); + clks[dsib_mux] = clk; + clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base, + 0, 82, &periph_u_regs, + periph_clk_enb_refcnt); + clks[dsib] = clk; + + /* xusb_hs_src */ + val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC); + val |= BIT(25); /* always select PLLU_60M */ + writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC); + + clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, + 1, 1); + clks[xusb_hs_src] = clk; + + /* xusb_host */ + clk = tegra_clk_register_periph_gate("xusb_host", "xusb_host_src", 0, + clk_base, 0, 89, &periph_u_regs, + periph_clk_enb_refcnt); + clks[xusb_host] = clk; + + /* xusb_ss */ + clk = tegra_clk_register_periph_gate("xusb_ss", "xusb_ss_src", 0, + clk_base, 0, 156, &periph_w_regs, + periph_clk_enb_refcnt); + clks[xusb_host] = clk; + + /* xusb_dev */ + clk = tegra_clk_register_periph_gate("xusb_dev", "xusb_dev_src", 0, + clk_base, 0, 95, &periph_u_regs, + periph_clk_enb_refcnt); + clks[xusb_dev] = clk; + + /* emc */ + clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, + ARRAY_SIZE(mux_pllmcp_clkm), 0, + clk_base + CLK_SOURCE_EMC, + 29, 3, 0, NULL); + clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, + CLK_IGNORE_UNUSED, 57, &periph_h_regs, + periph_clk_enb_refcnt); + 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, data->flags); + 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); + clks[data->clk_id] = clk; + } +} + +static struct tegra_cpu_car_ops tegra114_cpu_car_ops; + +static const struct of_device_id pmc_match[] __initconst = { + { .compatible = "nvidia,tegra114-pmc" }, + {}, +}; + +static __initdata struct tegra_clk_init_table init_table[] = { + {uarta, pll_p, 408000000, 0}, + {uartb, pll_p, 408000000, 0}, + {uartc, pll_p, 408000000, 0}, + {uartd, pll_p, 408000000, 0}, + {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, 1}, + {clk_out_1, 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}, + {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ +}; + +static void __init tegra114_clock_apply_init_table(void) +{ + tegra_init_from_table(init_table, clks, clk_max); +} + +void __init tegra114_clock_init(struct device_node *np) +{ + struct device_node *node; + int i; + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("ioremap tegra114 CAR failed\n"); + return; + } + + node = of_find_matching_node(NULL, pmc_match); + if (!node) { + pr_err("Failed to find pmc node\n"); + WARN_ON(1); + return; + } + + pmc_base = of_iomap(node, 0); + if (!pmc_base) { + pr_err("Can't map pmc registers\n"); + WARN_ON(1); + return; + } + + if (tegra114_osc_clk_init(clk_base) < 0) + return; + + tegra114_fixed_clk_init(clk_base); + tegra114_pll_init(clk_base, pmc_base); + tegra114_periph_clk_init(clk_base); + tegra114_audio_clk_init(clk_base); + tegra114_pmc_clk_init(pmc_base); + tegra114_super_clk_init(clk_base); + + for (i = 0; i < ARRAY_SIZE(clks); i++) { + if (IS_ERR(clks[i])) { + pr_err + ("Tegra114 clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + } + if (!clks[i]) + clks[i] = ERR_PTR(-EINVAL); + } + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + tegra_clk_apply_init_table = tegra114_clock_apply_init_table; + + tegra_cpu_car_ops = &tegra114_cpu_car_ops; +} diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 1e2de7305362..b0405b67f49c 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -86,8 +86,8 @@ #define PLLE_BASE 0xe8 #define PLLE_MISC 0xec -#define PLL_BASE_LOCK 27 -#define PLLE_MISC_LOCK 11 +#define PLL_BASE_LOCK BIT(27) +#define PLLE_MISC_LOCK BIT(11) #define PLL_MISC_LOCK_ENABLE 18 #define PLLDU_MISC_LOCK_ENABLE 22 @@ -236,7 +236,7 @@ enum tegra20_clk { 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, + iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev2, cdev1, 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, @@ -248,125 +248,125 @@ 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 }, + { 12000000, 600000000, 600, 12, 0, 8 }, + { 13000000, 600000000, 600, 13, 0, 8 }, + { 19200000, 600000000, 500, 16, 0, 6 }, + { 26000000, 600000000, 600, 26, 0, 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}, + { 12000000, 666000000, 666, 12, 0, 8}, + { 13000000, 666000000, 666, 13, 0, 8}, + { 19200000, 666000000, 555, 16, 0, 8}, + { 26000000, 666000000, 666, 26, 0, 8}, + { 12000000, 600000000, 600, 12, 0, 8}, + { 13000000, 600000000, 600, 13, 0, 8}, + { 19200000, 600000000, 375, 12, 0, 6}, + { 26000000, 600000000, 600, 26, 0, 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}, + { 12000000, 216000000, 432, 12, 1, 8}, + { 13000000, 216000000, 432, 13, 1, 8}, + { 19200000, 216000000, 90, 4, 1, 1}, + { 26000000, 216000000, 432, 26, 1, 8}, + { 12000000, 432000000, 432, 12, 0, 8}, + { 13000000, 432000000, 432, 13, 0, 8}, + { 19200000, 432000000, 90, 4, 0, 1}, + { 26000000, 432000000, 432, 26, 0, 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}, + { 28800000, 56448000, 49, 25, 0, 1}, + { 28800000, 73728000, 64, 25, 0, 1}, + { 28800000, 24000000, 5, 6, 0, 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, 216000000, 216, 12, 0, 4}, + { 13000000, 216000000, 216, 13, 0, 4}, + { 19200000, 216000000, 135, 12, 0, 3}, + { 26000000, 216000000, 216, 26, 0, 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, 594000000, 594, 12, 0, 8}, + { 13000000, 594000000, 594, 13, 0, 8}, + { 19200000, 594000000, 495, 16, 0, 8}, + { 26000000, 594000000, 594, 26, 0, 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}, + { 12000000, 1000000000, 1000, 12, 0, 12}, + { 13000000, 1000000000, 1000, 13, 0, 12}, + { 19200000, 1000000000, 625, 12, 0, 8}, + { 26000000, 1000000000, 1000, 26, 0, 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}, + { 12000000, 480000000, 960, 12, 0, 0}, + { 13000000, 480000000, 960, 13, 0, 0}, + { 19200000, 480000000, 200, 4, 0, 0}, + { 26000000, 480000000, 960, 26, 0, 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}, + { 12000000, 1000000000, 1000, 12, 0, 12}, + { 13000000, 1000000000, 1000, 13, 0, 12}, + { 19200000, 1000000000, 625, 12, 0, 8}, + { 26000000, 1000000000, 1000, 26, 0, 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}, + { 12000000, 912000000, 912, 12, 0, 12}, + { 13000000, 912000000, 912, 13, 0, 12}, + { 19200000, 912000000, 760, 16, 0, 8}, + { 26000000, 912000000, 912, 26, 0, 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}, + { 12000000, 816000000, 816, 12, 0, 12}, + { 13000000, 816000000, 816, 13, 0, 12}, + { 19200000, 816000000, 680, 16, 0, 8}, + { 26000000, 816000000, 816, 26, 0, 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}, + { 12000000, 760000000, 760, 12, 0, 12}, + { 13000000, 760000000, 760, 13, 0, 12}, + { 19200000, 760000000, 950, 24, 0, 8}, + { 26000000, 760000000, 760, 26, 0, 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}, + { 12000000, 750000000, 750, 12, 0, 12}, + { 13000000, 750000000, 750, 13, 0, 12}, + { 19200000, 750000000, 625, 16, 0, 8}, + { 26000000, 750000000, 750, 26, 0, 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}, + { 12000000, 608000000, 608, 12, 0, 12}, + { 13000000, 608000000, 608, 13, 0, 12}, + { 19200000, 608000000, 380, 12, 0, 8}, + { 26000000, 608000000, 608, 26, 0, 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}, + { 12000000, 456000000, 456, 12, 0, 12}, + { 13000000, 456000000, 456, 13, 0, 12}, + { 19200000, 456000000, 380, 16, 0, 8}, + { 26000000, 456000000, 456, 26, 0, 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}, + { 12000000, 312000000, 312, 12, 0, 12}, + { 13000000, 312000000, 312, 13, 0, 12}, + { 19200000, 312000000, 260, 16, 0, 8}, + { 26000000, 312000000, 312, 26, 0, 12}, { 0, 0, 0, 0, 0, 0 }, }; static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { - { 12000000, 100000000, 200, 24, 1, 0 }, + { 12000000, 100000000, 200, 24, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, }; @@ -380,7 +380,7 @@ static struct tegra_clk_pll_params pll_c_params = { .vco_max = 1400000000, .base_reg = PLLC_BASE, .misc_reg = PLLC_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -394,7 +394,7 @@ static struct tegra_clk_pll_params pll_m_params = { .vco_max = 1200000000, .base_reg = PLLM_BASE, .misc_reg = PLLM_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -408,7 +408,7 @@ static struct tegra_clk_pll_params pll_p_params = { .vco_max = 1400000000, .base_reg = PLLP_BASE, .misc_reg = PLLP_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -422,7 +422,7 @@ static struct tegra_clk_pll_params pll_a_params = { .vco_max = 1400000000, .base_reg = PLLA_BASE, .misc_reg = PLLA_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -436,11 +436,17 @@ static struct tegra_clk_pll_params pll_d_params = { .vco_max = 1000000000, .base_reg = PLLD_BASE, .misc_reg = PLLD_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, }; +static struct pdiv_map pllu_p[] = { + { .pdiv = 1, .hw_val = 1 }, + { .pdiv = 2, .hw_val = 0 }, + { .pdiv = 0, .hw_val = 0 }, +}; + static struct tegra_clk_pll_params pll_u_params = { .input_min = 2000000, .input_max = 40000000, @@ -450,9 +456,10 @@ static struct tegra_clk_pll_params pll_u_params = { .vco_max = 960000000, .base_reg = PLLU_BASE, .misc_reg = PLLU_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, + .pdiv_tohw = pllu_p, }; static struct tegra_clk_pll_params pll_x_params = { @@ -464,7 +471,7 @@ static struct tegra_clk_pll_params pll_x_params = { .vco_max = 1200000000, .base_reg = PLLX_BASE, .misc_reg = PLLX_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -478,7 +485,7 @@ static struct tegra_clk_pll_params pll_e_params = { .vco_max = 0, .base_reg = PLLE_BASE, .misc_reg = PLLE_MISC, - .lock_bit_idx = PLLE_MISC_LOCK, + .lock_mask = PLLE_MISC_LOCK, .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, .lock_delay = 0, }; @@ -711,8 +718,8 @@ static void tegra20_pll_init(void) } 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" }; + "pll_p", "pll_p_out4", + "pll_p_out3", "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" }; @@ -721,38 +728,6 @@ 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, @@ -1044,7 +1019,7 @@ static void __init tegra20_periph_clk_init(void) 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_base, data->offset, data->flags); clk_register_clkdev(clk, data->con_id, data->dev_id); clks[data->clk_id] = clk; } @@ -1279,9 +1254,16 @@ static __initdata struct tegra_clk_init_table init_table[] = { {host1x, pll_c, 150000000, 0}, {disp1, pll_p, 600000000, 0}, {disp2, pll_p, 600000000, 0}, + {gr2d, pll_c, 300000000, 0}, + {gr3d, pll_c, 300000000, 0}, {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */ }; +static void __init tegra20_clock_apply_init_table(void) +{ + tegra_init_from_table(init_table, clks, clk_max); +} + /* * Some clocks may be used by different drivers depending on the board * configuration. List those here to register them twice in the clock lookup @@ -1348,7 +1330,7 @@ void __init tegra20_clock_init(struct device_node *np) 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_clk_apply_init_table = tegra20_clock_apply_init_table; tegra_cpu_car_ops = &tegra20_cpu_car_ops; } diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index ba6f51bc9f3b..2dc0c5602613 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -116,8 +116,8 @@ #define PLLDU_MISC_LOCK_ENABLE 22 #define PLLE_MISC_LOCK_ENABLE 9 -#define PLL_BASE_LOCK 27 -#define PLLE_MISC_LOCK 11 +#define PLL_BASE_LOCK BIT(27) +#define PLLE_MISC_LOCK BIT(11) #define PLLE_AUX 0x48c #define PLLC_OUT 0x84 @@ -330,7 +330,7 @@ enum tegra30_clk { usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2cslow, dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92, - cdev1, cdev2, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4, + cdev2, cdev1, 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, @@ -374,164 +374,170 @@ static const struct utmi_clk_param utmi_parameters[] = { }; 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}, + { 12000000, 1040000000, 520, 6, 0, 8}, + { 13000000, 1040000000, 480, 6, 0, 8}, + { 16800000, 1040000000, 495, 8, 0, 8}, /* actual: 1039.5 MHz */ + { 19200000, 1040000000, 325, 6, 0, 6}, + { 26000000, 1040000000, 520, 13, 0, 8}, + + { 12000000, 832000000, 416, 6, 0, 8}, + { 13000000, 832000000, 832, 13, 0, 8}, + { 16800000, 832000000, 396, 8, 0, 8}, /* actual: 831.6 MHz */ + { 19200000, 832000000, 260, 6, 0, 8}, + { 26000000, 832000000, 416, 13, 0, 8}, + + { 12000000, 624000000, 624, 12, 0, 8}, + { 13000000, 624000000, 624, 13, 0, 8}, + { 16800000, 600000000, 520, 14, 0, 8}, + { 19200000, 624000000, 520, 16, 0, 8}, + { 26000000, 624000000, 624, 26, 0, 8}, + + { 12000000, 600000000, 600, 12, 0, 8}, + { 13000000, 600000000, 600, 13, 0, 8}, + { 16800000, 600000000, 500, 14, 0, 8}, + { 19200000, 600000000, 375, 12, 0, 6}, + { 26000000, 600000000, 600, 26, 0, 8}, + + { 12000000, 520000000, 520, 12, 0, 8}, + { 13000000, 520000000, 520, 13, 0, 8}, + { 16800000, 520000000, 495, 16, 0, 8}, /* actual: 519.75 MHz */ + { 19200000, 520000000, 325, 12, 0, 6}, + { 26000000, 520000000, 520, 26, 0, 8}, + + { 12000000, 416000000, 416, 12, 0, 8}, + { 13000000, 416000000, 416, 13, 0, 8}, + { 16800000, 416000000, 396, 16, 0, 8}, /* actual: 415.8 MHz */ + { 19200000, 416000000, 260, 12, 0, 6}, + { 26000000, 416000000, 416, 26, 0, 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}, + { 12000000, 666000000, 666, 12, 0, 8}, + { 13000000, 666000000, 666, 13, 0, 8}, + { 16800000, 666000000, 555, 14, 0, 8}, + { 19200000, 666000000, 555, 16, 0, 8}, + { 26000000, 666000000, 666, 26, 0, 8}, + { 12000000, 600000000, 600, 12, 0, 8}, + { 13000000, 600000000, 600, 13, 0, 8}, + { 16800000, 600000000, 500, 14, 0, 8}, + { 19200000, 600000000, 375, 12, 0, 6}, + { 26000000, 600000000, 600, 26, 0, 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}, + { 12000000, 216000000, 432, 12, 1, 8}, + { 13000000, 216000000, 432, 13, 1, 8}, + { 16800000, 216000000, 360, 14, 1, 8}, + { 19200000, 216000000, 360, 16, 1, 8}, + { 26000000, 216000000, 432, 26, 1, 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}, + { 9600000, 564480000, 294, 5, 0, 4}, + { 9600000, 552960000, 288, 5, 0, 4}, + { 9600000, 24000000, 5, 2, 0, 1}, - { 28800000, 56448000, 49, 25, 1, 1}, - { 28800000, 73728000, 64, 25, 1, 1}, - { 28800000, 24000000, 5, 6, 1, 1}, + { 28800000, 56448000, 49, 25, 0, 1}, + { 28800000, 73728000, 64, 25, 0, 1}, + { 28800000, 24000000, 5, 6, 0, 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}, + { 12000000, 216000000, 216, 12, 0, 4}, + { 13000000, 216000000, 216, 13, 0, 4}, + { 16800000, 216000000, 180, 14, 0, 4}, + { 19200000, 216000000, 180, 16, 0, 4}, + { 26000000, 216000000, 216, 26, 0, 4}, + + { 12000000, 594000000, 594, 12, 0, 8}, + { 13000000, 594000000, 594, 13, 0, 8}, + { 16800000, 594000000, 495, 14, 0, 8}, + { 19200000, 594000000, 495, 16, 0, 8}, + { 26000000, 594000000, 594, 26, 0, 8}, + + { 12000000, 1000000000, 1000, 12, 0, 12}, + { 13000000, 1000000000, 1000, 13, 0, 12}, + { 19200000, 1000000000, 625, 12, 0, 8}, + { 26000000, 1000000000, 1000, 26, 0, 12}, { 0, 0, 0, 0, 0, 0 }, }; +static struct pdiv_map pllu_p[] = { + { .pdiv = 1, .hw_val = 1 }, + { .pdiv = 2, .hw_val = 0 }, + { .pdiv = 0, .hw_val = 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}, + { 12000000, 480000000, 960, 12, 0, 12}, + { 13000000, 480000000, 960, 13, 0, 12}, + { 16800000, 480000000, 400, 7, 0, 5}, + { 19200000, 480000000, 200, 4, 0, 3}, + { 26000000, 480000000, 960, 26, 0, 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}, + { 12000000, 1700000000, 850, 6, 0, 8}, + { 13000000, 1700000000, 915, 7, 0, 8}, /* actual: 1699.2 MHz */ + { 16800000, 1700000000, 708, 7, 0, 8}, /* actual: 1699.2 MHz */ + { 19200000, 1700000000, 885, 10, 0, 8}, /* actual: 1699.2 MHz */ + { 26000000, 1700000000, 850, 13, 0, 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}, + { 12000000, 1600000000, 800, 6, 0, 8}, + { 13000000, 1600000000, 738, 6, 0, 8}, /* actual: 1599.0 MHz */ + { 16800000, 1600000000, 857, 9, 0, 8}, /* actual: 1599.7 MHz */ + { 19200000, 1600000000, 500, 6, 0, 8}, + { 26000000, 1600000000, 800, 13, 0, 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}, + { 12000000, 1500000000, 750, 6, 0, 8}, + { 13000000, 1500000000, 923, 8, 0, 8}, /* actual: 1499.8 MHz */ + { 16800000, 1500000000, 625, 7, 0, 8}, + { 19200000, 1500000000, 625, 8, 0, 8}, + { 26000000, 1500000000, 750, 13, 0, 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}, + { 12000000, 1400000000, 700, 6, 0, 8}, + { 13000000, 1400000000, 969, 9, 0, 8}, /* actual: 1399.7 MHz */ + { 16800000, 1400000000, 1000, 12, 0, 8}, + { 19200000, 1400000000, 875, 12, 0, 8}, + { 26000000, 1400000000, 700, 13, 0, 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}, + { 12000000, 1300000000, 975, 9, 0, 8}, + { 13000000, 1300000000, 1000, 10, 0, 8}, + { 16800000, 1300000000, 928, 12, 0, 8}, /* actual: 1299.2 MHz */ + { 19200000, 1300000000, 812, 12, 0, 8}, /* actual: 1299.2 MHz */ + { 26000000, 1300000000, 650, 13, 0, 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}, + { 12000000, 1200000000, 1000, 10, 0, 8}, + { 13000000, 1200000000, 923, 10, 0, 8}, /* actual: 1199.9 MHz */ + { 16800000, 1200000000, 1000, 14, 0, 8}, + { 19200000, 1200000000, 1000, 16, 0, 8}, + { 26000000, 1200000000, 600, 13, 0, 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}, + { 12000000, 1100000000, 825, 9, 0, 8}, + { 13000000, 1100000000, 846, 10, 0, 8}, /* actual: 1099.8 MHz */ + { 16800000, 1100000000, 982, 15, 0, 8}, /* actual: 1099.8 MHz */ + { 19200000, 1100000000, 859, 15, 0, 8}, /* actual: 1099.5 MHz */ + { 26000000, 1100000000, 550, 13, 0, 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}, + { 12000000, 1000000000, 1000, 12, 0, 8}, + { 13000000, 1000000000, 1000, 13, 0, 8}, + { 16800000, 1000000000, 833, 14, 0, 8}, /* actual: 999.6 MHz */ + { 19200000, 1000000000, 625, 12, 0, 8}, + { 26000000, 1000000000, 1000, 26, 0, 8}, { 0, 0, 0, 0, 0, 0 }, }; @@ -553,7 +559,7 @@ static struct tegra_clk_pll_params pll_c_params = { .vco_max = 1400000000, .base_reg = PLLC_BASE, .misc_reg = PLLC_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -567,7 +573,7 @@ static struct tegra_clk_pll_params pll_m_params = { .vco_max = 1200000000, .base_reg = PLLM_BASE, .misc_reg = PLLM_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -581,7 +587,7 @@ static struct tegra_clk_pll_params pll_p_params = { .vco_max = 1400000000, .base_reg = PLLP_BASE, .misc_reg = PLLP_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -595,7 +601,7 @@ static struct tegra_clk_pll_params pll_a_params = { .vco_max = 1400000000, .base_reg = PLLA_BASE, .misc_reg = PLLA_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -609,7 +615,7 @@ static struct tegra_clk_pll_params pll_d_params = { .vco_max = 1000000000, .base_reg = PLLD_BASE, .misc_reg = PLLD_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, }; @@ -623,7 +629,7 @@ static struct tegra_clk_pll_params pll_d2_params = { .vco_max = 1000000000, .base_reg = PLLD2_BASE, .misc_reg = PLLD2_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, }; @@ -637,9 +643,10 @@ static struct tegra_clk_pll_params pll_u_params = { .vco_max = 960000000, .base_reg = PLLU_BASE, .misc_reg = PLLU_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, + .pdiv_tohw = pllu_p, }; static struct tegra_clk_pll_params pll_x_params = { @@ -651,7 +658,7 @@ static struct tegra_clk_pll_params pll_x_params = { .vco_max = 1700000000, .base_reg = PLLX_BASE, .misc_reg = PLLX_MISC, - .lock_bit_idx = PLL_BASE_LOCK, + .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -665,7 +672,7 @@ static struct tegra_clk_pll_params pll_e_params = { .vco_max = 2400000000U, .base_reg = PLLE_BASE, .misc_reg = PLLE_MISC, - .lock_bit_idx = PLLE_MISC_LOCK, + .lock_mask = PLLE_MISC_LOCK, .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, .lock_delay = 300, }; @@ -1661,7 +1668,7 @@ static void __init tegra30_periph_clk_init(void) 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_base, data->offset, data->flags); clk_register_clkdev(clk, data->con_id, data->dev_id); clks[data->clk_id] = clk; } @@ -1911,9 +1918,16 @@ static __initdata struct tegra_clk_init_table init_table[] = { {disp1, pll_p, 600000000, 0}, {disp2, pll_p, 600000000, 0}, {twd, clk_max, 0, 1}, + {gr2d, pll_c, 300000000, 0}, + {gr3d, pll_c, 300000000, 0}, {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ }; +static void __init tegra30_clock_apply_init_table(void) +{ + tegra_init_from_table(init_table, clks, clk_max); +} + /* * Some clocks may be used by different drivers depending on the board * configuration. List those here to register them twice in the clock lookup @@ -1987,7 +2001,7 @@ void __init tegra30_clock_init(struct device_node *np) 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_clk_apply_init_table = tegra30_clock_apply_init_table; tegra_cpu_car_ops = &tegra30_cpu_car_ops; } diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index a603b9af0ad3..923ca7ee4694 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -22,7 +22,8 @@ #include "clk.h" /* Global data of Tegra CPU CAR ops */ -struct tegra_cpu_car_ops *tegra_cpu_car_ops; +static struct tegra_cpu_car_ops dummy_car_ops; +struct tegra_cpu_car_ops *tegra_cpu_car_ops = &dummy_car_ops; void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max) @@ -76,6 +77,7 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, static const struct of_device_id tegra_dt_clk_match[] = { { .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init }, { .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init }, + { .compatible = "nvidia,tegra114-car", .data = tegra114_clock_init }, { } }; @@ -83,3 +85,13 @@ void __init tegra_clocks_init(void) { of_clk_init(tegra_dt_clk_match); } + +tegra_clk_apply_init_table_func tegra_clk_apply_init_table; + +void __init tegra_clocks_apply_init_table(void) +{ + if (!tegra_clk_apply_init_table) + return; + + tegra_clk_apply_init_table(); +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 0744731c6229..e0565620d68e 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -1,4 +1,4 @@ -/* + /* * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -117,6 +117,17 @@ struct tegra_clk_pll_freq_table { }; /** + * struct pdiv_map - map post divider to hw value + * + * @pdiv: post divider + * @hw_val: value to be written to the PLL hw + */ +struct pdiv_map { + u8 pdiv; + u8 hw_val; +}; + +/** * struct clk_pll_params - PLL parameters * * @input_min: Minimum input frequency @@ -143,9 +154,18 @@ struct tegra_clk_pll_params { u32 base_reg; u32 misc_reg; u32 lock_reg; - u32 lock_bit_idx; + u32 lock_mask; u32 lock_enable_bit_idx; + u32 iddq_reg; + u32 iddq_bit_idx; + u32 aux_reg; + u32 dyn_ramp_reg; + u32 ext_misc_reg[3]; + int stepa_shift; + int stepb_shift; int lock_delay; + int max_p; + struct pdiv_map *pdiv_tohw; }; /** @@ -182,12 +202,16 @@ struct tegra_clk_pll_params { * TEGRA_PLL_FIXED - We are not supposed to change output frequency * of some plls. * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling. + * TEGRA_PLL_LOCK_MISC - Lock bit is in the misc register instead of the + * base register. + * TEGRA_PLL_BYPASS - PLL has bypass bit + * TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring */ struct tegra_clk_pll { struct clk_hw hw; void __iomem *clk_base; void __iomem *pmc; - u8 flags; + u32 flags; unsigned long fixed_rate; spinlock_t *lock; u8 divn_shift; @@ -210,20 +234,64 @@ struct tegra_clk_pll { #define TEGRA_PLLM BIT(5) #define TEGRA_PLL_FIXED BIT(6) #define TEGRA_PLLE_CONFIGURE BIT(7) +#define TEGRA_PLL_LOCK_MISC BIT(8) +#define TEGRA_PLL_BYPASS BIT(9) +#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10) 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_params *pll_params, u32 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_params *pll_params, u32 pll_flags, struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); +struct clk *tegra_clk_register_pllxc(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, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock); + +struct clk *tegra_clk_register_pllm(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, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock); + +struct clk *tegra_clk_register_pllc(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, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock); + +struct clk *tegra_clk_register_pllre(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, + u32 pll_flags, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock, unsigned long parent_rate); + +struct clk *tegra_clk_register_plle_tegra114(const char *name, + const char *parent_name, + void __iomem *clk_base, unsigned long flags, + unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, + struct tegra_clk_pll_freq_table *freq_table, + spinlock_t *lock); + /** * struct tegra_clk_pll_out - PLL divider down clock * @@ -290,6 +358,7 @@ struct tegra_clk_periph_regs { * 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. + * TEGRA_PERIPH_WAR_1005168 - Apply workaround for Tegra114 MSENC bug */ struct tegra_clk_periph_gate { u32 magic; @@ -309,6 +378,7 @@ struct tegra_clk_periph_gate { #define TEGRA_PERIPH_NO_RESET BIT(0) #define TEGRA_PERIPH_MANUAL_RESET BIT(1) #define TEGRA_PERIPH_ON_APB BIT(2) +#define TEGRA_PERIPH_WAR_1005168 BIT(3) void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert); extern const struct clk_ops tegra_clk_periph_gate_ops; @@ -349,21 +419,22 @@ 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); + u32 offset, unsigned long flags); 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, \ +#define TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, _mux_flags, \ _div_shift, _div_width, _div_frac_width, \ _div_flags, _clk_num, _enb_refcnt, _regs, \ - _gate_flags) \ + _gate_flags, _table) \ { \ .mux = { \ .flags = _mux_flags, \ .shift = _mux_shift, \ - .width = _mux_width, \ + .mask = _mux_mask, \ + .table = _table, \ }, \ .divider = { \ .flags = _div_flags, \ @@ -391,28 +462,41 @@ struct tegra_periph_init_data { u32 offset; const char *con_id; const char *dev_id; + unsigned long flags; }; -#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \ - _mux_shift, _mux_width, _mux_flags, _div_shift, \ +#define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\ + _mux_shift, _mux_mask, _mux_flags, _div_shift, \ _div_width, _div_frac_width, _div_flags, _regs, \ - _clk_num, _enb_refcnt, _gate_flags, _clk_id) \ + _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table,\ + _flags) \ { \ .name = _name, \ .clk_id = _clk_id, \ .parent_names = _parent_names, \ .num_parents = ARRAY_SIZE(_parent_names), \ - .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \ + .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, \ _mux_flags, _div_shift, \ _div_width, _div_frac_width, \ _div_flags, _clk_num, \ _enb_refcnt, _regs, \ - _gate_flags), \ + _gate_flags, _table), \ .offset = _offset, \ .con_id = _con_id, \ .dev_id = _dev_id, \ + .flags = _flags \ } +#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) \ + TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\ + _mux_shift, BIT(_mux_width) - 1, _mux_flags, \ + _div_shift, _div_width, _div_frac_width, _div_flags, \ + _regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\ + NULL, 0) + /** * struct clk_super_mux - super clock * @@ -499,4 +583,13 @@ void tegra30_clock_init(struct device_node *np); static inline void tegra30_clock_init(struct device_node *np) {} #endif /* CONFIG_ARCH_TEGRA_3x_SOC */ +#ifdef CONFIG_ARCH_TEGRA_114_SOC +void tegra114_clock_init(struct device_node *np); +#else +static inline void tegra114_clock_init(struct device_node *np) {} +#endif /* CONFIG_ARCH_TEGRA114_SOC */ + +typedef void (*tegra_clk_apply_init_table_func)(void); +extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table; + #endif /* TEGRA_CLK_H */ diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index 74faa7e3cf59..293a28854417 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c @@ -20,15 +20,23 @@ struct clk_prcmu { struct clk_hw hw; u8 cg_sel; + int is_prepared; int is_enabled; + int opp_requested; }; /* PRCMU clock operations. */ static int clk_prcmu_prepare(struct clk_hw *hw) { + int ret; struct clk_prcmu *clk = to_clk_prcmu(hw); - return prcmu_request_clock(clk->cg_sel, true); + + ret = prcmu_request_clock(clk->cg_sel, true); + if (!ret) + clk->is_prepared = 1; + + return ret;; } static void clk_prcmu_unprepare(struct clk_hw *hw) @@ -36,7 +44,15 @@ static void clk_prcmu_unprepare(struct clk_hw *hw) struct clk_prcmu *clk = to_clk_prcmu(hw); if (prcmu_request_clock(clk->cg_sel, false)) pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, - hw->init->name); + __clk_get_name(hw->clk)); + else + clk->is_prepared = 0; +} + +static int clk_prcmu_is_prepared(struct clk_hw *hw) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + return clk->is_prepared; } static int clk_prcmu_enable(struct clk_hw *hw) @@ -79,58 +95,52 @@ static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate, return prcmu_set_clock_rate(clk->cg_sel, rate); } -static int request_ape_opp100(bool enable) -{ - static int reqs; - int err = 0; - - if (enable) { - if (!reqs) - err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, - "clock", 100); - if (!err) - reqs++; - } else { - reqs--; - if (!reqs) - prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, - "clock"); - } - return err; -} - static int clk_prcmu_opp_prepare(struct clk_hw *hw) { int err; struct clk_prcmu *clk = to_clk_prcmu(hw); - err = request_ape_opp100(true); - if (err) { - pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n", - __func__, hw->init->name); - return err; + if (!clk->opp_requested) { + err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + (char *)__clk_get_name(hw->clk), + 100); + if (err) { + pr_err("clk_prcmu: %s fail req APE OPP for %s.\n", + __func__, __clk_get_name(hw->clk)); + return err; + } + clk->opp_requested = 1; } err = prcmu_request_clock(clk->cg_sel, true); - if (err) - request_ape_opp100(false); + if (err) { + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, + (char *)__clk_get_name(hw->clk)); + clk->opp_requested = 0; + return err; + } - return err; + clk->is_prepared = 1; + return 0; } static void clk_prcmu_opp_unprepare(struct clk_hw *hw) { struct clk_prcmu *clk = to_clk_prcmu(hw); - if (prcmu_request_clock(clk->cg_sel, false)) - goto out_error; - if (request_ape_opp100(false)) - goto out_error; - return; - -out_error: - pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, - hw->init->name); + if (prcmu_request_clock(clk->cg_sel, false)) { + pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, + __clk_get_name(hw->clk)); + return; + } + + if (clk->opp_requested) { + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, + (char *)__clk_get_name(hw->clk)); + clk->opp_requested = 0; + } + + clk->is_prepared = 0; } static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw) @@ -138,38 +148,49 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw) int err; struct clk_prcmu *clk = to_clk_prcmu(hw); - err = prcmu_request_ape_opp_100_voltage(true); - if (err) { - pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n", - __func__, hw->init->name); - return err; + if (!clk->opp_requested) { + err = prcmu_request_ape_opp_100_voltage(true); + if (err) { + pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n", + __func__, __clk_get_name(hw->clk)); + return err; + } + clk->opp_requested = 1; } err = prcmu_request_clock(clk->cg_sel, true); - if (err) + if (err) { prcmu_request_ape_opp_100_voltage(false); + clk->opp_requested = 0; + return err; + } - return err; + clk->is_prepared = 1; + return 0; } static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw) { struct clk_prcmu *clk = to_clk_prcmu(hw); - if (prcmu_request_clock(clk->cg_sel, false)) - goto out_error; - if (prcmu_request_ape_opp_100_voltage(false)) - goto out_error; - return; - -out_error: - pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, - hw->init->name); + if (prcmu_request_clock(clk->cg_sel, false)) { + pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, + __clk_get_name(hw->clk)); + return; + } + + if (clk->opp_requested) { + prcmu_request_ape_opp_100_voltage(false); + clk->opp_requested = 0; + } + + clk->is_prepared = 0; } static struct clk_ops clk_prcmu_scalable_ops = { .prepare = clk_prcmu_prepare, .unprepare = clk_prcmu_unprepare, + .is_prepared = clk_prcmu_is_prepared, .enable = clk_prcmu_enable, .disable = clk_prcmu_disable, .is_enabled = clk_prcmu_is_enabled, @@ -181,6 +202,7 @@ static struct clk_ops clk_prcmu_scalable_ops = { static struct clk_ops clk_prcmu_gate_ops = { .prepare = clk_prcmu_prepare, .unprepare = clk_prcmu_unprepare, + .is_prepared = clk_prcmu_is_prepared, .enable = clk_prcmu_enable, .disable = clk_prcmu_disable, .is_enabled = clk_prcmu_is_enabled, @@ -202,6 +224,7 @@ static struct clk_ops clk_prcmu_rate_ops = { static struct clk_ops clk_prcmu_opp_gate_ops = { .prepare = clk_prcmu_opp_prepare, .unprepare = clk_prcmu_opp_unprepare, + .is_prepared = clk_prcmu_is_prepared, .enable = clk_prcmu_enable, .disable = clk_prcmu_disable, .is_enabled = clk_prcmu_is_enabled, @@ -211,6 +234,7 @@ static struct clk_ops clk_prcmu_opp_gate_ops = { static struct clk_ops clk_prcmu_opp_volt_scalable_ops = { .prepare = clk_prcmu_opp_volt_prepare, .unprepare = clk_prcmu_opp_volt_unprepare, + .is_prepared = clk_prcmu_is_prepared, .enable = clk_prcmu_enable, .disable = clk_prcmu_disable, .is_enabled = clk_prcmu_is_enabled, @@ -242,7 +266,9 @@ static struct clk *clk_reg_prcmu(const char *name, } clk->cg_sel = cg_sel; + clk->is_prepared = 1; clk->is_enabled = 1; + clk->opp_requested = 0; /* "rate" can be used for changing the initial frequency */ if (rate) prcmu_set_clock_rate(cg_sel, rate); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e507ab7df60b..73fcddb8314d 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -31,6 +31,9 @@ config SUNXI_TIMER config VT8500_TIMER bool +config CADENCE_TTC_TIMER + bool + config CLKSRC_NOMADIK_MTU bool depends on (ARCH_NOMADIK || ARCH_U8500) @@ -67,3 +70,8 @@ config CLKSRC_METAG_GENERIC def_bool y if METAG help This option enables support for the Meta per-thread timers. + +config CLKSRC_EXYNOS_MCT + def_bool y if ARCH_EXYNOS + help + Support for Multi Core Timer controller on Exynos SoCs. diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 4d8283aec5b5..cd1f09cbd61a 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -19,6 +19,8 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o +obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o +obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 50c68fef944b..766611d29945 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -95,23 +95,13 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id) } } -static struct of_device_id bcm2835_time_match[] __initconst = { - { .compatible = "brcm,bcm2835-system-timer" }, - {} -}; - -static void __init bcm2835_timer_init(void) +static void __init bcm2835_timer_init(struct device_node *node) { - struct device_node *node; void __iomem *base; u32 freq; int irq; struct bcm2835_timer *timer; - node = of_find_matching_node(NULL, bcm2835_time_match); - if (!node) - panic("No bcm2835 timer node"); - base = of_iomap(node, 0); if (!base) panic("Can't remap registers"); diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c new file mode 100644 index 000000000000..685bc60e210a --- /dev/null +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -0,0 +1,436 @@ +/* + * This file contains driver for the Cadence Triple Timer Counter Rev 06 + * + * Copyright (C) 2011-2013 Xilinx + * + * based on arch/mips/kernel/time.c timer driver + * + * 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.h> +#include <linux/interrupt.h> +#include <linux/clockchips.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> +#include <linux/clk-provider.h> + +/* + * This driver configures the 2 16-bit count-up timers as follows: + * + * T1: Timer 1, clocksource for generic timekeeping + * T2: Timer 2, clockevent source for hrtimers + * T3: Timer 3, <unused> + * + * The input frequency to the timer module for emulation is 2.5MHz which is + * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32, + * the timers are clocked at 78.125KHz (12.8 us resolution). + + * The input frequency to the timer module in silicon is configurable and + * obtained from device tree. The pre-scaler of 32 is used. + */ + +/* + * Timer Register Offset Definitions of Timer 1, Increment base address by 4 + * and use same offsets for Timer 2 + */ +#define TTC_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */ +#define TTC_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */ +#define TTC_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */ +#define TTC_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */ +#define TTC_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */ +#define TTC_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */ + +#define TTC_CNT_CNTRL_DISABLE_MASK 0x1 + +/* + * Setup the timers to use pre-scaling, using a fixed value for now that will + * work across most input frequency, but it may need to be more dynamic + */ +#define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */ +#define PRESCALE 2048 /* The exponent must match this */ +#define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1) +#define CLK_CNTRL_PRESCALE_EN 1 +#define CNT_CNTRL_RESET (1 << 4) + +/** + * struct ttc_timer - This definition defines local timer structure + * + * @base_addr: Base address of timer + * @clk: Associated clock source + * @clk_rate_change_nb Notifier block for clock rate changes + */ +struct ttc_timer { + void __iomem *base_addr; + struct clk *clk; + struct notifier_block clk_rate_change_nb; +}; + +#define to_ttc_timer(x) \ + container_of(x, struct ttc_timer, clk_rate_change_nb) + +struct ttc_timer_clocksource { + struct ttc_timer ttc; + struct clocksource cs; +}; + +#define to_ttc_timer_clksrc(x) \ + container_of(x, struct ttc_timer_clocksource, cs) + +struct ttc_timer_clockevent { + struct ttc_timer ttc; + struct clock_event_device ce; +}; + +#define to_ttc_timer_clkevent(x) \ + container_of(x, struct ttc_timer_clockevent, ce) + +/** + * ttc_set_interval - Set the timer interval value + * + * @timer: Pointer to the timer instance + * @cycles: Timer interval ticks + **/ +static void ttc_set_interval(struct ttc_timer *timer, + unsigned long cycles) +{ + u32 ctrl_reg; + + /* Disable the counter, set the counter value and re-enable counter */ + ctrl_reg = __raw_readl(timer->base_addr + TTC_CNT_CNTRL_OFFSET); + ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; + __raw_writel(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); + + __raw_writel(cycles, timer->base_addr + TTC_INTR_VAL_OFFSET); + + /* + * Reset the counter (0x10) so that it starts from 0, one-shot + * mode makes this needed for timing to be right. + */ + ctrl_reg |= CNT_CNTRL_RESET; + ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; + __raw_writel(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); +} + +/** + * ttc_clock_event_interrupt - Clock event timer interrupt handler + * + * @irq: IRQ number of the Timer + * @dev_id: void pointer to the ttc_timer instance + * + * returns: Always IRQ_HANDLED - success + **/ +static irqreturn_t ttc_clock_event_interrupt(int irq, void *dev_id) +{ + struct ttc_timer_clockevent *ttce = dev_id; + struct ttc_timer *timer = &ttce->ttc; + + /* Acknowledge the interrupt and call event handler */ + __raw_readl(timer->base_addr + TTC_ISR_OFFSET); + + ttce->ce.event_handler(&ttce->ce); + + return IRQ_HANDLED; +} + +/** + * __ttc_clocksource_read - Reads the timer counter register + * + * returns: Current timer counter register value + **/ +static cycle_t __ttc_clocksource_read(struct clocksource *cs) +{ + struct ttc_timer *timer = &to_ttc_timer_clksrc(cs)->ttc; + + return (cycle_t)__raw_readl(timer->base_addr + + TTC_COUNT_VAL_OFFSET); +} + +/** + * ttc_set_next_event - Sets the time interval for next event + * + * @cycles: Timer interval ticks + * @evt: Address of clock event instance + * + * returns: Always 0 - success + **/ +static int ttc_set_next_event(unsigned long cycles, + struct clock_event_device *evt) +{ + struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); + struct ttc_timer *timer = &ttce->ttc; + + ttc_set_interval(timer, cycles); + return 0; +} + +/** + * ttc_set_mode - Sets the mode of timer + * + * @mode: Mode to be set + * @evt: Address of clock event instance + **/ +static void ttc_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); + struct ttc_timer *timer = &ttce->ttc; + u32 ctrl_reg; + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + ttc_set_interval(timer, + DIV_ROUND_CLOSEST(clk_get_rate(ttce->ttc.clk), + PRESCALE * HZ)); + break; + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + ctrl_reg = __raw_readl(timer->base_addr + + TTC_CNT_CNTRL_OFFSET); + ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; + __raw_writel(ctrl_reg, + timer->base_addr + TTC_CNT_CNTRL_OFFSET); + break; + case CLOCK_EVT_MODE_RESUME: + ctrl_reg = __raw_readl(timer->base_addr + + TTC_CNT_CNTRL_OFFSET); + ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; + __raw_writel(ctrl_reg, + timer->base_addr + TTC_CNT_CNTRL_OFFSET); + break; + } +} + +static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct clk_notifier_data *ndata = data; + struct ttc_timer *ttc = to_ttc_timer(nb); + struct ttc_timer_clocksource *ttccs = container_of(ttc, + struct ttc_timer_clocksource, ttc); + + switch (event) { + case POST_RATE_CHANGE: + /* + * Do whatever is necessary to maintain a proper time base + * + * I cannot find a way to adjust the currently used clocksource + * to the new frequency. __clocksource_updatefreq_hz() sounds + * good, but does not work. Not sure what's that missing. + * + * This approach works, but triggers two clocksource switches. + * The first after unregister to clocksource jiffies. And + * another one after the register to the newly registered timer. + * + * Alternatively we could 'waste' another HW timer to ping pong + * between clock sources. That would also use one register and + * one unregister call, but only trigger one clocksource switch + * for the cost of another HW timer used by the OS. + */ + clocksource_unregister(&ttccs->cs); + clocksource_register_hz(&ttccs->cs, + ndata->new_rate / PRESCALE); + /* fall through */ + case PRE_RATE_CHANGE: + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) +{ + struct ttc_timer_clocksource *ttccs; + int err; + + ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); + if (WARN_ON(!ttccs)) + return; + + ttccs->ttc.clk = clk; + + err = clk_prepare_enable(ttccs->ttc.clk); + if (WARN_ON(err)) { + kfree(ttccs); + return; + } + + ttccs->ttc.clk_rate_change_nb.notifier_call = + ttc_rate_change_clocksource_cb; + ttccs->ttc.clk_rate_change_nb.next = NULL; + if (clk_notifier_register(ttccs->ttc.clk, + &ttccs->ttc.clk_rate_change_nb)) + pr_warn("Unable to register clock notifier.\n"); + + ttccs->ttc.base_addr = base; + ttccs->cs.name = "ttc_clocksource"; + ttccs->cs.rating = 200; + ttccs->cs.read = __ttc_clocksource_read; + ttccs->cs.mask = CLOCKSOURCE_MASK(16); + ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; + + /* + * Setup the clock source counter to be an incrementing counter + * with no interrupt and it rolls over at 0xFFFF. Pre-scale + * it by 32 also. Let it start running now. + */ + __raw_writel(0x0, ttccs->ttc.base_addr + TTC_IER_OFFSET); + __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, + ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); + __raw_writel(CNT_CNTRL_RESET, + ttccs->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); + + err = clocksource_register_hz(&ttccs->cs, + clk_get_rate(ttccs->ttc.clk) / PRESCALE); + if (WARN_ON(err)) { + kfree(ttccs); + return; + } +} + +static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct clk_notifier_data *ndata = data; + struct ttc_timer *ttc = to_ttc_timer(nb); + struct ttc_timer_clockevent *ttcce = container_of(ttc, + struct ttc_timer_clockevent, ttc); + + switch (event) { + case POST_RATE_CHANGE: + { + unsigned long flags; + + /* + * clockevents_update_freq should be called with IRQ disabled on + * the CPU the timer provides events for. The timer we use is + * common to both CPUs, not sure if we need to run on both + * cores. + */ + local_irq_save(flags); + clockevents_update_freq(&ttcce->ce, + ndata->new_rate / PRESCALE); + local_irq_restore(flags); + + /* fall through */ + } + case PRE_RATE_CHANGE: + case ABORT_RATE_CHANGE: + default: + return NOTIFY_DONE; + } +} + +static void __init ttc_setup_clockevent(struct clk *clk, + void __iomem *base, u32 irq) +{ + struct ttc_timer_clockevent *ttcce; + int err; + + ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); + if (WARN_ON(!ttcce)) + return; + + ttcce->ttc.clk = clk; + + err = clk_prepare_enable(ttcce->ttc.clk); + if (WARN_ON(err)) { + kfree(ttcce); + return; + } + + ttcce->ttc.clk_rate_change_nb.notifier_call = + ttc_rate_change_clockevent_cb; + ttcce->ttc.clk_rate_change_nb.next = NULL; + if (clk_notifier_register(ttcce->ttc.clk, + &ttcce->ttc.clk_rate_change_nb)) + pr_warn("Unable to register clock notifier.\n"); + + ttcce->ttc.base_addr = base; + ttcce->ce.name = "ttc_clockevent"; + ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + ttcce->ce.set_next_event = ttc_set_next_event; + ttcce->ce.set_mode = ttc_set_mode; + ttcce->ce.rating = 200; + ttcce->ce.irq = irq; + ttcce->ce.cpumask = cpu_possible_mask; + + /* + * Setup the clock event timer to be an interval timer which + * is prescaled by 32 using the interval interrupt. Leave it + * disabled for now. + */ + __raw_writel(0x23, ttcce->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); + __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, + ttcce->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); + __raw_writel(0x1, ttcce->ttc.base_addr + TTC_IER_OFFSET); + + err = request_irq(irq, ttc_clock_event_interrupt, + IRQF_DISABLED | IRQF_TIMER, + ttcce->ce.name, ttcce); + if (WARN_ON(err)) { + kfree(ttcce); + return; + } + + clockevents_config_and_register(&ttcce->ce, + clk_get_rate(ttcce->ttc.clk) / PRESCALE, 1, 0xfffe); +} + +/** + * ttc_timer_init - Initialize the timer + * + * Initializes the timer hardware and register the clock source and clock event + * timers with Linux kernal timer framework + */ +static void __init ttc_timer_init(struct device_node *timer) +{ + unsigned int irq; + void __iomem *timer_baseaddr; + struct clk *clk; + static int initialized; + + if (initialized) + return; + + initialized = 1; + + /* + * Get the 1st Triple Timer Counter (TTC) block from the device tree + * and use it. Note that the event timer uses the interrupt and it's the + * 2nd TTC hence the irq_of_parse_and_map(,1) + */ + timer_baseaddr = of_iomap(timer, 0); + if (!timer_baseaddr) { + pr_err("ERROR: invalid timer base address\n"); + BUG(); + } + + irq = irq_of_parse_and_map(timer, 1); + if (irq <= 0) { + pr_err("ERROR: invalid interrupt number\n"); + BUG(); + } + + clk = of_clk_get_by_name(timer, "cpu_1x"); + if (IS_ERR(clk)) { + pr_err("ERROR: timer input clock not found\n"); + BUG(); + } + + ttc_setup_clocksource(clk, timer_baseaddr); + ttc_setup_clockevent(clk, timer_baseaddr + 4, irq); + + pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq); +} + +CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index bdabdaa8d00f..37f5325bec95 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/of.h> +#include <linux/clocksource.h> extern struct of_device_id __clksrc_of_table[]; @@ -26,10 +27,10 @@ void __init clocksource_of_init(void) { struct device_node *np; const struct of_device_id *match; - void (*init_func)(void); + clocksource_of_init_fn init_func; for_each_matching_node_and_match(np, __clksrc_of_table, &match) { init_func = match->data; - init_func(); + init_func(np); } } diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index e6a553cb73e8..4329a29a5310 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -399,7 +399,18 @@ static struct platform_driver em_sti_device_driver = { } }; -module_platform_driver(em_sti_device_driver); +static int __init em_sti_init(void) +{ + return platform_driver_register(&em_sti_device_driver); +} + +static void __exit em_sti_exit(void) +{ + platform_driver_unregister(&em_sti_device_driver); +} + +subsys_initcall(em_sti_init); +module_exit(em_sti_exit); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver"); diff --git a/arch/arm/mach-exynos/mct.c b/drivers/clocksource/exynos_mct.c index c9d6650f9b5d..509a6019c96c 100644 --- a/arch/arm/mach-exynos/mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -20,6 +20,9 @@ #include <linux/delay.h> #include <linux/percpu.h> #include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/clocksource.h> #include <asm/arch_timer.h> #include <asm/localtimer.h> @@ -28,9 +31,36 @@ #include <mach/map.h> #include <mach/irqs.h> -#include <mach/regs-mct.h> #include <asm/mach/time.h> +#define EXYNOS4_MCTREG(x) (x) +#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100) +#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104) +#define EXYNOS4_MCT_G_CNT_WSTAT EXYNOS4_MCTREG(0x110) +#define EXYNOS4_MCT_G_COMP0_L EXYNOS4_MCTREG(0x200) +#define EXYNOS4_MCT_G_COMP0_U EXYNOS4_MCTREG(0x204) +#define EXYNOS4_MCT_G_COMP0_ADD_INCR EXYNOS4_MCTREG(0x208) +#define EXYNOS4_MCT_G_TCON EXYNOS4_MCTREG(0x240) +#define EXYNOS4_MCT_G_INT_CSTAT EXYNOS4_MCTREG(0x244) +#define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248) +#define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C) +#define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300) +#define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * x)) +#define EXYNOS4_MCT_L_MASK (0xffffff00) + +#define MCT_L_TCNTB_OFFSET (0x00) +#define MCT_L_ICNTB_OFFSET (0x08) +#define MCT_L_TCON_OFFSET (0x20) +#define MCT_L_INT_CSTAT_OFFSET (0x30) +#define MCT_L_INT_ENB_OFFSET (0x34) +#define MCT_L_WSTAT_OFFSET (0x40) +#define MCT_G_TCON_START (1 << 8) +#define MCT_G_TCON_COMP0_AUTO_INC (1 << 1) +#define MCT_G_TCON_COMP0_ENABLE (1 << 0) +#define MCT_L_TCON_INTERVAL_MODE (1 << 2) +#define MCT_L_TCON_INT_START (1 << 1) +#define MCT_L_TCON_TIMER_START (1 << 0) + #define TICK_BASE_CNT 1 enum { @@ -38,64 +68,75 @@ enum { MCT_INT_PPI }; +enum { + MCT_G0_IRQ, + MCT_G1_IRQ, + MCT_G2_IRQ, + MCT_G3_IRQ, + MCT_L0_IRQ, + MCT_L1_IRQ, + MCT_L2_IRQ, + MCT_L3_IRQ, + MCT_NR_IRQS, +}; + +static void __iomem *reg_base; static unsigned long clk_rate; static unsigned int mct_int_type; +static int mct_irqs[MCT_NR_IRQS]; struct mct_clock_event_device { struct clock_event_device *evt; - void __iomem *base; + unsigned long base; char name[10]; }; -static void exynos4_mct_write(unsigned int value, void *addr) +static void exynos4_mct_write(unsigned int value, unsigned long offset) { - void __iomem *stat_addr; + unsigned long stat_addr; u32 mask; u32 i; - __raw_writel(value, addr); + __raw_writel(value, reg_base + offset); - if (likely(addr >= EXYNOS4_MCT_L_BASE(0))) { - u32 base = (u32) addr & EXYNOS4_MCT_L_MASK; - switch ((u32) addr & ~EXYNOS4_MCT_L_MASK) { - case (u32) MCT_L_TCON_OFFSET: - stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; + if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) { + stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; + switch (offset & EXYNOS4_MCT_L_MASK) { + case MCT_L_TCON_OFFSET: mask = 1 << 3; /* L_TCON write status */ break; - case (u32) MCT_L_ICNTB_OFFSET: - stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; + case MCT_L_ICNTB_OFFSET: mask = 1 << 1; /* L_ICNTB write status */ break; - case (u32) MCT_L_TCNTB_OFFSET: - stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; + case MCT_L_TCNTB_OFFSET: mask = 1 << 0; /* L_TCNTB write status */ break; default: return; } } else { - switch ((u32) addr) { - case (u32) EXYNOS4_MCT_G_TCON: + switch (offset) { + case EXYNOS4_MCT_G_TCON: stat_addr = EXYNOS4_MCT_G_WSTAT; mask = 1 << 16; /* G_TCON write status */ break; - case (u32) EXYNOS4_MCT_G_COMP0_L: + case EXYNOS4_MCT_G_COMP0_L: stat_addr = EXYNOS4_MCT_G_WSTAT; mask = 1 << 0; /* G_COMP0_L write status */ break; - case (u32) EXYNOS4_MCT_G_COMP0_U: + case EXYNOS4_MCT_G_COMP0_U: stat_addr = EXYNOS4_MCT_G_WSTAT; mask = 1 << 1; /* G_COMP0_U write status */ break; - case (u32) EXYNOS4_MCT_G_COMP0_ADD_INCR: + case EXYNOS4_MCT_G_COMP0_ADD_INCR: stat_addr = EXYNOS4_MCT_G_WSTAT; mask = 1 << 2; /* G_COMP0_ADD_INCR w status */ break; - case (u32) EXYNOS4_MCT_G_CNT_L: + case EXYNOS4_MCT_G_CNT_L: stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; mask = 1 << 0; /* G_CNT_L write status */ break; - case (u32) EXYNOS4_MCT_G_CNT_U: + case EXYNOS4_MCT_G_CNT_U: stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; mask = 1 << 1; /* G_CNT_U write status */ break; @@ -106,12 +147,12 @@ static void exynos4_mct_write(unsigned int value, void *addr) /* Wait maximum 1 ms until written values are applied */ for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++) - if (__raw_readl(stat_addr) & mask) { - __raw_writel(mask, stat_addr); + if (__raw_readl(reg_base + stat_addr) & mask) { + __raw_writel(mask, reg_base + stat_addr); return; } - panic("MCT hangs after writing %d (addr:0x%08x)\n", value, (u32)addr); + panic("MCT hangs after writing %d (offset:0x%lx)\n", value, offset); } /* Clocksource handling */ @@ -122,7 +163,7 @@ static void exynos4_mct_frc_start(u32 hi, u32 lo) exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L); exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U); - reg = __raw_readl(EXYNOS4_MCT_G_TCON); + reg = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); reg |= MCT_G_TCON_START; exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON); } @@ -130,12 +171,12 @@ static void exynos4_mct_frc_start(u32 hi, u32 lo) static cycle_t exynos4_frc_read(struct clocksource *cs) { unsigned int lo, hi; - u32 hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U); + u32 hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); do { hi = hi2; - lo = __raw_readl(EXYNOS4_MCT_G_CNT_L); - hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U); + lo = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_L); + hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); } while (hi != hi2); return ((cycle_t)hi << 32) | lo; @@ -167,7 +208,7 @@ static void exynos4_mct_comp0_stop(void) { unsigned int tcon; - tcon = __raw_readl(EXYNOS4_MCT_G_TCON); + tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC); exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON); @@ -180,7 +221,7 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode, unsigned int tcon; cycle_t comp_cycle; - tcon = __raw_readl(EXYNOS4_MCT_G_TCON); + tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); if (mode == CLOCK_EVT_MODE_PERIODIC) { tcon |= MCT_G_TCON_COMP0_AUTO_INC; @@ -257,11 +298,7 @@ static void exynos4_clockevent_init(void) mct_comp_device.cpumask = cpumask_of(0); clockevents_config_and_register(&mct_comp_device, clk_rate, 0xf, 0xffffffff); - - if (soc_is_exynos5250()) - setup_irq(EXYNOS5_IRQ_MCT_G0, &mct_comp_event_irq); - else - setup_irq(EXYNOS4_IRQ_MCT_G0, &mct_comp_event_irq); + setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); } #ifdef CONFIG_LOCAL_TIMERS @@ -273,12 +310,12 @@ static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt) { unsigned long tmp; unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START; - void __iomem *addr = mevt->base + MCT_L_TCON_OFFSET; + unsigned long offset = mevt->base + MCT_L_TCON_OFFSET; - tmp = __raw_readl(addr); + tmp = __raw_readl(reg_base + offset); if (tmp & mask) { tmp &= ~mask; - exynos4_mct_write(tmp, addr); + exynos4_mct_write(tmp, offset); } } @@ -297,7 +334,7 @@ static void exynos4_mct_tick_start(unsigned long cycles, /* enable MCT tick interrupt */ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET); - tmp = __raw_readl(mevt->base + MCT_L_TCON_OFFSET); + tmp = __raw_readl(reg_base + mevt->base + MCT_L_TCON_OFFSET); tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START | MCT_L_TCON_INTERVAL_MODE; exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); @@ -349,7 +386,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) exynos4_mct_tick_stop(mevt); /* Clear the MCT tick interrupt */ - if (__raw_readl(mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { + if (__raw_readl(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); return 1; } else { @@ -385,7 +422,6 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) { struct mct_clock_event_device *mevt; unsigned int cpu = smp_processor_id(); - int mct_lx_irq; mevt = this_cpu_ptr(&percpu_mct_tick); mevt->evt = evt; @@ -406,21 +442,17 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) if (mct_int_type == MCT_INT_SPI) { if (cpu == 0) { - mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L0 : - EXYNOS5_IRQ_MCT_L0; mct_tick0_event_irq.dev_id = mevt; - evt->irq = mct_lx_irq; - setup_irq(mct_lx_irq, &mct_tick0_event_irq); + evt->irq = mct_irqs[MCT_L0_IRQ]; + setup_irq(evt->irq, &mct_tick0_event_irq); } else { - mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L1 : - EXYNOS5_IRQ_MCT_L1; mct_tick1_event_irq.dev_id = mevt; - evt->irq = mct_lx_irq; - setup_irq(mct_lx_irq, &mct_tick1_event_irq); - irq_set_affinity(mct_lx_irq, cpumask_of(1)); + evt->irq = mct_irqs[MCT_L1_IRQ]; + setup_irq(evt->irq, &mct_tick1_event_irq); + irq_set_affinity(evt->irq, cpumask_of(1)); } } else { - enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, 0); + enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0); } return 0; @@ -436,7 +468,7 @@ static void exynos4_local_timer_stop(struct clock_event_device *evt) else remove_irq(evt->irq, &mct_tick1_event_irq); else - disable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER); + disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); } static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { @@ -445,41 +477,88 @@ static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { }; #endif /* CONFIG_LOCAL_TIMERS */ -static void __init exynos4_timer_resources(void) +static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base) { - struct clk *mct_clk; - mct_clk = clk_get(NULL, "xtal"); + struct clk *mct_clk, *tick_clk; + + tick_clk = np ? of_clk_get_by_name(np, "fin_pll") : + clk_get(NULL, "fin_pll"); + if (IS_ERR(tick_clk)) + panic("%s: unable to determine tick clock rate\n", __func__); + clk_rate = clk_get_rate(tick_clk); + + mct_clk = np ? of_clk_get_by_name(np, "mct") : clk_get(NULL, "mct"); + if (IS_ERR(mct_clk)) + panic("%s: unable to retrieve mct clock instance\n", __func__); + clk_prepare_enable(mct_clk); - clk_rate = clk_get_rate(mct_clk); + reg_base = base; + if (!reg_base) + panic("%s: unable to ioremap mct address space\n", __func__); #ifdef CONFIG_LOCAL_TIMERS if (mct_int_type == MCT_INT_PPI) { int err; - err = request_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, + err = request_percpu_irq(mct_irqs[MCT_L0_IRQ], exynos4_mct_tick_isr, "MCT", &percpu_mct_tick); WARN(err, "MCT: can't request IRQ %d (%d)\n", - EXYNOS_IRQ_MCT_LOCALTIMER, err); + mct_irqs[MCT_L0_IRQ], err); } local_timer_register(&exynos4_mct_tick_ops); #endif /* CONFIG_LOCAL_TIMERS */ } -void __init exynos4_timer_init(void) +void __init mct_init(void) { - if (soc_is_exynos5440()) { - arch_timer_of_register(); - return; + if (soc_is_exynos4210()) { + mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0; + mct_irqs[MCT_L0_IRQ] = EXYNOS4_IRQ_MCT_L0; + mct_irqs[MCT_L1_IRQ] = EXYNOS4_IRQ_MCT_L1; + mct_int_type = MCT_INT_SPI; + } else { + panic("unable to determine mct controller type\n"); } - if ((soc_is_exynos4210()) || (soc_is_exynos5250())) - mct_int_type = MCT_INT_SPI; - else - mct_int_type = MCT_INT_PPI; + exynos4_timer_resources(NULL, S5P_VA_SYSTIMER); + exynos4_clocksource_init(); + exynos4_clockevent_init(); +} - exynos4_timer_resources(); +static void __init mct_init_dt(struct device_node *np, unsigned int int_type) +{ + u32 nr_irqs, i; + + mct_int_type = int_type; + + /* This driver uses only one global timer interrupt */ + mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); + + /* + * Find out the number of local irqs specified. The local + * timer irqs are specified after the four global timer + * irqs are specified. + */ + nr_irqs = of_irq_count(np); + for (i = MCT_L0_IRQ; i < nr_irqs; i++) + mct_irqs[i] = irq_of_parse_and_map(np, i); + + exynos4_timer_resources(np, of_iomap(np, 0)); exynos4_clocksource_init(); exynos4_clockevent_init(); } + + +static void __init mct_init_spi(struct device_node *np) +{ + return mct_init_dt(np, MCT_INT_SPI); +} + +static void __init mct_init_ppi(struct device_node *np) +{ + return mct_init_dt(np, MCT_INT_PPI); +} +CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi); +CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 488c14cc8dbf..08d0c418c94a 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -54,62 +54,100 @@ struct sh_cmt_priv { struct clocksource cs; unsigned long total_cycles; bool cs_enabled; + + /* callbacks for CMSTR and CMCSR access */ + unsigned long (*read_control)(void __iomem *base, unsigned long offs); + void (*write_control)(void __iomem *base, unsigned long offs, + unsigned long value); + + /* callbacks for CMCNT and CMCOR access */ + unsigned long (*read_count)(void __iomem *base, unsigned long offs); + void (*write_count)(void __iomem *base, unsigned long offs, + unsigned long value); }; -static DEFINE_RAW_SPINLOCK(sh_cmt_lock); +/* Examples of supported CMT timer register layouts and I/O access widths: + * + * "16-bit counter and 16-bit control" as found on sh7263: + * CMSTR 0xfffec000 16-bit + * CMCSR 0xfffec002 16-bit + * CMCNT 0xfffec004 16-bit + * CMCOR 0xfffec006 16-bit + * + * "32-bit counter and 16-bit control" as found on sh7372, sh73a0, r8a7740: + * CMSTR 0xffca0000 16-bit + * CMCSR 0xffca0060 16-bit + * CMCNT 0xffca0064 32-bit + * CMCOR 0xffca0068 32-bit + */ + +static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) +{ + return ioread16(base + (offs << 1)); +} + +static unsigned long sh_cmt_read32(void __iomem *base, unsigned long offs) +{ + return ioread32(base + (offs << 2)); +} + +static void sh_cmt_write16(void __iomem *base, unsigned long offs, + unsigned long value) +{ + iowrite16(value, base + (offs << 1)); +} + +static void sh_cmt_write32(void __iomem *base, unsigned long offs, + unsigned long value) +{ + iowrite32(value, base + (offs << 2)); +} -#define CMSTR -1 /* shared register */ #define CMCSR 0 /* channel register */ #define CMCNT 1 /* channel register */ #define CMCOR 2 /* channel register */ -static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr) +static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) { struct sh_timer_config *cfg = p->pdev->dev.platform_data; - void __iomem *base = p->mapbase; - unsigned long offs; - - if (reg_nr == CMSTR) { - offs = 0; - base -= cfg->channel_offset; - } else - offs = reg_nr; - - if (p->width == 16) - offs <<= 1; - else { - offs <<= 2; - if ((reg_nr == CMCNT) || (reg_nr == CMCOR)) - return ioread32(base + offs); - } - return ioread16(base + offs); + return p->read_control(p->mapbase - cfg->channel_offset, 0); } -static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr, - unsigned long value) +static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) +{ + return p->read_control(p->mapbase, CMCSR); +} + +static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p) +{ + return p->read_count(p->mapbase, CMCNT); +} + +static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, + unsigned long value) { struct sh_timer_config *cfg = p->pdev->dev.platform_data; - void __iomem *base = p->mapbase; - unsigned long offs; - - if (reg_nr == CMSTR) { - offs = 0; - base -= cfg->channel_offset; - } else - offs = reg_nr; - - if (p->width == 16) - offs <<= 1; - else { - offs <<= 2; - if ((reg_nr == CMCNT) || (reg_nr == CMCOR)) { - iowrite32(value, base + offs); - return; - } - } - iowrite16(value, base + offs); + p->write_control(p->mapbase - cfg->channel_offset, 0, value); +} + +static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, + unsigned long value) +{ + p->write_control(p->mapbase, CMCSR, value); +} + +static inline void sh_cmt_write_cmcnt(struct sh_cmt_priv *p, + unsigned long value) +{ + p->write_count(p->mapbase, CMCNT, value); +} + +static inline void sh_cmt_write_cmcor(struct sh_cmt_priv *p, + unsigned long value) +{ + p->write_count(p->mapbase, CMCOR, value); } static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p, @@ -118,15 +156,15 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p, unsigned long v1, v2, v3; int o1, o2; - o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit; + o1 = sh_cmt_read_cmcsr(p) & p->overflow_bit; /* Make sure the timer value is stable. Stolen from acpi_pm.c */ do { o2 = o1; - v1 = sh_cmt_read(p, CMCNT); - v2 = sh_cmt_read(p, CMCNT); - v3 = sh_cmt_read(p, CMCNT); - o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit; + v1 = sh_cmt_read_cmcnt(p); + v2 = sh_cmt_read_cmcnt(p); + v3 = sh_cmt_read_cmcnt(p); + o1 = sh_cmt_read_cmcsr(p) & p->overflow_bit; } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); @@ -134,6 +172,7 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p, return v2; } +static DEFINE_RAW_SPINLOCK(sh_cmt_lock); static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) { @@ -142,14 +181,14 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) /* start stop register shared by multiple timer channels */ raw_spin_lock_irqsave(&sh_cmt_lock, flags); - value = sh_cmt_read(p, CMSTR); + value = sh_cmt_read_cmstr(p); if (start) value |= 1 << cfg->timer_bit; else value &= ~(1 << cfg->timer_bit); - sh_cmt_write(p, CMSTR, value); + sh_cmt_write_cmstr(p, value); raw_spin_unlock_irqrestore(&sh_cmt_lock, flags); } @@ -173,14 +212,14 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) /* configure channel, periodic mode and maximum timeout */ if (p->width == 16) { *rate = clk_get_rate(p->clk) / 512; - sh_cmt_write(p, CMCSR, 0x43); + sh_cmt_write_cmcsr(p, 0x43); } else { *rate = clk_get_rate(p->clk) / 8; - sh_cmt_write(p, CMCSR, 0x01a4); + sh_cmt_write_cmcsr(p, 0x01a4); } - sh_cmt_write(p, CMCOR, 0xffffffff); - sh_cmt_write(p, CMCNT, 0); + sh_cmt_write_cmcor(p, 0xffffffff); + sh_cmt_write_cmcnt(p, 0); /* * According to the sh73a0 user's manual, as CMCNT can be operated @@ -194,12 +233,12 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) * take RCLKx2 at maximum. */ for (k = 0; k < 100; k++) { - if (!sh_cmt_read(p, CMCNT)) + if (!sh_cmt_read_cmcnt(p)) break; udelay(1); } - if (sh_cmt_read(p, CMCNT)) { + if (sh_cmt_read_cmcnt(p)) { dev_err(&p->pdev->dev, "cannot clear CMCNT\n"); ret = -ETIMEDOUT; goto err1; @@ -222,7 +261,7 @@ static void sh_cmt_disable(struct sh_cmt_priv *p) sh_cmt_start_stop_ch(p, 0); /* disable interrupts in CMT block */ - sh_cmt_write(p, CMCSR, 0); + sh_cmt_write_cmcsr(p, 0); /* stop clock */ clk_disable(p->clk); @@ -270,7 +309,7 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p, if (new_match > p->max_match_value) new_match = p->max_match_value; - sh_cmt_write(p, CMCOR, new_match); + sh_cmt_write_cmcor(p, new_match); now = sh_cmt_get_counter(p, &has_wrapped); if (has_wrapped && (new_match > p->match_value)) { @@ -346,7 +385,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) struct sh_cmt_priv *p = dev_id; /* clear flags */ - sh_cmt_write(p, CMCSR, sh_cmt_read(p, CMCSR) & p->clear_bits); + sh_cmt_write_cmcsr(p, sh_cmt_read_cmcsr(p) & p->clear_bits); /* update clock source counter to begin with if enabled * the wrap flag should be cleared by the timer specific @@ -625,14 +664,6 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name, unsigned long clockevent_rating, unsigned long clocksource_rating) { - if (p->width == (sizeof(p->max_match_value) * 8)) - p->max_match_value = ~0; - else - p->max_match_value = (1 << p->width) - 1; - - p->match_value = p->max_match_value; - raw_spin_lock_init(&p->lock); - if (clockevent_rating) sh_cmt_register_clockevent(p, name, clockevent_rating); @@ -657,8 +688,6 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) goto err0; } - platform_set_drvdata(pdev, p); - res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&p->pdev->dev, "failed to get I/O memory\n"); @@ -693,32 +722,51 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) goto err1; } + p->read_control = sh_cmt_read16; + p->write_control = sh_cmt_write16; + if (resource_size(res) == 6) { p->width = 16; + p->read_count = sh_cmt_read16; + p->write_count = sh_cmt_write16; p->overflow_bit = 0x80; p->clear_bits = ~0x80; } else { p->width = 32; + p->read_count = sh_cmt_read32; + p->write_count = sh_cmt_write32; p->overflow_bit = 0x8000; p->clear_bits = ~0xc000; } + if (p->width == (sizeof(p->max_match_value) * 8)) + p->max_match_value = ~0; + else + p->max_match_value = (1 << p->width) - 1; + + p->match_value = p->max_match_value; + raw_spin_lock_init(&p->lock); + ret = sh_cmt_register(p, (char *)dev_name(&p->pdev->dev), cfg->clockevent_rating, cfg->clocksource_rating); if (ret) { dev_err(&p->pdev->dev, "registration failed\n"); - goto err1; + goto err2; } p->cs_enabled = false; ret = setup_irq(irq, &p->irqaction); if (ret) { dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); - goto err1; + goto err2; } + platform_set_drvdata(pdev, p); + return 0; +err2: + clk_put(p->clk); err1: iounmap(p->mapbase); @@ -751,7 +799,6 @@ static int sh_cmt_probe(struct platform_device *pdev) ret = sh_cmt_setup(p, pdev); if (ret) { kfree(p); - platform_set_drvdata(pdev, NULL); pm_runtime_idle(&pdev->dev); return ret; } @@ -791,7 +838,7 @@ static void __exit sh_cmt_exit(void) } early_platform_init("earlytimer", &sh_cmt_device_driver); -module_init(sh_cmt_init); +subsys_initcall(sh_cmt_init); module_exit(sh_cmt_exit); MODULE_AUTHOR("Magnus Damm"); diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 83943e27cfac..4aac9ee0d0c0 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -386,7 +386,7 @@ static void __exit sh_mtu2_exit(void) } early_platform_init("earlytimer", &sh_mtu2_device_driver); -module_init(sh_mtu2_init); +subsys_initcall(sh_mtu2_init); module_exit(sh_mtu2_exit); MODULE_AUTHOR("Magnus Damm"); diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index b4502edce2a1..78b8dae49628 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -549,7 +549,7 @@ static void __exit sh_tmu_exit(void) } early_platform_init("earlytimer", &sh_tmu_device_driver); -module_init(sh_tmu_init); +subsys_initcall(sh_tmu_init); module_exit(sh_tmu_exit); MODULE_AUTHOR("Magnus Damm"); diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c index 4086b9167159..0ce85e29769b 100644 --- a/drivers/clocksource/sunxi_timer.c +++ b/drivers/clocksource/sunxi_timer.c @@ -23,7 +23,7 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/sunxi_timer.h> -#include <linux/clk-provider.h> +#include <linux/clk/sunxi.h> #define TIMER_CTL_REG 0x00 #define TIMER_CTL_ENABLE (1 << 0) @@ -123,7 +123,7 @@ void __init sunxi_timer_init(void) if (irq <= 0) panic("Can't parse IRQ"); - of_clk_init(NULL); + sunxi_init_clocks(); clk = of_clk_get(node, 0); if (IS_ERR(clk)) diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 0bde03feb095..ae877b021b54 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -154,29 +154,12 @@ static struct irqaction tegra_timer_irq = { .dev_id = &tegra_clockevent, }; -static const struct of_device_id timer_match[] __initconst = { - { .compatible = "nvidia,tegra20-timer" }, - {} -}; - -static const struct of_device_id rtc_match[] __initconst = { - { .compatible = "nvidia,tegra20-rtc" }, - {} -}; - -static void __init tegra20_init_timer(void) +static void __init tegra20_init_timer(struct device_node *np) { - struct device_node *np; struct clk *clk; unsigned long rate; int ret; - np = of_find_matching_node(NULL, timer_match); - if (!np) { - pr_err("Failed to find timer DT node\n"); - BUG(); - } - timer_reg_base = of_iomap(np, 0); if (!timer_reg_base) { pr_err("Can't map timer registers\n"); @@ -189,7 +172,7 @@ static void __init tegra20_init_timer(void) BUG(); } - clk = clk_get_sys("timer", NULL); + clk = of_clk_get(np, 0); if (IS_ERR(clk)) { pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n"); rate = 12000000; @@ -200,30 +183,6 @@ static void __init tegra20_init_timer(void) of_node_put(np); - np = of_find_matching_node(NULL, rtc_match); - if (!np) { - pr_err("Failed to find RTC DT node\n"); - BUG(); - } - - rtc_base = of_iomap(np, 0); - if (!rtc_base) { - pr_err("Can't map RTC registers"); - BUG(); - } - - /* - * rtc registers are used by read_persistent_clock, keep the rtc clock - * enabled - */ - clk = clk_get_sys("rtc-tegra", NULL); - if (IS_ERR(clk)) - pr_warn("Unable to get rtc-tegra clock\n"); - else - clk_prepare_enable(clk); - - of_node_put(np); - switch (rate) { case 12000000: timer_writel(0x000b, TIMERUS_USEC_CFG); @@ -259,12 +218,34 @@ static void __init tegra20_init_timer(void) tegra_clockevent.irq = tegra_timer_irq.irq; clockevents_config_and_register(&tegra_clockevent, 1000000, 0x1, 0x1fffffff); -#ifdef CONFIG_HAVE_ARM_TWD - twd_local_timer_of_register(); -#endif +} +CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); + +static void __init tegra20_init_rtc(struct device_node *np) +{ + struct clk *clk; + + rtc_base = of_iomap(np, 0); + if (!rtc_base) { + pr_err("Can't map RTC registers"); + BUG(); + } + + /* + * rtc registers are used by read_persistent_clock, keep the rtc clock + * enabled + */ + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) + pr_warn("Unable to get rtc-tegra clock\n"); + else + clk_prepare_enable(clk); + + of_node_put(np); + register_persistent_clock(NULL, tegra_read_persistent_clock); } -CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer); +CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); #ifdef CONFIG_PM static u32 usec_config; diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 8efc86b5b5dd..64f553f04fa4 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -129,22 +129,10 @@ static struct irqaction irq = { .dev_id = &clockevent, }; -static struct of_device_id vt8500_timer_ids[] = { - { .compatible = "via,vt8500-timer" }, - { } -}; - -static void __init vt8500_timer_init(void) +static void __init vt8500_timer_init(struct device_node *np) { - struct device_node *np; int timer_irq; - np = of_find_matching_node(NULL, vt8500_timer_ids); - if (!np) { - pr_err("%s: Timer description missing from Device Tree\n", - __func__); - return; - } regbase = of_iomap(np, 0); if (!regbase) { pr_err("%s: Missing iobase description in Device Tree\n", @@ -177,4 +165,4 @@ static void __init vt8500_timer_init(void) 4, 0xf0000000); } -CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init) +CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 937bc286591f..57a8774f0b4e 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -730,7 +730,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { cpumask_copy(policy->cpus, perf->shared_cpu_map); } - cpumask_copy(policy->related_cpus, perf->shared_cpu_map); #ifdef CONFIG_SMP dmi_check_system(sw_any_bug_dmi_table); @@ -742,7 +741,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) if (check_amd_hwpstate_cpu(cpu) && !acpi_pstate_strict) { cpumask_clear(policy->cpus); cpumask_set_cpu(cpu, policy->cpus); - cpumask_copy(policy->related_cpus, cpu_sibling_mask(cpu)); policy->shared_type = CPUFREQ_SHARED_TYPE_HW; pr_info_once(PFX "overriding BIOS provided _PSD data\n"); } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 2fd779eb1ed1..bfd6273fd873 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -180,15 +180,19 @@ static void cpufreq_stats_free_sysfs(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - if (!cpufreq_frequency_get_table(cpu)) + if (!policy) return; - if (policy && !policy_is_shared(policy)) { + if (!cpufreq_frequency_get_table(cpu)) + goto put_ref; + + if (!policy_is_shared(policy)) { pr_debug("%s: Free sysfs stat\n", __func__); sysfs_remove_group(&policy->kobj, &stats_attr_group); } - if (policy) - cpufreq_cpu_put(policy); + +put_ref: + cpufreq_cpu_put(policy); } static int cpufreq_stats_create_table(struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index f6dd1e761129..ad72922919ed 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -358,14 +358,14 @@ static void intel_pstate_sysfs_expose_params(void) static int intel_pstate_min_pstate(void) { u64 value; - rdmsrl(0xCE, value); + rdmsrl(MSR_PLATFORM_INFO, value); return (value >> 40) & 0xFF; } static int intel_pstate_max_pstate(void) { u64 value; - rdmsrl(0xCE, value); + rdmsrl(MSR_PLATFORM_INFO, value); return (value >> 8) & 0xFF; } @@ -373,7 +373,7 @@ static int intel_pstate_turbo_pstate(void) { u64 value; int nont, ret; - rdmsrl(0x1AD, value); + rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value); nont = intel_pstate_max_pstate(); ret = ((value) & 255); if (ret <= nont) @@ -454,7 +454,7 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, sample->idletime_us * 100, sample->duration_us); core_pct = div64_u64(sample->aperf * 100, sample->mperf); - sample->freq = cpu->pstate.turbo_pstate * core_pct * 1000; + sample->freq = cpu->pstate.max_pstate * core_pct * 1000; sample->core_pct_busy = div_s64((sample->pstate_pct_busy * core_pct), 100); @@ -752,6 +752,29 @@ static struct cpufreq_driver intel_pstate_driver = { static int __initdata no_load; +static int intel_pstate_msrs_not_valid(void) +{ + /* Check that all the msr's we are using are valid. */ + u64 aperf, mperf, tmp; + + rdmsrl(MSR_IA32_APERF, aperf); + rdmsrl(MSR_IA32_MPERF, mperf); + + if (!intel_pstate_min_pstate() || + !intel_pstate_max_pstate() || + !intel_pstate_turbo_pstate()) + return -ENODEV; + + rdmsrl(MSR_IA32_APERF, tmp); + if (!(tmp - aperf)) + return -ENODEV; + + rdmsrl(MSR_IA32_MPERF, tmp); + if (!(tmp - mperf)) + return -ENODEV; + + return 0; +} static int __init intel_pstate_init(void) { int cpu, rc = 0; @@ -764,6 +787,9 @@ static int __init intel_pstate_init(void) if (!id) return -ENODEV; + if (intel_pstate_msrs_not_valid()) + return -ENODEV; + pr_info("Intel P-state driver initializing.\n"); all_cpu_data = vmalloc(sizeof(void *) * num_possible_cpus()); diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index b2a0a0726a54..cf268b14ae9a 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1650,11 +1650,7 @@ struct caam_alg_template { }; static struct caam_alg_template driver_algs[] = { - /* - * single-pass ipsec_esp descriptor - * authencesn(*,*) is also registered, although not present - * explicitly here. - */ + /* single-pass ipsec_esp descriptor */ { .name = "authenc(hmac(md5),cbc(aes))", .driver_name = "authenc-hmac-md5-cbc-aes-caam", @@ -2217,9 +2213,7 @@ static int __init caam_algapi_init(void) for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { /* TODO: check if h/w supports alg */ struct caam_crypto_alg *t_alg; - bool done = false; -authencesn: t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); @@ -2233,25 +2227,8 @@ authencesn: dev_warn(ctrldev, "%s alg registration failed\n", t_alg->crypto_alg.cra_driver_name); kfree(t_alg); - } else { + } else list_add_tail(&t_alg->entry, &priv->alg_list); - if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD && - !memcmp(driver_algs[i].name, "authenc", 7) && - !done) { - char *name; - - name = driver_algs[i].name; - memmove(name + 10, name + 7, strlen(name) - 7); - memcpy(name + 7, "esn", 3); - - name = driver_algs[i].driver_name; - memmove(name + 10, name + 7, strlen(name) - 7); - memcpy(name + 7, "esn", 3); - - done = true; - goto authencesn; - } - } } if (!list_empty(&priv->alg_list)) dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n", diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h index cf15e7813801..762aeff626ac 100644 --- a/drivers/crypto/caam/compat.h +++ b/drivers/crypto/caam/compat.h @@ -23,7 +23,6 @@ #include <linux/types.h> #include <linux/debugfs.h> #include <linux/circ_buf.h> -#include <linux/string.h> #include <net/xfrm.h> #include <crypto/algapi.h> diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 09b184adf31b..5b2b5e61e4f9 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -38,7 +38,6 @@ #include <linux/spinlock.h> #include <linux/rtnetlink.h> #include <linux/slab.h> -#include <linux/string.h> #include <crypto/algapi.h> #include <crypto/aes.h> @@ -1974,11 +1973,7 @@ struct talitos_alg_template { }; static struct talitos_alg_template driver_algs[] = { - /* - * AEAD algorithms. These use a single-pass ipsec_esp descriptor. - * authencesn(*,*) is also registered, although not present - * explicitly here. - */ + /* AEAD algorithms. These use a single-pass ipsec_esp descriptor */ { .type = CRYPTO_ALG_TYPE_AEAD, .alg.crypto = { .cra_name = "authenc(hmac(sha1),cbc(aes))", @@ -2820,9 +2815,7 @@ static int talitos_probe(struct platform_device *ofdev) if (hw_supports(dev, driver_algs[i].desc_hdr_template)) { struct talitos_crypto_alg *t_alg; char *name = NULL; - bool authenc = false; -authencesn: t_alg = talitos_alg_alloc(dev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); @@ -2837,8 +2830,6 @@ authencesn: err = crypto_register_alg( &t_alg->algt.alg.crypto); name = t_alg->algt.alg.crypto.cra_driver_name; - authenc = authenc ? !authenc : - !(bool)memcmp(name, "authenc", 7); break; case CRYPTO_ALG_TYPE_AHASH: err = crypto_register_ahash( @@ -2851,25 +2842,8 @@ authencesn: dev_err(dev, "%s alg registration failed\n", name); kfree(t_alg); - } else { + } else list_add_tail(&t_alg->entry, &priv->alg_list); - if (authenc) { - struct crypto_alg *alg = - &driver_algs[i].alg.crypto; - - name = alg->cra_name; - memmove(name + 10, name + 7, - strlen(name) - 7); - memcpy(name + 7, "esn", 3); - - name = alg->cra_driver_name; - memmove(name + 10, name + 7, - strlen(name) - 7); - memcpy(name + 7, "esn", 3); - - goto authencesn; - } - } } } if (!list_empty(&priv->alg_list)) diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index c599558faeda..43a5329d4483 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1001,6 +1001,13 @@ static inline void convert_burst(u32 *maxburst) *maxburst = 0; } +static inline void convert_slave_id(struct dw_dma_chan *dwc) +{ + struct dw_dma *dw = to_dw_dma(dwc->chan.device); + + dwc->dma_sconfig.slave_id -= dw->request_line_base; +} + static int set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) { @@ -1015,6 +1022,7 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) convert_burst(&dwc->dma_sconfig.src_maxburst); convert_burst(&dwc->dma_sconfig.dst_maxburst); + convert_slave_id(dwc); return 0; } @@ -1276,9 +1284,9 @@ static struct dma_chan *dw_dma_xlate(struct of_phandle_args *dma_spec, if (dma_spec->args_count != 3) return NULL; - fargs.req = be32_to_cpup(dma_spec->args+0); - fargs.src = be32_to_cpup(dma_spec->args+1); - fargs.dst = be32_to_cpup(dma_spec->args+2); + fargs.req = dma_spec->args[0]; + fargs.src = dma_spec->args[1]; + fargs.dst = dma_spec->args[2]; if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS || fargs.src >= dw->nr_masters || @@ -1628,6 +1636,7 @@ dw_dma_parse_dt(struct platform_device *pdev) static int dw_probe(struct platform_device *pdev) { + const struct platform_device_id *match; struct dw_dma_platform_data *pdata; struct resource *io; struct dw_dma *dw; @@ -1711,6 +1720,11 @@ static int dw_probe(struct platform_device *pdev) memcpy(dw->data_width, pdata->data_width, 4); } + /* Get the base request line if set */ + match = platform_get_device_id(pdev); + if (match) + dw->request_line_base = (unsigned int)match->driver_data; + /* Calculate all channel mask before DMA setup */ dw->all_chan_mask = (1 << nr_channels) - 1; @@ -1906,7 +1920,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table); #endif static const struct platform_device_id dw_dma_ids[] = { - { "INTL9C60", 0 }, + /* Name, Request Line Base */ + { "INTL9C60", (kernel_ulong_t)16 }, { } }; diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index cf0ce5c77d60..4d02c3669b75 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -247,6 +247,7 @@ struct dw_dma { /* hardware configuration */ unsigned char nr_masters; unsigned char data_width[4]; + unsigned int request_line_base; struct dw_dma_chan chan[0]; }; diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index b70e3815c459..8f3c947b0029 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -32,6 +32,38 @@ #define DEV_NAME "max77693-muic" #define DELAY_MS_DEFAULT 20000 /* unit: millisecond */ +/* + * Default value of MAX77693 register to bring up MUIC device. + * If user don't set some initial value for MUIC device through platform data, + * extcon-max77693 driver use 'default_init_data' to bring up base operation + * of MAX77693 MUIC device. + */ +struct max77693_reg_data default_init_data[] = { + { + /* STATUS2 - [3]ChgDetRun */ + .addr = MAX77693_MUIC_REG_STATUS2, + .data = STATUS2_CHGDETRUN_MASK, + }, { + /* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */ + .addr = MAX77693_MUIC_REG_INTMASK1, + .data = INTMASK1_ADC1K_MASK + | INTMASK1_ADC_MASK, + }, { + /* INTMASK2 - Unmask [0]ChgTypM */ + .addr = MAX77693_MUIC_REG_INTMASK2, + .data = INTMASK2_CHGTYP_MASK, + }, { + /* INTMASK3 - Mask all of interrupts */ + .addr = MAX77693_MUIC_REG_INTMASK3, + .data = 0x0, + }, { + /* CDETCTRL2 */ + .addr = MAX77693_MUIC_REG_CDETCTRL2, + .data = CDETCTRL2_VIDRMEN_MASK + | CDETCTRL2_DXOVPEN_MASK, + }, +}; + enum max77693_muic_adc_debounce_time { ADC_DEBOUNCE_TIME_5MS = 0, ADC_DEBOUNCE_TIME_10MS, @@ -1045,8 +1077,9 @@ static int max77693_muic_probe(struct platform_device *pdev) { struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); - struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; struct max77693_muic_info *info; + struct max77693_reg_data *init_data; + int num_init_data; int delay_jiffies; int ret; int i; @@ -1145,15 +1178,25 @@ static int max77693_muic_probe(struct platform_device *pdev) goto err_irq; } - /* Initialize MUIC register by using platform data */ - for (i = 0 ; i < muic_pdata->num_init_data ; i++) { - enum max77693_irq_source irq_src = MAX77693_IRQ_GROUP_NR; + + /* Initialize MUIC register by using platform data or default data */ + if (pdata->muic_data) { + init_data = pdata->muic_data->init_data; + num_init_data = pdata->muic_data->num_init_data; + } else { + init_data = default_init_data; + num_init_data = ARRAY_SIZE(default_init_data); + } + + for (i = 0 ; i < num_init_data ; i++) { + enum max77693_irq_source irq_src + = MAX77693_IRQ_GROUP_NR; max77693_write_reg(info->max77693->regmap_muic, - muic_pdata->init_data[i].addr, - muic_pdata->init_data[i].data); + init_data[i].addr, + init_data[i].data); - switch (muic_pdata->init_data[i].addr) { + switch (init_data[i].addr) { case MAX77693_MUIC_REG_INTMASK1: irq_src = MUIC_INT1; break; @@ -1167,22 +1210,40 @@ static int max77693_muic_probe(struct platform_device *pdev) if (irq_src < MAX77693_IRQ_GROUP_NR) info->max77693->irq_masks_cur[irq_src] - = muic_pdata->init_data[i].data; + = init_data[i].data; } - /* - * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB - * h/w path of COMP2/COMN1 on CONTROL1 register. - */ - if (muic_pdata->path_uart) - info->path_uart = muic_pdata->path_uart; - else - info->path_uart = CONTROL1_SW_UART; + if (pdata->muic_data) { + struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; - if (muic_pdata->path_usb) - info->path_usb = muic_pdata->path_usb; - else + /* + * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB + * h/w path of COMP2/COMN1 on CONTROL1 register. + */ + if (muic_pdata->path_uart) + info->path_uart = muic_pdata->path_uart; + else + info->path_uart = CONTROL1_SW_UART; + + if (muic_pdata->path_usb) + info->path_usb = muic_pdata->path_usb; + else + info->path_usb = CONTROL1_SW_USB; + + /* + * Default delay time for detecting cable state + * after certain time. + */ + if (muic_pdata->detcable_delay_ms) + delay_jiffies = + msecs_to_jiffies(muic_pdata->detcable_delay_ms); + else + delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); + } else { info->path_usb = CONTROL1_SW_USB; + info->path_uart = CONTROL1_SW_UART; + delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); + } /* Set initial path for UART */ max77693_muic_set_path(info, info->path_uart, true); @@ -1208,10 +1269,6 @@ static int max77693_muic_probe(struct platform_device *pdev) * driver should notify cable state to upper layer. */ INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq); - if (muic_pdata->detcable_delay_ms) - delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms); - else - delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); schedule_delayed_work(&info->wq_detcable, delay_jiffies); return ret; diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index e636d950ad6c..69641bcae325 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -712,29 +712,45 @@ static int max8997_muic_probe(struct platform_device *pdev) goto err_irq; } - /* Initialize registers according to platform data */ if (pdata->muic_pdata) { - struct max8997_muic_platform_data *mdata = info->muic_pdata; - - for (i = 0; i < mdata->num_init_data; i++) { - max8997_write_reg(info->muic, mdata->init_data[i].addr, - mdata->init_data[i].data); + struct max8997_muic_platform_data *muic_pdata + = pdata->muic_pdata; + + /* Initialize registers according to platform data */ + for (i = 0; i < muic_pdata->num_init_data; i++) { + max8997_write_reg(info->muic, + muic_pdata->init_data[i].addr, + muic_pdata->init_data[i].data); } - } - /* - * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB - * h/w path of COMP2/COMN1 on CONTROL1 register. - */ - if (pdata->muic_pdata->path_uart) - info->path_uart = pdata->muic_pdata->path_uart; - else - info->path_uart = CONTROL1_SW_UART; + /* + * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB + * h/w path of COMP2/COMN1 on CONTROL1 register. + */ + if (muic_pdata->path_uart) + info->path_uart = muic_pdata->path_uart; + else + info->path_uart = CONTROL1_SW_UART; - if (pdata->muic_pdata->path_usb) - info->path_usb = pdata->muic_pdata->path_usb; - else + if (muic_pdata->path_usb) + info->path_usb = muic_pdata->path_usb; + else + info->path_usb = CONTROL1_SW_USB; + + /* + * Default delay time for detecting cable state + * after certain time. + */ + if (muic_pdata->detcable_delay_ms) + delay_jiffies = + msecs_to_jiffies(muic_pdata->detcable_delay_ms); + else + delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); + } else { + info->path_uart = CONTROL1_SW_UART; info->path_usb = CONTROL1_SW_USB; + delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); + } /* Set initial path for UART */ max8997_muic_set_path(info, info->path_uart, true); @@ -751,10 +767,6 @@ static int max8997_muic_probe(struct platform_device *pdev) * driver should notify cable state to upper layer. */ INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq); - if (pdata->muic_pdata->detcable_delay_ms) - delay_jiffies = msecs_to_jiffies(pdata->muic_pdata->detcable_delay_ms); - else - delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); schedule_delayed_work(&info->wq_detcable, delay_jiffies); return 0; diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 9b00072a020f..42c759a4d047 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -53,6 +53,24 @@ config EFI_VARS Subsequent efibootmgr releases may be found at: <http://linux.dell.com/efibootmgr> +config EFI_VARS_PSTORE + bool "Register efivars backend for pstore" + depends on EFI_VARS && PSTORE + default y + help + Say Y here to enable use efivars as a backend to pstore. This + will allow writing console messages, crash dumps, or anything + else supported by pstore to EFI variables. + +config EFI_VARS_PSTORE_DEFAULT_DISABLE + bool "Disable using efivars as a pstore backend by default" + depends on EFI_VARS_PSTORE + default n + help + Saying Y here will disable the use of efivars as a storage + backend for pstore by default. This setting can be overridden + using the efivars module's pstore_disable parameter. + config EFI_PCDP bool "Console device selection via EFI PCDP or HCDP table" depends on ACPI && EFI && IA64 diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index fe62aa392239..7acafb80fd4c 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -103,6 +103,11 @@ MODULE_VERSION(EFIVARS_VERSION); */ #define GUID_LEN 36 +static bool efivars_pstore_disable = + IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); + +module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); + /* * The maximum size of VariableName + Data = 1024 * Therefore, it's reasonable to save that much @@ -165,6 +170,7 @@ efivar_create_sysfs_entry(struct efivars *efivars, static void efivar_update_sysfs_entries(struct work_struct *); static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); +static bool efivar_wq_enabled = true; /* Return the number of unicode characters in data */ static unsigned long @@ -1309,9 +1315,7 @@ static const struct inode_operations efivarfs_dir_inode_operations = { .create = efivarfs_create, }; -static struct pstore_info efi_pstore_info; - -#ifdef CONFIG_PSTORE +#ifdef CONFIG_EFI_VARS_PSTORE static int efi_pstore_open(struct pstore_info *psi) { @@ -1441,7 +1445,7 @@ static int efi_pstore_write(enum pstore_type_id type, spin_unlock_irqrestore(&efivars->lock, flags); - if (reason == KMSG_DUMP_OOPS) + if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled) schedule_work(&efivar_work); *id = part; @@ -1514,38 +1518,6 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, return 0; } -#else -static int efi_pstore_open(struct pstore_info *psi) -{ - return 0; -} - -static int efi_pstore_close(struct pstore_info *psi) -{ - return 0; -} - -static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, int *count, - struct timespec *timespec, - char **buf, struct pstore_info *psi) -{ - return -1; -} - -static int efi_pstore_write(enum pstore_type_id type, - enum kmsg_dump_reason reason, u64 *id, - unsigned int part, int count, size_t size, - struct pstore_info *psi) -{ - return 0; -} - -static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, - struct timespec time, struct pstore_info *psi) -{ - return 0; -} -#endif static struct pstore_info efi_pstore_info = { .owner = THIS_MODULE, @@ -1557,6 +1529,24 @@ static struct pstore_info efi_pstore_info = { .erase = efi_pstore_erase, }; +static void efivar_pstore_register(struct efivars *efivars) +{ + efivars->efi_pstore_info = efi_pstore_info; + efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); + if (efivars->efi_pstore_info.buf) { + efivars->efi_pstore_info.bufsize = 1024; + efivars->efi_pstore_info.data = efivars; + spin_lock_init(&efivars->efi_pstore_info.buf_lock); + pstore_register(&efivars->efi_pstore_info); + } +} +#else +static void efivar_pstore_register(struct efivars *efivars) +{ + return; +} +#endif + static ssize_t efivar_create(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) @@ -1716,6 +1706,31 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor) return found; } +/* + * Returns the size of variable_name, in bytes, including the + * terminating NULL character, or variable_name_size if no NULL + * character is found among the first variable_name_size bytes. + */ +static unsigned long var_name_strnsize(efi_char16_t *variable_name, + unsigned long variable_name_size) +{ + unsigned long len; + efi_char16_t c; + + /* + * The variable name is, by definition, a NULL-terminated + * string, so make absolutely sure that variable_name_size is + * the value we expect it to be. If not, return the real size. + */ + for (len = 2; len <= variable_name_size; len += sizeof(c)) { + c = variable_name[(len / sizeof(c)) - 1]; + if (!c) + break; + } + + return min(len, variable_name_size); +} + static void efivar_update_sysfs_entries(struct work_struct *work) { struct efivars *efivars = &__efivars; @@ -1756,10 +1771,13 @@ static void efivar_update_sysfs_entries(struct work_struct *work) if (!found) { kfree(variable_name); break; - } else + } else { + variable_name_size = var_name_strnsize(variable_name, + variable_name_size); efivar_create_sysfs_entry(efivars, variable_name_size, variable_name, &vendor); + } } } @@ -1958,6 +1976,35 @@ void unregister_efivars(struct efivars *efivars) } EXPORT_SYMBOL_GPL(unregister_efivars); +/* + * Print a warning when duplicate EFI variables are encountered and + * disable the sysfs workqueue since the firmware is buggy. + */ +static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, + unsigned long len16) +{ + size_t i, len8 = len16 / sizeof(efi_char16_t); + char *s8; + + /* + * Disable the workqueue since the algorithm it uses for + * detecting new variables won't work with this buggy + * implementation of GetNextVariableName(). + */ + efivar_wq_enabled = false; + + s8 = kzalloc(len8, GFP_KERNEL); + if (!s8) + return; + + for (i = 0; i < len8; i++) + s8[i] = s16[i]; + + printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", + s8, vendor_guid); + kfree(s8); +} + int register_efivars(struct efivars *efivars, const struct efivar_operations *ops, struct kobject *parent_kobj) @@ -2006,6 +2053,24 @@ int register_efivars(struct efivars *efivars, &vendor_guid); switch (status) { case EFI_SUCCESS: + variable_name_size = var_name_strnsize(variable_name, + variable_name_size); + + /* + * Some firmware implementations return the + * same variable name on multiple calls to + * get_next_variable(). Terminate the loop + * immediately as there is no guarantee that + * we'll ever see a different variable name, + * and may end up looping here forever. + */ + if (variable_is_present(variable_name, &vendor_guid)) { + dup_variable_bug(variable_name, &vendor_guid, + variable_name_size); + status = EFI_NOT_FOUND; + break; + } + efivar_create_sysfs_entry(efivars, variable_name_size, variable_name, @@ -2025,15 +2090,8 @@ int register_efivars(struct efivars *efivars, if (error) unregister_efivars(efivars); - efivars->efi_pstore_info = efi_pstore_info; - - efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); - if (efivars->efi_pstore_info.buf) { - efivars->efi_pstore_info.bufsize = 1024; - efivars->efi_pstore_info.data = efivars; - spin_lock_init(&efivars->efi_pstore_info.buf_lock); - pstore_register(&efivars->efi_pstore_info); - } + if (!efivars_pstore_disable) + efivar_pstore_register(efivars); register_filesystem(&efivarfs_type); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 93aaadf99f28..b166e30b3bc4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -227,12 +227,6 @@ config GPIO_TS5500 blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 LCD port. -config GPIO_VT8500 - bool "VIA/Wondermedia SoC GPIO Support" - depends on ARCH_VT8500 - help - Say yes here to support the VT8500/WM8505/WM8650 GPIO controller. - config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 22e07bc9fcb5..a274d7df3c8c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -80,7 +80,6 @@ obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o -obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index b3643ff007e4..99e0fa49fcbd 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -1122,8 +1122,12 @@ int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) #ifdef CONFIG_PLAT_S3C24XX static int s3c24xx_gpiolib_fbank_to_irq(struct gpio_chip *chip, unsigned offset) { - if (offset < 4) - return IRQ_EINT0 + offset; + if (offset < 4) { + if (soc_is_s3c2412()) + return IRQ_EINT0_2412 + offset; + else + return IRQ_EINT0 + offset; + } if (offset < 8) return IRQ_EINT4 + offset - 4; @@ -3024,6 +3028,7 @@ static __init int samsung_gpiolib_init(void) static const struct of_device_id exynos_pinctrl_ids[] = { { .compatible = "samsung,exynos4210-pinctrl", }, { .compatible = "samsung,exynos4x12-pinctrl", }, + { .compatible = "samsung,exynos5250-pinctrl", }, { .compatible = "samsung,exynos5440-pinctrl", }, }; for_each_matching_node(pctrl_np, exynos_pinctrl_ids) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 414ad912232f..e3956359202c 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -72,6 +72,7 @@ struct tegra_gpio_bank { u32 oe[4]; u32 int_enb[4]; u32 int_lvl[4]; + u32 wake_enb[4]; #endif }; @@ -333,15 +334,31 @@ static int tegra_gpio_suspend(struct device *dev) bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio)); bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio)); bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio)); + + /* Enable gpio irq for wake up source */ + tegra_gpio_writel(bank->wake_enb[p], + GPIO_INT_ENB(gpio)); } } local_irq_restore(flags); return 0; } -static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable) +static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) { struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + int gpio = d->hwirq; + u32 port, bit, mask; + + port = GPIO_PORT(gpio); + bit = GPIO_BIT(gpio); + mask = BIT(bit); + + if (enable) + bank->wake_enb[port] |= mask; + else + bank->wake_enb[port] &= ~mask; + return irq_set_irq_wake(bank->irq, enable); } #endif @@ -353,7 +370,7 @@ static struct irq_chip tegra_gpio_irq_chip = { .irq_unmask = tegra_gpio_irq_unmask, .irq_set_type = tegra_gpio_irq_set_type, #ifdef CONFIG_PM_SLEEP - .irq_set_wake = tegra_gpio_wake_enable, + .irq_set_wake = tegra_gpio_irq_set_wake, #endif }; diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c deleted file mode 100644 index 81683ca35ac1..000000000000 --- a/drivers/gpio/gpio-vt8500.c +++ /dev/null @@ -1,355 +0,0 @@ -/* drivers/gpio/gpio-vt8500.c - * - * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> - * Based on arch/arm/mach-vt8500/gpio.c: - * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.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/module.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/platform_device.h> -#include <linux/bitops.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/of_device.h> - -/* - We handle GPIOs by bank, each bank containing up to 32 GPIOs covered - by one set of registers (although not all may be valid). - - Because different SoC's have different register offsets, we pass the - register offsets as data in vt8500_gpio_dt_ids[]. - - A value of NO_REG is used to indicate that this register is not - supported. Only used for ->en at the moment. -*/ - -#define NO_REG 0xFFFF - -/* - * struct vt8500_gpio_bank_regoffsets - * @en: offset to enable register of the bank - * @dir: offset to direction register of the bank - * @data_out: offset to the data out register of the bank - * @data_in: offset to the data in register of the bank - * @ngpio: highest valid pin in this bank - */ - -struct vt8500_gpio_bank_regoffsets { - unsigned int en; - unsigned int dir; - unsigned int data_out; - unsigned int data_in; - unsigned char ngpio; -}; - -struct vt8500_gpio_data { - unsigned int num_banks; - struct vt8500_gpio_bank_regoffsets banks[]; -}; - -#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \ -{ \ - .en = __en, \ - .dir = __dir, \ - .data_out = __out, \ - .data_in = __in, \ - .ngpio = __ngpio, \ -} - -static struct vt8500_gpio_data vt8500_data = { - .num_banks = 7, - .banks = { - VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9), - VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26), - VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28), - VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31), - VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19), - VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19), - VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23), - }, -}; - -static struct vt8500_gpio_data wm8505_data = { - .num_banks = 10, - .banks = { - VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), - VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8), - VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32), - VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6), - VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16), - VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25), - VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5), - VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5), - VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), - VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), - VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), - }, -}; - -/* - * No information about which bits are valid so we just make - * them all available until its figured out. - */ -static struct vt8500_gpio_data wm8650_data = { - .num_banks = 9, - .banks = { - VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32), - VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32), - VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32), - VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32), - VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32), - VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32), - VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32), - VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32), - VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32), - VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), - }, -}; - -struct vt8500_gpio_chip { - struct gpio_chip chip; - - const struct vt8500_gpio_bank_regoffsets *regs; - void __iomem *base; -}; - -struct vt8500_data { - struct vt8500_gpio_chip *chip; - void __iomem *iobase; - int num_banks; -}; - - -#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) - -static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - u32 val; - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - - if (vt8500_chip->regs->en == NO_REG) - return 0; - - val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en); - val |= BIT(offset); - writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en); - - return 0; -} - -static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - u32 val; - - if (vt8500_chip->regs->en == NO_REG) - return; - - val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en); - val &= ~BIT(offset); - writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en); -} - -static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - - u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir); - val &= ~BIT(offset); - writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir); - - return 0; -} - -static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - - u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir); - val |= BIT(offset); - writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir); - - if (value) { - val = readl_relaxed(vt8500_chip->base + - vt8500_chip->regs->data_out); - val |= BIT(offset); - writel_relaxed(val, vt8500_chip->base + - vt8500_chip->regs->data_out); - } - return 0; -} - -static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - - return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >> - offset) & 1; -} - -static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset, - int value) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - - u32 val = readl_relaxed(vt8500_chip->base + - vt8500_chip->regs->data_out); - if (value) - val |= BIT(offset); - else - val &= ~BIT(offset); - - writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out); -} - -static int vt8500_of_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, u32 *flags) -{ - /* bank if specificed in gpiospec->args[0] */ - if (flags) - *flags = gpiospec->args[2]; - - return gpiospec->args[1]; -} - -static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base, - const struct vt8500_gpio_data *data) -{ - struct vt8500_data *priv; - struct vt8500_gpio_chip *vtchip; - struct gpio_chip *chip; - int i; - int pin_cnt = 0; - - priv = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_data), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "failed to allocate memory\n"); - return -ENOMEM; - } - - priv->chip = devm_kzalloc(&pdev->dev, - sizeof(struct vt8500_gpio_chip) * data->num_banks, - GFP_KERNEL); - if (!priv->chip) { - dev_err(&pdev->dev, "failed to allocate chip memory\n"); - return -ENOMEM; - } - - priv->iobase = base; - priv->num_banks = data->num_banks; - platform_set_drvdata(pdev, priv); - - vtchip = priv->chip; - - for (i = 0; i < data->num_banks; i++) { - vtchip[i].base = base; - vtchip[i].regs = &data->banks[i]; - - chip = &vtchip[i].chip; - - chip->of_xlate = vt8500_of_xlate; - chip->of_gpio_n_cells = 3; - chip->of_node = pdev->dev.of_node; - - chip->request = vt8500_gpio_request; - chip->free = vt8500_gpio_free; - chip->direction_input = vt8500_gpio_direction_input; - chip->direction_output = vt8500_gpio_direction_output; - chip->get = vt8500_gpio_get_value; - chip->set = vt8500_gpio_set_value; - chip->can_sleep = 0; - chip->base = pin_cnt; - chip->ngpio = data->banks[i].ngpio; - - pin_cnt += data->banks[i].ngpio; - - gpiochip_add(chip); - } - return 0; -} - -static struct of_device_id vt8500_gpio_dt_ids[] = { - { .compatible = "via,vt8500-gpio", .data = &vt8500_data, }, - { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, }, - { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, }, - { /* Sentinel */ }, -}; - -static int vt8500_gpio_probe(struct platform_device *pdev) -{ - int ret; - void __iomem *gpio_base; - struct resource *res; - const struct of_device_id *of_id = - of_match_device(vt8500_gpio_dt_ids, &pdev->dev); - - if (!of_id) { - dev_err(&pdev->dev, "No matching driver data\n"); - return -ENODEV; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Unable to get IO resource\n"); - return -ENODEV; - } - - gpio_base = devm_request_and_ioremap(&pdev->dev, res); - if (!gpio_base) { - dev_err(&pdev->dev, "Unable to map GPIO registers\n"); - return -ENOMEM; - } - - ret = vt8500_add_chips(pdev, gpio_base, of_id->data); - - return ret; -} - -static int vt8500_gpio_remove(struct platform_device *pdev) -{ - int i; - int ret; - struct vt8500_data *priv = platform_get_drvdata(pdev); - struct vt8500_gpio_chip *vtchip = priv->chip; - - for (i = 0; i < priv->num_banks; i++) { - ret = gpiochip_remove(&vtchip[i].chip); - if (ret) - dev_warn(&pdev->dev, "gpiochip_remove returned %d\n", - ret); - } - - return 0; -} - -static struct platform_driver vt8500_gpio_driver = { - .probe = vt8500_gpio_probe, - .remove = vt8500_gpio_remove, - .driver = { - .name = "vt8500-gpio", - .owner = THIS_MODULE, - .of_match_table = vt8500_gpio_dt_ids, - }, -}; - -module_platform_driver(vt8500_gpio_driver); - -MODULE_DESCRIPTION("VT8500 GPIO Driver"); -MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); -MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index a71a54a3e3f7..5150df6cba08 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -193,7 +193,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (!np) return; - do { + for (;; index++) { ret = of_parse_phandle_with_args(np, "gpio-ranges", "#gpio-range-cells", index, &pinspec); if (ret) @@ -222,8 +222,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (ret) break; - - } while (index++); + } } #else diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 36493ce71f9a..98cc14725ba9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -38,11 +38,12 @@ /* position control register for hardware window 0, 2 ~ 4.*/ #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) #define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16) -/* size control register for hardware window 0. */ -#define VIDOSD_C_SIZE_W0 (VIDOSD_BASE + 0x08) -/* alpha control register for hardware window 1 ~ 4. */ -#define VIDOSD_C(win) (VIDOSD_BASE + 0x18 + (win) * 16) -/* size control register for hardware window 1 ~ 4. */ +/* + * size control register for hardware windows 0 and alpha control register + * for hardware windows 1 ~ 4 + */ +#define VIDOSD_C(win) (VIDOSD_BASE + 0x08 + (win) * 16) +/* size control register for hardware windows 1 ~ 2. */ #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) @@ -50,9 +51,9 @@ #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) /* color key control register for hardware window 1 ~ 4. */ -#define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + (x * 8)) +#define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + ((x - 1) * 8)) /* color key value register for hardware window 1 ~ 4. */ -#define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + (x * 8)) +#define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) /* FIMD has totally five hardware windows. */ #define WINDOWS_NR 5 @@ -109,9 +110,9 @@ struct fimd_context { #ifdef CONFIG_OF static const struct of_device_id fimd_driver_dt_match[] = { - { .compatible = "samsung,exynos4-fimd", + { .compatible = "samsung,exynos4210-fimd", .data = &exynos4_fimd_driver_data }, - { .compatible = "samsung,exynos5-fimd", + { .compatible = "samsung,exynos5250-fimd", .data = &exynos5_fimd_driver_data }, {}, }; @@ -581,7 +582,7 @@ static void fimd_win_commit(struct device *dev, int zpos) if (win != 3 && win != 4) { u32 offset = VIDOSD_D(win); if (win == 0) - offset = VIDOSD_C_SIZE_W0; + offset = VIDOSD_C(win); val = win_data->ovl_width * win_data->ovl_height; writel(val, ctx->regs + offset); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 3b0da0378acf..47a493c8a71f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -48,8 +48,14 @@ /* registers for base address */ #define G2D_SRC_BASE_ADDR 0x0304 +#define G2D_SRC_COLOR_MODE 0x030C +#define G2D_SRC_LEFT_TOP 0x0310 +#define G2D_SRC_RIGHT_BOTTOM 0x0314 #define G2D_SRC_PLANE2_BASE_ADDR 0x0318 #define G2D_DST_BASE_ADDR 0x0404 +#define G2D_DST_COLOR_MODE 0x040C +#define G2D_DST_LEFT_TOP 0x0410 +#define G2D_DST_RIGHT_BOTTOM 0x0414 #define G2D_DST_PLANE2_BASE_ADDR 0x0418 #define G2D_PAT_BASE_ADDR 0x0500 #define G2D_MSK_BASE_ADDR 0x0520 @@ -82,7 +88,7 @@ #define G2D_DMA_LIST_DONE_COUNT_OFFSET 17 /* G2D_DMA_HOLD_CMD */ -#define G2D_USET_HOLD (1 << 2) +#define G2D_USER_HOLD (1 << 2) #define G2D_LIST_HOLD (1 << 1) #define G2D_BITBLT_HOLD (1 << 0) @@ -91,13 +97,27 @@ #define G2D_START_NHOLT (1 << 1) #define G2D_START_BITBLT (1 << 0) +/* buffer color format */ +#define G2D_FMT_XRGB8888 0 +#define G2D_FMT_ARGB8888 1 +#define G2D_FMT_RGB565 2 +#define G2D_FMT_XRGB1555 3 +#define G2D_FMT_ARGB1555 4 +#define G2D_FMT_XRGB4444 5 +#define G2D_FMT_ARGB4444 6 +#define G2D_FMT_PACKED_RGB888 7 +#define G2D_FMT_A8 11 +#define G2D_FMT_L8 12 + +/* buffer valid length */ +#define G2D_LEN_MIN 1 +#define G2D_LEN_MAX 8000 + #define G2D_CMDLIST_SIZE (PAGE_SIZE / 4) #define G2D_CMDLIST_NUM 64 #define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) #define G2D_CMDLIST_DATA_NUM (G2D_CMDLIST_SIZE / sizeof(u32) - 2) -#define MAX_BUF_ADDR_NR 6 - /* maximum buffer pool size of userptr is 64MB as default */ #define MAX_POOL (64 * 1024 * 1024) @@ -106,6 +126,17 @@ enum { BUF_TYPE_USERPTR, }; +enum g2d_reg_type { + REG_TYPE_NONE = -1, + REG_TYPE_SRC, + REG_TYPE_SRC_PLANE2, + REG_TYPE_DST, + REG_TYPE_DST_PLANE2, + REG_TYPE_PAT, + REG_TYPE_MSK, + MAX_REG_TYPE_NR +}; + /* cmdlist data structure */ struct g2d_cmdlist { u32 head; @@ -113,6 +144,42 @@ struct g2d_cmdlist { u32 last; /* last data offset */ }; +/* + * A structure of buffer description + * + * @format: color format + * @left_x: the x coordinates of left top corner + * @top_y: the y coordinates of left top corner + * @right_x: the x coordinates of right bottom corner + * @bottom_y: the y coordinates of right bottom corner + * + */ +struct g2d_buf_desc { + unsigned int format; + unsigned int left_x; + unsigned int top_y; + unsigned int right_x; + unsigned int bottom_y; +}; + +/* + * A structure of buffer information + * + * @map_nr: manages the number of mapped buffers + * @reg_types: stores regitster type in the order of requested command + * @handles: stores buffer handle in its reg_type position + * @types: stores buffer type in its reg_type position + * @descs: stores buffer description in its reg_type position + * + */ +struct g2d_buf_info { + unsigned int map_nr; + enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; + unsigned long handles[MAX_REG_TYPE_NR]; + unsigned int types[MAX_REG_TYPE_NR]; + struct g2d_buf_desc descs[MAX_REG_TYPE_NR]; +}; + struct drm_exynos_pending_g2d_event { struct drm_pending_event base; struct drm_exynos_g2d_event event; @@ -131,14 +198,11 @@ struct g2d_cmdlist_userptr { bool in_pool; bool out_of_list; }; - struct g2d_cmdlist_node { struct list_head list; struct g2d_cmdlist *cmdlist; - unsigned int map_nr; - unsigned long handles[MAX_BUF_ADDR_NR]; - unsigned int obj_type[MAX_BUF_ADDR_NR]; dma_addr_t dma_addr; + struct g2d_buf_info buf_info; struct drm_exynos_pending_g2d_event *event; }; @@ -188,6 +252,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) struct exynos_drm_subdrv *subdrv = &g2d->subdrv; int nr; int ret; + struct g2d_buf_info *buf_info; init_dma_attrs(&g2d->cmdlist_dma_attrs); dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs); @@ -209,11 +274,17 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) } for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) { + unsigned int i; + node[nr].cmdlist = g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE; node[nr].dma_addr = g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE; + buf_info = &node[nr].buf_info; + for (i = 0; i < MAX_REG_TYPE_NR; i++) + buf_info->reg_types[i] = REG_TYPE_NONE; + list_add_tail(&node[nr].list, &g2d->free_cmdlist); } @@ -450,7 +521,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, DMA_BIDIRECTIONAL); if (ret < 0) { DRM_ERROR("failed to map sgt with dma region.\n"); - goto err_free_sgt; + goto err_sg_free_table; } g2d_userptr->dma_addr = sgt->sgl[0].dma_address; @@ -467,8 +538,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, return &g2d_userptr->dma_addr; -err_free_sgt: +err_sg_free_table: sg_free_table(sgt); + +err_free_sgt: kfree(sgt); sgt = NULL; @@ -506,36 +579,172 @@ static void g2d_userptr_free_all(struct drm_device *drm_dev, g2d->current_pool = 0; } +static enum g2d_reg_type g2d_get_reg_type(int reg_offset) +{ + enum g2d_reg_type reg_type; + + switch (reg_offset) { + case G2D_SRC_BASE_ADDR: + case G2D_SRC_COLOR_MODE: + case G2D_SRC_LEFT_TOP: + case G2D_SRC_RIGHT_BOTTOM: + reg_type = REG_TYPE_SRC; + break; + case G2D_SRC_PLANE2_BASE_ADDR: + reg_type = REG_TYPE_SRC_PLANE2; + break; + case G2D_DST_BASE_ADDR: + case G2D_DST_COLOR_MODE: + case G2D_DST_LEFT_TOP: + case G2D_DST_RIGHT_BOTTOM: + reg_type = REG_TYPE_DST; + break; + case G2D_DST_PLANE2_BASE_ADDR: + reg_type = REG_TYPE_DST_PLANE2; + break; + case G2D_PAT_BASE_ADDR: + reg_type = REG_TYPE_PAT; + break; + case G2D_MSK_BASE_ADDR: + reg_type = REG_TYPE_MSK; + break; + default: + reg_type = REG_TYPE_NONE; + DRM_ERROR("Unknown register offset![%d]\n", reg_offset); + break; + }; + + return reg_type; +} + +static unsigned long g2d_get_buf_bpp(unsigned int format) +{ + unsigned long bpp; + + switch (format) { + case G2D_FMT_XRGB8888: + case G2D_FMT_ARGB8888: + bpp = 4; + break; + case G2D_FMT_RGB565: + case G2D_FMT_XRGB1555: + case G2D_FMT_ARGB1555: + case G2D_FMT_XRGB4444: + case G2D_FMT_ARGB4444: + bpp = 2; + break; + case G2D_FMT_PACKED_RGB888: + bpp = 3; + break; + default: + bpp = 1; + break; + } + + return bpp; +} + +static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc, + enum g2d_reg_type reg_type, + unsigned long size) +{ + unsigned int width, height; + unsigned long area; + + /* + * check source and destination buffers only. + * so the others are always valid. + */ + if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST) + return true; + + width = buf_desc->right_x - buf_desc->left_x; + if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) { + DRM_ERROR("width[%u] is out of range!\n", width); + return false; + } + + height = buf_desc->bottom_y - buf_desc->top_y; + if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) { + DRM_ERROR("height[%u] is out of range!\n", height); + return false; + } + + area = (unsigned long)width * (unsigned long)height * + g2d_get_buf_bpp(buf_desc->format); + if (area > size) { + DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size); + return false; + } + + return true; +} + static int g2d_map_cmdlist_gem(struct g2d_data *g2d, struct g2d_cmdlist_node *node, struct drm_device *drm_dev, struct drm_file *file) { struct g2d_cmdlist *cmdlist = node->cmdlist; + struct g2d_buf_info *buf_info = &node->buf_info; int offset; + int ret; int i; - for (i = 0; i < node->map_nr; i++) { + for (i = 0; i < buf_info->map_nr; i++) { + struct g2d_buf_desc *buf_desc; + enum g2d_reg_type reg_type; + int reg_pos; unsigned long handle; dma_addr_t *addr; - offset = cmdlist->last - (i * 2 + 1); - handle = cmdlist->data[offset]; + reg_pos = cmdlist->last - 2 * (i + 1); + + offset = cmdlist->data[reg_pos]; + handle = cmdlist->data[reg_pos + 1]; + + reg_type = g2d_get_reg_type(offset); + if (reg_type == REG_TYPE_NONE) { + ret = -EFAULT; + goto err; + } + + buf_desc = &buf_info->descs[reg_type]; + + if (buf_info->types[reg_type] == BUF_TYPE_GEM) { + unsigned long size; + + size = exynos_drm_gem_get_size(drm_dev, handle, file); + if (!size) { + ret = -EFAULT; + goto err; + } + + if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, + size)) { + ret = -EFAULT; + goto err; + } - if (node->obj_type[i] == BUF_TYPE_GEM) { addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, file); if (IS_ERR(addr)) { - node->map_nr = i; - return -EFAULT; + ret = -EFAULT; + goto err; } } else { struct drm_exynos_g2d_userptr g2d_userptr; if (copy_from_user(&g2d_userptr, (void __user *)handle, sizeof(struct drm_exynos_g2d_userptr))) { - node->map_nr = i; - return -EFAULT; + ret = -EFAULT; + goto err; + } + + if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, + g2d_userptr.size)) { + ret = -EFAULT; + goto err; } addr = g2d_userptr_get_dma_addr(drm_dev, @@ -544,16 +753,21 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, file, &handle); if (IS_ERR(addr)) { - node->map_nr = i; - return -EFAULT; + ret = -EFAULT; + goto err; } } - cmdlist->data[offset] = *addr; - node->handles[i] = handle; + cmdlist->data[reg_pos + 1] = *addr; + buf_info->reg_types[i] = reg_type; + buf_info->handles[reg_type] = handle; } return 0; + +err: + buf_info->map_nr = i; + return ret; } static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, @@ -561,22 +775,33 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, struct drm_file *filp) { struct exynos_drm_subdrv *subdrv = &g2d->subdrv; + struct g2d_buf_info *buf_info = &node->buf_info; int i; - for (i = 0; i < node->map_nr; i++) { - unsigned long handle = node->handles[i]; + for (i = 0; i < buf_info->map_nr; i++) { + struct g2d_buf_desc *buf_desc; + enum g2d_reg_type reg_type; + unsigned long handle; + + reg_type = buf_info->reg_types[i]; + + buf_desc = &buf_info->descs[reg_type]; + handle = buf_info->handles[reg_type]; - if (node->obj_type[i] == BUF_TYPE_GEM) + if (buf_info->types[reg_type] == BUF_TYPE_GEM) exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, filp); else g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, false); - node->handles[i] = 0; + buf_info->reg_types[i] = REG_TYPE_NONE; + buf_info->handles[reg_type] = 0; + buf_info->types[reg_type] = 0; + memset(buf_desc, 0x00, sizeof(*buf_desc)); } - node->map_nr = 0; + buf_info->map_nr = 0; } static void g2d_dma_start(struct g2d_data *g2d, @@ -589,10 +814,6 @@ static void g2d_dma_start(struct g2d_data *g2d, pm_runtime_get_sync(g2d->dev); clk_enable(g2d->gate_clk); - /* interrupt enable */ - writel_relaxed(G2D_INTEN_ACF | G2D_INTEN_UCF | G2D_INTEN_GCF, - g2d->regs + G2D_INTEN); - writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR); writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND); } @@ -643,7 +864,6 @@ static void g2d_runqueue_worker(struct work_struct *work) struct g2d_data *g2d = container_of(work, struct g2d_data, runqueue_work); - mutex_lock(&g2d->runqueue_mutex); clk_disable(g2d->gate_clk); pm_runtime_put_sync(g2d->dev); @@ -724,20 +944,14 @@ static int g2d_check_reg_offset(struct device *dev, int i; for (i = 0; i < nr; i++) { - index = cmdlist->last - 2 * (i + 1); + struct g2d_buf_info *buf_info = &node->buf_info; + struct g2d_buf_desc *buf_desc; + enum g2d_reg_type reg_type; + unsigned long value; - if (for_addr) { - /* check userptr buffer type. */ - reg_offset = (cmdlist->data[index] & - ~0x7fffffff) >> 31; - if (reg_offset) { - node->obj_type[i] = BUF_TYPE_USERPTR; - cmdlist->data[index] &= ~G2D_BUF_USERPTR; - } - } + index = cmdlist->last - 2 * (i + 1); reg_offset = cmdlist->data[index] & ~0xfffff000; - if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END) goto err; if (reg_offset % 4) @@ -753,8 +967,60 @@ static int g2d_check_reg_offset(struct device *dev, if (!for_addr) goto err; - if (node->obj_type[i] != BUF_TYPE_USERPTR) - node->obj_type[i] = BUF_TYPE_GEM; + reg_type = g2d_get_reg_type(reg_offset); + if (reg_type == REG_TYPE_NONE) + goto err; + + /* check userptr buffer type. */ + if ((cmdlist->data[index] & ~0x7fffffff) >> 31) { + buf_info->types[reg_type] = BUF_TYPE_USERPTR; + cmdlist->data[index] &= ~G2D_BUF_USERPTR; + } else + buf_info->types[reg_type] = BUF_TYPE_GEM; + break; + case G2D_SRC_COLOR_MODE: + case G2D_DST_COLOR_MODE: + if (for_addr) + goto err; + + reg_type = g2d_get_reg_type(reg_offset); + if (reg_type == REG_TYPE_NONE) + goto err; + + buf_desc = &buf_info->descs[reg_type]; + value = cmdlist->data[index + 1]; + + buf_desc->format = value & 0xf; + break; + case G2D_SRC_LEFT_TOP: + case G2D_DST_LEFT_TOP: + if (for_addr) + goto err; + + reg_type = g2d_get_reg_type(reg_offset); + if (reg_type == REG_TYPE_NONE) + goto err; + + buf_desc = &buf_info->descs[reg_type]; + value = cmdlist->data[index + 1]; + + buf_desc->left_x = value & 0x1fff; + buf_desc->top_y = (value & 0x1fff0000) >> 16; + break; + case G2D_SRC_RIGHT_BOTTOM: + case G2D_DST_RIGHT_BOTTOM: + if (for_addr) + goto err; + + reg_type = g2d_get_reg_type(reg_offset); + if (reg_type == REG_TYPE_NONE) + goto err; + + buf_desc = &buf_info->descs[reg_type]; + value = cmdlist->data[index + 1]; + + buf_desc->right_x = value & 0x1fff; + buf_desc->bottom_y = (value & 0x1fff0000) >> 16; break; default: if (for_addr) @@ -860,9 +1126,23 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR; cmdlist->data[cmdlist->last++] = 0; + /* + * 'LIST_HOLD' command should be set to the DMA_HOLD_CMD_REG + * and GCF bit should be set to INTEN register if user wants + * G2D interrupt event once current command list execution is + * finished. + * Otherwise only ACF bit should be set to INTEN register so + * that one interrupt is occured after all command lists + * have been completed. + */ if (node->event) { + cmdlist->data[cmdlist->last++] = G2D_INTEN; + cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF | G2D_INTEN_GCF; cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD; cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD; + } else { + cmdlist->data[cmdlist->last++] = G2D_INTEN; + cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF; } /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */ @@ -887,7 +1167,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, if (ret < 0) goto err_free_event; - node->map_nr = req->cmd_buf_nr; + node->buf_info.map_nr = req->cmd_buf_nr; if (req->cmd_buf_nr) { struct drm_exynos_g2d_cmd *cmd_buf; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 67e17ce112b6..0e6fe000578c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -164,6 +164,27 @@ out: exynos_gem_obj = NULL; } +unsigned long exynos_drm_gem_get_size(struct drm_device *dev, + unsigned int gem_handle, + struct drm_file *file_priv) +{ + struct exynos_drm_gem_obj *exynos_gem_obj; + struct drm_gem_object *obj; + + obj = drm_gem_object_lookup(dev, file_priv, gem_handle); + if (!obj) { + DRM_ERROR("failed to lookup gem object.\n"); + return 0; + } + + exynos_gem_obj = to_exynos_gem_obj(obj); + + drm_gem_object_unreference_unlocked(obj); + + return exynos_gem_obj->buffer->size; +} + + struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, unsigned long size) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 35ebac47dc2b..468766bee450 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -130,6 +130,11 @@ int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +/* get buffer size to gem handle. */ +unsigned long exynos_drm_gem_get_size(struct drm_device *dev, + unsigned int gem_handle, + struct drm_file *file_priv); + /* initialize gem object. */ int exynos_drm_gem_init_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 13ccbd4bcfaa..9504b0cd825a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -117,13 +117,12 @@ static struct edid *vidi_get_edid(struct device *dev, } edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; - edid = kzalloc(edid_len, GFP_KERNEL); + edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL); if (!edid) { DRM_DEBUG_KMS("failed to allocate edid\n"); return ERR_PTR(-ENOMEM); } - memcpy(edid, ctx->raw_edid, edid_len); return edid; } @@ -563,12 +562,11 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, return -EINVAL; } edid_len = (1 + raw_edid->extensions) * EDID_LENGTH; - ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL); + ctx->raw_edid = kmemdup(raw_edid, edid_len, GFP_KERNEL); if (!ctx->raw_edid) { DRM_DEBUG_KMS("failed to allocate raw_edid.\n"); return -ENOMEM; } - memcpy(ctx->raw_edid, raw_edid, edid_len); } else { /* * with connection = 0, free raw_edid diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e919aba29b3d..2f4f72f07047 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -818,7 +818,7 @@ static void mixer_win_disable(void *ctx, int win) mixer_ctx->win_data[win].enabled = false; } -int mixer_check_timing(void *ctx, struct fb_videomode *timing) +static int mixer_check_timing(void *ctx, struct fb_videomode *timing) { struct mixer_context *mixer_ctx = ctx; u32 w, h; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0a8eceb75902..e9b57893db2b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -125,6 +125,11 @@ MODULE_PARM_DESC(preliminary_hw_support, "Enable Haswell and ValleyView Support. " "(default: false)"); +int i915_disable_power_well __read_mostly = 0; +module_param_named(disable_power_well, i915_disable_power_well, int, 0600); +MODULE_PARM_DESC(disable_power_well, + "Disable the power well when possible (default: false)"); + static struct drm_driver driver; extern int intel_agp_enabled; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e95337c97459..01769e2a9953 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1398,6 +1398,7 @@ extern int i915_enable_fbc __read_mostly; extern bool i915_enable_hangcheck __read_mostly; extern int i915_enable_ppgtt __read_mostly; extern unsigned int i915_preliminary_hw_support __read_mostly; +extern int i915_disable_power_well __read_mostly; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 287b42c9d1a8..b20d50192fcc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5771,6 +5771,11 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } + if (is_cpu_edp) + intel_crtc->cpu_transcoder = TRANSCODER_EDP; + else + intel_crtc->cpu_transcoder = pipe; + /* We are not sure yet this won't happen. */ WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); @@ -5837,11 +5842,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; int ret; - if (IS_HASWELL(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) - intel_crtc->cpu_transcoder = TRANSCODER_EDP; - else - intel_crtc->cpu_transcoder = pipe; - drm_vblank_pre_modeset(dev, pipe); ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a3730e0289e5..bee8cb6108a7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -321,9 +321,6 @@ void intel_panel_enable_backlight(struct drm_device *dev, if (dev_priv->backlight_level == 0) dev_priv->backlight_level = intel_panel_get_max_backlight(dev); - dev_priv->backlight_enabled = true; - intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); - if (INTEL_INFO(dev)->gen >= 4) { uint32_t reg, tmp; @@ -359,12 +356,12 @@ void intel_panel_enable_backlight(struct drm_device *dev, } set_level: - /* Check the current backlight level and try to set again if it's zero. - * On some machines, BLC_PWM_CPU_CTL is cleared to zero automatically - * when BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1 are written. + /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. + * BLC_PWM_CPU_CTL may be cleared to zero automatically when these + * registers are set. */ - if (!intel_panel_get_backlight(dev)) - intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); + dev_priv->backlight_enabled = true; + intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); } static void intel_panel_init_backlight(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a1794c6df1bf..adca00783e61 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4079,6 +4079,9 @@ void intel_set_power_well(struct drm_device *dev, bool enable) if (!IS_HASWELL(dev)) return; + if (!i915_disable_power_well && !enable) + return; + tmp = I915_READ(HSW_PWR_WELL_DRIVER); is_enabled = tmp & HSW_PWR_WELL_STATE; enable_requested = tmp & HSW_PWR_WELL_ENABLE; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 92e47e5c9564..c4388776f4e4 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -590,6 +590,9 @@ #define USB_VENDOR_ID_MONTEREY 0x0566 #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 +#define USB_VENDOR_ID_MSI 0x1770 +#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 + #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 @@ -684,6 +687,9 @@ #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 +#define USB_VENDOR_ID_REALTEK 0x0bda +#define USB_DEVICE_ID_REALTEK_READER 0x0152 + #define USB_VENDOR_ID_ROCCAT 0x1e7d #define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4 #define USB_DEVICE_ID_ROCCAT_ISKU 0x319c diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 7a1ebb867cf4..82e9211b3ca9 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -621,6 +621,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, { struct mt_device *td = hid_get_drvdata(hid); __s32 quirks = td->mtclass.quirks; + struct input_dev *input = field->hidinput->input; if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { @@ -670,13 +671,16 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, break; default: + if (usage->type) + input_event(input, usage->type, usage->code, + value); return; } if (usage->usage_index + 1 == field->report_count) { /* we only take into account the last report. */ if (usage->hid == td->last_slot_field) - mt_complete_slot(td, field->hidinput->input); + mt_complete_slot(td, input); if (field->index == td->last_field_index && td->num_received >= td->num_expected) diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index e0e6abf1cd3b..19b8360f2330 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,6 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, @@ -80,6 +81,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 17ba4f8bc12d..70b1808a08f4 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -186,8 +186,10 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, wq->rq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), wq->rq.memsize, &(wq->rq.dma_addr), GFP_KERNEL); - if (!wq->rq.queue) + if (!wq->rq.queue) { + ret = -ENOMEM; goto free_sq; + } PDBG("%s sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n", __func__, wq->sq.queue, (unsigned long long)virt_to_phys(wq->sq.queue), diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 439c35d4a669..ea93870266eb 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -620,7 +620,7 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data, goto bail; } - opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0x7f; dev->opstats[opcode].n_bytes += tlen; dev->opstats[opcode].n_packets++; diff --git a/drivers/infiniband/hw/qib/Kconfig b/drivers/infiniband/hw/qib/Kconfig index 8349f9c5064c..1e603a375069 100644 --- a/drivers/infiniband/hw/qib/Kconfig +++ b/drivers/infiniband/hw/qib/Kconfig @@ -1,7 +1,7 @@ config INFINIBAND_QIB - tristate "QLogic PCIe HCA support" + tristate "Intel PCIe HCA support" depends on 64BIT ---help--- - This is a low-level driver for QLogic PCIe QLE InfiniBand host - channel adapters. This driver does not support the QLogic + This is a low-level driver for Intel PCIe QLE InfiniBand host + channel adapters. This driver does not support the Intel HyperTransport card (model QHT7140). diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c index 5423edcab51f..216092477dfc 100644 --- a/drivers/infiniband/hw/qib/qib_driver.c +++ b/drivers/infiniband/hw/qib/qib_driver.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * @@ -63,8 +64,8 @@ MODULE_PARM_DESC(compat_ddr_negotiate, "Attempt pre-IBTA 1.2 DDR speed negotiation"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("QLogic <support@qlogic.com>"); -MODULE_DESCRIPTION("QLogic IB driver"); +MODULE_AUTHOR("Intel <ibsupport@intel.com>"); +MODULE_DESCRIPTION("Intel IB driver"); MODULE_VERSION(QIB_DRIVER_VERSION); /* diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index a099ac171e22..0232ae56b1fa 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation. * All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. @@ -51,7 +52,7 @@ static u32 qib_6120_iblink_state(u64); /* * This file contains all the chip-specific register information and - * access functions for the QLogic QLogic_IB PCI-Express chip. + * access functions for the Intel Intel_IB PCI-Express chip. * */ diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 50e33aa0b4e3..173f805790da 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Intel Corporation. All rights reserved. + * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * @@ -1138,7 +1138,7 @@ void qib_disable_after_error(struct qib_devdata *dd) static void qib_remove_one(struct pci_dev *); static int qib_init_one(struct pci_dev *, const struct pci_device_id *); -#define DRIVER_LOAD_MSG "QLogic " QIB_DRV_NAME " loaded: " +#define DRIVER_LOAD_MSG "Intel " QIB_DRV_NAME " loaded: " #define PFX QIB_DRV_NAME ": " static DEFINE_PCI_DEVICE_TABLE(qib_pci_tbl) = { @@ -1355,7 +1355,7 @@ static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dd = qib_init_iba6120_funcs(pdev, ent); #else qib_early_err(&pdev->dev, - "QLogic PCIE device 0x%x cannot work if CONFIG_PCI_MSI is not enabled\n", + "Intel PCIE device 0x%x cannot work if CONFIG_PCI_MSI is not enabled\n", ent->device); dd = ERR_PTR(-ENODEV); #endif @@ -1371,7 +1371,7 @@ static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) default: qib_early_err(&pdev->dev, - "Failing on unknown QLogic deviceid 0x%x\n", + "Failing on unknown Intel deviceid 0x%x\n", ent->device); ret = -ENODEV; } diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c index 50a8a0d4fe67..08a6c6d39e56 100644 --- a/drivers/infiniband/hw/qib/qib_sd7220.c +++ b/drivers/infiniband/hw/qib/qib_sd7220.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Intel Corporation. All rights reserved. + * Copyright (c) 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * @@ -44,7 +44,7 @@ #include "qib.h" #include "qib_7220.h" -#define SD7220_FW_NAME "qlogic/sd7220.fw" +#define SD7220_FW_NAME "intel/sd7220.fw" MODULE_FIRMWARE(SD7220_FW_NAME); /* diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index ba51a4715a1d..7c0ab16a2fe2 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Intel Corporation. All rights reserved. + * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. * @@ -2224,7 +2224,7 @@ int qib_register_ib_device(struct qib_devdata *dd) ibdev->dma_ops = &qib_dma_mapping_ops; snprintf(ibdev->node_desc, sizeof(ibdev->node_desc), - "QLogic Infiniband HCA %s", init_utsname()->nodename); + "Intel Infiniband HCA %s", init_utsname()->nodename); ret = ib_register_device(ibdev, qib_create_port_files); if (ret) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 67b0c1d23678..1ef880de3a41 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -758,9 +758,13 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ if (++priv->tx_outstanding == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", tx->qp->qp_num); - if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP)) - ipoib_warn(priv, "request notify on send CQ failed\n"); netif_stop_queue(dev); + rc = ib_req_notify_cq(priv->send_cq, + IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS); + if (rc < 0) + ipoib_warn(priv, "request notify on send CQ failed\n"); + else if (rc) + ipoib_send_comp_handler(priv->send_cq, dev); } } } diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 5c514d0711d1..c332fb98480d 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -130,7 +130,7 @@ config IRQ_REMAP # OMAP IOMMU support config OMAP_IOMMU bool "OMAP IOMMU Support" - depends on ARCH_OMAP + depends on ARCH_OMAP2PLUS select IOMMU_API config OMAP_IOVMM diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 98f555dafb55..b287ca33833d 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2466,18 +2466,16 @@ static int device_change_notifier(struct notifier_block *nb, /* allocate a protection domain if a device is added */ dma_domain = find_protection_domain(devid); - if (dma_domain) - goto out; - dma_domain = dma_ops_domain_alloc(); - if (!dma_domain) - goto out; - dma_domain->target_dev = devid; - - spin_lock_irqsave(&iommu_pd_list_lock, flags); - list_add_tail(&dma_domain->list, &iommu_pd_list); - spin_unlock_irqrestore(&iommu_pd_list_lock, flags); - - dev_data = get_dev_data(dev); + if (!dma_domain) { + dma_domain = dma_ops_domain_alloc(); + if (!dma_domain) + goto out; + dma_domain->target_dev = devid; + + spin_lock_irqsave(&iommu_pd_list_lock, flags); + list_add_tail(&dma_domain->list, &iommu_pd_list); + spin_unlock_irqrestore(&iommu_pd_list_lock, flags); + } dev->archdata.dma_ops = &amd_iommu_dma_ops; diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index b6ecddb63cd0..e3c2d74b7684 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -980,7 +980,7 @@ static void __init free_iommu_all(void) * BIOS should disable L2B micellaneous clock gating by setting * L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b */ -static void __init amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) +static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) { u32 value; diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index d56f8c17c5fe..7c11ff368d07 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -2,7 +2,6 @@ #include <linux/cpumask.h> #include <linux/kernel.h> #include <linux/string.h> -#include <linux/cpumask.h> #include <linux/errno.h> #include <linux/msi.h> #include <linux/irq.h> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index a350969e5efe..4a33351c25dc 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -25,6 +25,14 @@ config ARM_VIC_NR The maximum number of VICs available in the system, for power management. +config RENESAS_INTC_IRQPIN + bool + select IRQ_DOMAIN + +config RENESAS_IRQC + bool + select IRQ_DOMAIN + config VERSATILE_FPGA_IRQ bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 98e3b87bdf1b..48fbdf978494 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -2,10 +2,14 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o +obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o obj-$(CONFIG_METAG) += irq-metag-ext.o obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o +obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o +obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o +obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 04d86a9803f4..e8501dbaa0b7 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -31,6 +31,7 @@ struct combiner_chip_data { unsigned int irq_offset; unsigned int irq_mask; void __iomem *base; + unsigned int parent_irq; }; static struct irq_domain *combiner_irq_domain; @@ -87,22 +88,46 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } +#ifdef CONFIG_SMP +static int combiner_set_affinity(struct irq_data *d, + const struct cpumask *mask_val, bool force) +{ + struct combiner_chip_data *chip_data = irq_data_get_irq_chip_data(d); + struct irq_chip *chip = irq_get_chip(chip_data->parent_irq); + struct irq_data *data = irq_get_irq_data(chip_data->parent_irq); + + if (chip && chip->irq_set_affinity) + return chip->irq_set_affinity(data, mask_val, force); + else + return -EINVAL; +} +#endif + static struct irq_chip combiner_chip = { - .name = "COMBINER", - .irq_mask = combiner_mask_irq, - .irq_unmask = combiner_unmask_irq, + .name = "COMBINER", + .irq_mask = combiner_mask_irq, + .irq_unmask = combiner_unmask_irq, +#ifdef CONFIG_SMP + .irq_set_affinity = combiner_set_affinity, +#endif }; -static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq) +static unsigned int max_combiner_nr(void) { - unsigned int max_nr; - if (soc_is_exynos5250()) - max_nr = EXYNOS5_MAX_COMBINER_NR; + return EXYNOS5_MAX_COMBINER_NR; + else if (soc_is_exynos4412()) + return EXYNOS4412_MAX_COMBINER_NR; + else if (soc_is_exynos4212()) + return EXYNOS4212_MAX_COMBINER_NR; else - max_nr = EXYNOS4_MAX_COMBINER_NR; + return EXYNOS4210_MAX_COMBINER_NR; +} - if (combiner_nr >= max_nr) +static void __init combiner_cascade_irq(unsigned int combiner_nr, + unsigned int irq) +{ + if (combiner_nr >= max_combiner_nr()) BUG(); if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0) BUG(); @@ -110,12 +135,13 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i } static void __init combiner_init_one(unsigned int combiner_nr, - void __iomem *base) + void __iomem *base, unsigned int irq) { combiner_data[combiner_nr].base = base; combiner_data[combiner_nr].irq_offset = irq_find_mapping( combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER); combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); + combiner_data[combiner_nr].parent_irq = irq; /* Disable all interrupts */ __raw_writel(combiner_data[combiner_nr].irq_mask, @@ -166,23 +192,38 @@ static struct irq_domain_ops combiner_irq_domain_ops = { .map = combiner_irq_domain_map, }; +static unsigned int exynos4x12_combiner_extra_irq(int group) +{ + switch (group) { + case 16: + return IRQ_SPI(107); + case 17: + return IRQ_SPI(108); + case 18: + return IRQ_SPI(48); + case 19: + return IRQ_SPI(42); + default: + return 0; + } +} + void __init combiner_init(void __iomem *combiner_base, struct device_node *np) { int i, irq, irq_base; unsigned int max_nr, nr_irq; + max_nr = max_combiner_nr(); + if (np) { if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { - pr_warning("%s: number of combiners not specified, " + pr_info("%s: number of combiners not specified, " "setting default as %d.\n", - __func__, EXYNOS4_MAX_COMBINER_NR); - max_nr = EXYNOS4_MAX_COMBINER_NR; + __func__, max_nr); } - } else { - max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR : - EXYNOS4_MAX_COMBINER_NR; } + nr_irq = max_nr * MAX_IRQ_IN_COMBINER; irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); @@ -199,12 +240,15 @@ void __init combiner_init(void __iomem *combiner_base, } for (i = 0; i < max_nr; i++) { - combiner_init_one(i, combiner_base + (i >> 2) * 0x10); - irq = IRQ_SPI(i); + if (i < EXYNOS4210_MAX_COMBINER_NR || soc_is_exynos5250()) + irq = IRQ_SPI(i); + else + irq = exynos4x12_combiner_extra_irq(i); #ifdef CONFIG_OF if (np) irq = irq_of_parse_and_map(np, i); #endif + combiner_init_one(i, combiner_base + (i >> 2) * 0x10, irq); combiner_cascade_irq(i, irq); } } diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c new file mode 100644 index 000000000000..5a68e5accec1 --- /dev/null +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -0,0 +1,547 @@ +/* + * Renesas INTC External IRQ Pin Driver + * + * Copyright (C) 2013 Magnus Damm + * + * 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 + * + * 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/init.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_data/irq-renesas-intc-irqpin.h> + +#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */ + +#define INTC_IRQPIN_REG_SENSE 0 /* ICRn */ +#define INTC_IRQPIN_REG_PRIO 1 /* INTPRInn */ +#define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */ +#define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */ +#define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */ +#define INTC_IRQPIN_REG_NR 5 + +/* INTC external IRQ PIN hardware register access: + * + * SENSE is read-write 32-bit with 2-bits or 4-bits per IRQ (*) + * PRIO is read-write 32-bit with 4-bits per IRQ (**) + * SOURCE is read-only 32-bit or 8-bit with 1-bit per IRQ (***) + * MASK is write-only 32-bit or 8-bit with 1-bit per IRQ (***) + * CLEAR is write-only 32-bit or 8-bit with 1-bit per IRQ (***) + * + * (*) May be accessed by more than one driver instance - lock needed + * (**) Read-modify-write access by one driver instance - lock needed + * (***) Accessed by one driver instance only - no locking needed + */ + +struct intc_irqpin_iomem { + void __iomem *iomem; + unsigned long (*read)(void __iomem *iomem); + void (*write)(void __iomem *iomem, unsigned long data); + int width; +}; + +struct intc_irqpin_irq { + int hw_irq; + int requested_irq; + int domain_irq; + struct intc_irqpin_priv *p; +}; + +struct intc_irqpin_priv { + struct intc_irqpin_iomem iomem[INTC_IRQPIN_REG_NR]; + struct intc_irqpin_irq irq[INTC_IRQPIN_MAX]; + struct renesas_intc_irqpin_config config; + unsigned int number_of_irqs; + struct platform_device *pdev; + struct irq_chip irq_chip; + struct irq_domain *irq_domain; + bool shared_irqs; + u8 shared_irq_mask; +}; + +static unsigned long intc_irqpin_read32(void __iomem *iomem) +{ + return ioread32(iomem); +} + +static unsigned long intc_irqpin_read8(void __iomem *iomem) +{ + return ioread8(iomem); +} + +static void intc_irqpin_write32(void __iomem *iomem, unsigned long data) +{ + iowrite32(data, iomem); +} + +static void intc_irqpin_write8(void __iomem *iomem, unsigned long data) +{ + iowrite8(data, iomem); +} + +static inline unsigned long intc_irqpin_read(struct intc_irqpin_priv *p, + int reg) +{ + struct intc_irqpin_iomem *i = &p->iomem[reg]; + + return i->read(i->iomem); +} + +static inline void intc_irqpin_write(struct intc_irqpin_priv *p, + int reg, unsigned long data) +{ + struct intc_irqpin_iomem *i = &p->iomem[reg]; + + i->write(i->iomem, data); +} + +static inline unsigned long intc_irqpin_hwirq_mask(struct intc_irqpin_priv *p, + int reg, int hw_irq) +{ + return BIT((p->iomem[reg].width - 1) - hw_irq); +} + +static inline void intc_irqpin_irq_write_hwirq(struct intc_irqpin_priv *p, + int reg, int hw_irq) +{ + intc_irqpin_write(p, reg, intc_irqpin_hwirq_mask(p, reg, hw_irq)); +} + +static DEFINE_RAW_SPINLOCK(intc_irqpin_lock); /* only used by slow path */ + +static void intc_irqpin_read_modify_write(struct intc_irqpin_priv *p, + int reg, int shift, + int width, int value) +{ + unsigned long flags; + unsigned long tmp; + + raw_spin_lock_irqsave(&intc_irqpin_lock, flags); + + tmp = intc_irqpin_read(p, reg); + tmp &= ~(((1 << width) - 1) << shift); + tmp |= value << shift; + intc_irqpin_write(p, reg, tmp); + + raw_spin_unlock_irqrestore(&intc_irqpin_lock, flags); +} + +static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p, + int irq, int do_mask) +{ + int bitfield_width = 4; /* PRIO assumed to have fixed bitfield width */ + int shift = (7 - irq) * bitfield_width; /* PRIO assumed to be 32-bit */ + + intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_PRIO, + shift, bitfield_width, + do_mask ? 0 : (1 << bitfield_width) - 1); +} + +static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value) +{ + int bitfield_width = p->config.sense_bitfield_width; + int shift = (7 - irq) * bitfield_width; /* SENSE assumed to be 32-bit */ + + dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d\n", irq, value); + + if (value >= (1 << bitfield_width)) + return -EINVAL; + + intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_SENSE, shift, + bitfield_width, value); + return 0; +} + +static void intc_irqpin_dbg(struct intc_irqpin_irq *i, char *str) +{ + dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n", + str, i->requested_irq, i->hw_irq, i->domain_irq); +} + +static void intc_irqpin_irq_enable(struct irq_data *d) +{ + struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); + int hw_irq = irqd_to_hwirq(d); + + intc_irqpin_dbg(&p->irq[hw_irq], "enable"); + intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq); +} + +static void intc_irqpin_irq_disable(struct irq_data *d) +{ + struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); + int hw_irq = irqd_to_hwirq(d); + + intc_irqpin_dbg(&p->irq[hw_irq], "disable"); + intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq); +} + +static void intc_irqpin_shared_irq_enable(struct irq_data *d) +{ + struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); + int hw_irq = irqd_to_hwirq(d); + + intc_irqpin_dbg(&p->irq[hw_irq], "shared enable"); + intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq); + + p->shared_irq_mask &= ~BIT(hw_irq); +} + +static void intc_irqpin_shared_irq_disable(struct irq_data *d) +{ + struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); + int hw_irq = irqd_to_hwirq(d); + + intc_irqpin_dbg(&p->irq[hw_irq], "shared disable"); + intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq); + + p->shared_irq_mask |= BIT(hw_irq); +} + +static void intc_irqpin_irq_enable_force(struct irq_data *d) +{ + struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); + int irq = p->irq[irqd_to_hwirq(d)].requested_irq; + + intc_irqpin_irq_enable(d); + + /* enable interrupt through parent interrupt controller, + * assumes non-shared interrupt with 1:1 mapping + * needed for busted IRQs on some SoCs like sh73a0 + */ + irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq)); +} + +static void intc_irqpin_irq_disable_force(struct irq_data *d) +{ + struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); + int irq = p->irq[irqd_to_hwirq(d)].requested_irq; + + /* disable interrupt through parent interrupt controller, + * assumes non-shared interrupt with 1:1 mapping + * needed for busted IRQs on some SoCs like sh73a0 + */ + irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq)); + intc_irqpin_irq_disable(d); +} + +#define INTC_IRQ_SENSE_VALID 0x10 +#define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID) + +static unsigned char intc_irqpin_sense[IRQ_TYPE_SENSE_MASK + 1] = { + [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x00), + [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x01), + [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x02), + [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x03), + [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x04), +}; + +static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type) +{ + unsigned char value = intc_irqpin_sense[type & IRQ_TYPE_SENSE_MASK]; + struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); + + if (!(value & INTC_IRQ_SENSE_VALID)) + return -EINVAL; + + return intc_irqpin_set_sense(p, irqd_to_hwirq(d), + value ^ INTC_IRQ_SENSE_VALID); +} + +static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id) +{ + struct intc_irqpin_irq *i = dev_id; + struct intc_irqpin_priv *p = i->p; + unsigned long bit; + + intc_irqpin_dbg(i, "demux1"); + bit = intc_irqpin_hwirq_mask(p, INTC_IRQPIN_REG_SOURCE, i->hw_irq); + + if (intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE) & bit) { + intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, ~bit); + intc_irqpin_dbg(i, "demux2"); + generic_handle_irq(i->domain_irq); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static irqreturn_t intc_irqpin_shared_irq_handler(int irq, void *dev_id) +{ + struct intc_irqpin_priv *p = dev_id; + unsigned int reg_source = intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE); + irqreturn_t status = IRQ_NONE; + int k; + + for (k = 0; k < 8; k++) { + if (reg_source & BIT(7 - k)) { + if (BIT(k) & p->shared_irq_mask) + continue; + + status |= intc_irqpin_irq_handler(irq, &p->irq[k]); + } + } + + return status; +} + +static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct intc_irqpin_priv *p = h->host_data; + + p->irq[hw].domain_irq = virq; + p->irq[hw].hw_irq = hw; + + intc_irqpin_dbg(&p->irq[hw], "map"); + irq_set_chip_data(virq, h->host_data); + irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); + set_irq_flags(virq, IRQF_VALID); /* kill me now */ + return 0; +} + +static struct irq_domain_ops intc_irqpin_irq_domain_ops = { + .map = intc_irqpin_irq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int intc_irqpin_probe(struct platform_device *pdev) +{ + struct renesas_intc_irqpin_config *pdata = pdev->dev.platform_data; + struct intc_irqpin_priv *p; + struct intc_irqpin_iomem *i; + struct resource *io[INTC_IRQPIN_REG_NR]; + struct resource *irq; + struct irq_chip *irq_chip; + void (*enable_fn)(struct irq_data *d); + void (*disable_fn)(struct irq_data *d); + const char *name = dev_name(&pdev->dev); + int ref_irq; + int ret; + int k; + + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + if (!p) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + ret = -ENOMEM; + goto err0; + } + + /* deal with driver instance configuration */ + if (pdata) + memcpy(&p->config, pdata, sizeof(*pdata)); + if (!p->config.sense_bitfield_width) + p->config.sense_bitfield_width = 4; /* default to 4 bits */ + + p->pdev = pdev; + platform_set_drvdata(pdev, p); + + /* get hold of manadatory IOMEM */ + for (k = 0; k < INTC_IRQPIN_REG_NR; k++) { + io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k); + if (!io[k]) { + dev_err(&pdev->dev, "not enough IOMEM resources\n"); + ret = -EINVAL; + goto err0; + } + } + + /* allow any number of IRQs between 1 and INTC_IRQPIN_MAX */ + for (k = 0; k < INTC_IRQPIN_MAX; k++) { + irq = platform_get_resource(pdev, IORESOURCE_IRQ, k); + if (!irq) + break; + + p->irq[k].p = p; + p->irq[k].requested_irq = irq->start; + } + + p->number_of_irqs = k; + if (p->number_of_irqs < 1) { + dev_err(&pdev->dev, "not enough IRQ resources\n"); + ret = -EINVAL; + goto err0; + } + + /* ioremap IOMEM and setup read/write callbacks */ + for (k = 0; k < INTC_IRQPIN_REG_NR; k++) { + i = &p->iomem[k]; + + switch (resource_size(io[k])) { + case 1: + i->width = 8; + i->read = intc_irqpin_read8; + i->write = intc_irqpin_write8; + break; + case 4: + i->width = 32; + i->read = intc_irqpin_read32; + i->write = intc_irqpin_write32; + break; + default: + dev_err(&pdev->dev, "IOMEM size mismatch\n"); + ret = -EINVAL; + goto err0; + } + + i->iomem = devm_ioremap_nocache(&pdev->dev, io[k]->start, + resource_size(io[k])); + if (!i->iomem) { + dev_err(&pdev->dev, "failed to remap IOMEM\n"); + ret = -ENXIO; + goto err0; + } + } + + /* mask all interrupts using priority */ + for (k = 0; k < p->number_of_irqs; k++) + intc_irqpin_mask_unmask_prio(p, k, 1); + + /* clear all pending interrupts */ + intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, 0x0); + + /* scan for shared interrupt lines */ + ref_irq = p->irq[0].requested_irq; + p->shared_irqs = true; + for (k = 1; k < p->number_of_irqs; k++) { + if (ref_irq != p->irq[k].requested_irq) { + p->shared_irqs = false; + break; + } + } + + /* use more severe masking method if requested */ + if (p->config.control_parent) { + enable_fn = intc_irqpin_irq_enable_force; + disable_fn = intc_irqpin_irq_disable_force; + } else if (!p->shared_irqs) { + enable_fn = intc_irqpin_irq_enable; + disable_fn = intc_irqpin_irq_disable; + } else { + enable_fn = intc_irqpin_shared_irq_enable; + disable_fn = intc_irqpin_shared_irq_disable; + } + + irq_chip = &p->irq_chip; + irq_chip->name = name; + irq_chip->irq_mask = disable_fn; + irq_chip->irq_unmask = enable_fn; + irq_chip->irq_enable = enable_fn; + irq_chip->irq_disable = disable_fn; + irq_chip->irq_set_type = intc_irqpin_irq_set_type; + irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; + + p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, + p->number_of_irqs, + p->config.irq_base, + &intc_irqpin_irq_domain_ops, p); + if (!p->irq_domain) { + ret = -ENXIO; + dev_err(&pdev->dev, "cannot initialize irq domain\n"); + goto err0; + } + + if (p->shared_irqs) { + /* request one shared interrupt */ + if (devm_request_irq(&pdev->dev, p->irq[0].requested_irq, + intc_irqpin_shared_irq_handler, + IRQF_SHARED, name, p)) { + dev_err(&pdev->dev, "failed to request low IRQ\n"); + ret = -ENOENT; + goto err1; + } + } else { + /* request interrupts one by one */ + for (k = 0; k < p->number_of_irqs; k++) { + if (devm_request_irq(&pdev->dev, + p->irq[k].requested_irq, + intc_irqpin_irq_handler, + 0, name, &p->irq[k])) { + dev_err(&pdev->dev, + "failed to request low IRQ\n"); + ret = -ENOENT; + goto err1; + } + } + } + + /* unmask all interrupts on prio level */ + for (k = 0; k < p->number_of_irqs; k++) + intc_irqpin_mask_unmask_prio(p, k, 0); + + dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); + + /* warn in case of mismatch if irq base is specified */ + if (p->config.irq_base) { + if (p->config.irq_base != p->irq[0].domain_irq) + dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n", + p->config.irq_base, p->irq[0].domain_irq); + } + + return 0; + +err1: + irq_domain_remove(p->irq_domain); +err0: + return ret; +} + +static int intc_irqpin_remove(struct platform_device *pdev) +{ + struct intc_irqpin_priv *p = platform_get_drvdata(pdev); + + irq_domain_remove(p->irq_domain); + + return 0; +} + +static const struct of_device_id intc_irqpin_dt_ids[] = { + { .compatible = "renesas,intc-irqpin", }, + {}, +}; +MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids); + +static struct platform_driver intc_irqpin_device_driver = { + .probe = intc_irqpin_probe, + .remove = intc_irqpin_remove, + .driver = { + .name = "renesas_intc_irqpin", + .of_match_table = intc_irqpin_dt_ids, + .owner = THIS_MODULE, + } +}; + +static int __init intc_irqpin_init(void) +{ + return platform_driver_register(&intc_irqpin_device_driver); +} +postcore_initcall(intc_irqpin_init); + +static void __exit intc_irqpin_exit(void) +{ + platform_driver_unregister(&intc_irqpin_device_driver); +} +module_exit(intc_irqpin_exit); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("Renesas INTC External IRQ Pin Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c new file mode 100644 index 000000000000..927bff373aac --- /dev/null +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -0,0 +1,307 @@ +/* + * Renesas IRQC Driver + * + * Copyright (C) 2013 Magnus Damm + * + * 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 + * + * 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/init.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_data/irq-renesas-irqc.h> + +#define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */ + +#define IRQC_REQ_STS 0x00 +#define IRQC_EN_STS 0x04 +#define IRQC_EN_SET 0x08 +#define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10)) +#define DETECT_STATUS 0x100 +#define IRQC_CONFIG(n) (0x180 + ((n) * 0x04)) + +struct irqc_irq { + int hw_irq; + int requested_irq; + int domain_irq; + struct irqc_priv *p; +}; + +struct irqc_priv { + void __iomem *iomem; + void __iomem *cpu_int_base; + struct irqc_irq irq[IRQC_IRQ_MAX]; + struct renesas_irqc_config config; + unsigned int number_of_irqs; + struct platform_device *pdev; + struct irq_chip irq_chip; + struct irq_domain *irq_domain; +}; + +static void irqc_dbg(struct irqc_irq *i, char *str) +{ + dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n", + str, i->requested_irq, i->hw_irq, i->domain_irq); +} + +static void irqc_irq_enable(struct irq_data *d) +{ + struct irqc_priv *p = irq_data_get_irq_chip_data(d); + int hw_irq = irqd_to_hwirq(d); + + irqc_dbg(&p->irq[hw_irq], "enable"); + iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_SET); +} + +static void irqc_irq_disable(struct irq_data *d) +{ + struct irqc_priv *p = irq_data_get_irq_chip_data(d); + int hw_irq = irqd_to_hwirq(d); + + irqc_dbg(&p->irq[hw_irq], "disable"); + iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_STS); +} + +#define INTC_IRQ_SENSE_VALID 0x10 +#define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID) + +static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { + [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x01), + [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x02), + [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x04), /* Synchronous */ + [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x08), /* Synchronous */ + [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x0c), /* Synchronous */ +}; + +static int irqc_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct irqc_priv *p = irq_data_get_irq_chip_data(d); + int hw_irq = irqd_to_hwirq(d); + unsigned char value = irqc_sense[type & IRQ_TYPE_SENSE_MASK]; + unsigned long tmp; + + irqc_dbg(&p->irq[hw_irq], "sense"); + + if (!(value & INTC_IRQ_SENSE_VALID)) + return -EINVAL; + + tmp = ioread32(p->iomem + IRQC_CONFIG(hw_irq)); + tmp &= ~0x3f; + tmp |= value ^ INTC_IRQ_SENSE_VALID; + iowrite32(tmp, p->iomem + IRQC_CONFIG(hw_irq)); + return 0; +} + +static irqreturn_t irqc_irq_handler(int irq, void *dev_id) +{ + struct irqc_irq *i = dev_id; + struct irqc_priv *p = i->p; + unsigned long bit = BIT(i->hw_irq); + + irqc_dbg(i, "demux1"); + + if (ioread32(p->iomem + DETECT_STATUS) & bit) { + iowrite32(bit, p->iomem + DETECT_STATUS); + irqc_dbg(i, "demux2"); + generic_handle_irq(i->domain_irq); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct irqc_priv *p = h->host_data; + + p->irq[hw].domain_irq = virq; + p->irq[hw].hw_irq = hw; + + irqc_dbg(&p->irq[hw], "map"); + irq_set_chip_data(virq, h->host_data); + irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); + set_irq_flags(virq, IRQF_VALID); /* kill me now */ + return 0; +} + +static struct irq_domain_ops irqc_irq_domain_ops = { + .map = irqc_irq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int irqc_probe(struct platform_device *pdev) +{ + struct renesas_irqc_config *pdata = pdev->dev.platform_data; + struct irqc_priv *p; + struct resource *io; + struct resource *irq; + struct irq_chip *irq_chip; + const char *name = dev_name(&pdev->dev); + int ret; + int k; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + ret = -ENOMEM; + goto err0; + } + + /* deal with driver instance configuration */ + if (pdata) + memcpy(&p->config, pdata, sizeof(*pdata)); + + p->pdev = pdev; + platform_set_drvdata(pdev, p); + + /* get hold of manadatory IOMEM */ + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!io) { + dev_err(&pdev->dev, "not enough IOMEM resources\n"); + ret = -EINVAL; + goto err1; + } + + /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */ + for (k = 0; k < IRQC_IRQ_MAX; k++) { + irq = platform_get_resource(pdev, IORESOURCE_IRQ, k); + if (!irq) + break; + + p->irq[k].p = p; + p->irq[k].requested_irq = irq->start; + } + + p->number_of_irqs = k; + if (p->number_of_irqs < 1) { + dev_err(&pdev->dev, "not enough IRQ resources\n"); + ret = -EINVAL; + goto err1; + } + + /* ioremap IOMEM and setup read/write callbacks */ + p->iomem = ioremap_nocache(io->start, resource_size(io)); + if (!p->iomem) { + dev_err(&pdev->dev, "failed to remap IOMEM\n"); + ret = -ENXIO; + goto err2; + } + + p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */ + + irq_chip = &p->irq_chip; + irq_chip->name = name; + irq_chip->irq_mask = irqc_irq_disable; + irq_chip->irq_unmask = irqc_irq_enable; + irq_chip->irq_enable = irqc_irq_enable; + irq_chip->irq_disable = irqc_irq_disable; + irq_chip->irq_set_type = irqc_irq_set_type; + irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; + + p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, + p->number_of_irqs, + p->config.irq_base, + &irqc_irq_domain_ops, p); + if (!p->irq_domain) { + ret = -ENXIO; + dev_err(&pdev->dev, "cannot initialize irq domain\n"); + goto err2; + } + + /* request interrupts one by one */ + for (k = 0; k < p->number_of_irqs; k++) { + if (request_irq(p->irq[k].requested_irq, irqc_irq_handler, + 0, name, &p->irq[k])) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + ret = -ENOENT; + goto err3; + } + } + + dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); + + /* warn in case of mismatch if irq base is specified */ + if (p->config.irq_base) { + if (p->config.irq_base != p->irq[0].domain_irq) + dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n", + p->config.irq_base, p->irq[0].domain_irq); + } + + return 0; +err3: + for (; k >= 0; k--) + free_irq(p->irq[k - 1].requested_irq, &p->irq[k - 1]); + + irq_domain_remove(p->irq_domain); +err2: + iounmap(p->iomem); +err1: + kfree(p); +err0: + return ret; +} + +static int irqc_remove(struct platform_device *pdev) +{ + struct irqc_priv *p = platform_get_drvdata(pdev); + int k; + + for (k = 0; k < p->number_of_irqs; k++) + free_irq(p->irq[k].requested_irq, &p->irq[k]); + + irq_domain_remove(p->irq_domain); + iounmap(p->iomem); + kfree(p); + return 0; +} + +static const struct of_device_id irqc_dt_ids[] = { + { .compatible = "renesas,irqc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, irqc_dt_ids); + +static struct platform_driver irqc_device_driver = { + .probe = irqc_probe, + .remove = irqc_remove, + .driver = { + .name = "renesas_irqc", + .of_match_table = irqc_dt_ids, + .owner = THIS_MODULE, + } +}; + +static int __init irqc_init(void) +{ + return platform_driver_register(&irqc_device_driver); +} +postcore_initcall(irqc_init); + +static void __exit irqc_exit(void) +{ + platform_driver_unregister(&irqc_device_driver); +} +module_exit(irqc_exit); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("Renesas IRQC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-s3c24xx/irq.c b/drivers/irqchip/irq-s3c24xx.c index cb9f5e011e73..5e40b3424df8 100644 --- a/arch/arm/mach-s3c24xx/irq.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -25,7 +25,11 @@ #include <linux/ioport.h> #include <linux/device.h> #include <linux/irqdomain.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <asm/exception.h> #include <asm/mach/irq.h> #include <mach/regs-irq.h> @@ -34,7 +38,8 @@ #include <plat/cpu.h> #include <plat/regs-irqtype.h> #include <plat/pm.h> -#include <plat/irq.h> + +#include "irqchip.h" #define S3C_IRQTYPE_NONE 0 #define S3C_IRQTYPE_EINT 1 @@ -43,6 +48,7 @@ struct s3c_irq_data { unsigned int type; + unsigned long offset; unsigned long parent_irq; /* data gets filled during init */ @@ -69,23 +75,34 @@ struct s3c_irq_intc { struct s3c_irq_data *irqs; }; +/* + * Array holding pointers to the global controller structs + * [0] ... main_intc + * [1] ... sub_intc + * [2] ... main_intc2 on s3c2416 + */ +static struct s3c_irq_intc *s3c_intc[3]; + static void s3c_irq_mask(struct irq_data *data) { - struct s3c_irq_intc *intc = data->domain->host_data; + struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); + struct s3c_irq_intc *intc = irq_data->intc; struct s3c_irq_intc *parent_intc = intc->parent; - struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq]; struct s3c_irq_data *parent_data; unsigned long mask; unsigned int irqno; mask = __raw_readl(intc->reg_mask); - mask |= (1UL << data->hwirq); + mask |= (1UL << irq_data->offset); __raw_writel(mask, intc->reg_mask); - if (parent_intc && irq_data->parent_irq) { + if (parent_intc) { parent_data = &parent_intc->irqs[irq_data->parent_irq]; - /* check to see if we need to mask the parent IRQ */ + /* check to see if we need to mask the parent IRQ + * The parent_irq is always in main_intc, so the hwirq + * for find_mapping does not need an offset in any case. + */ if ((mask & parent_data->sub_bits) == parent_data->sub_bits) { irqno = irq_find_mapping(parent_intc->domain, irq_data->parent_irq); @@ -96,17 +113,17 @@ static void s3c_irq_mask(struct irq_data *data) static void s3c_irq_unmask(struct irq_data *data) { - struct s3c_irq_intc *intc = data->domain->host_data; + struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); + struct s3c_irq_intc *intc = irq_data->intc; struct s3c_irq_intc *parent_intc = intc->parent; - struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq]; unsigned long mask; unsigned int irqno; mask = __raw_readl(intc->reg_mask); - mask &= ~(1UL << data->hwirq); + mask &= ~(1UL << irq_data->offset); __raw_writel(mask, intc->reg_mask); - if (parent_intc && irq_data->parent_irq) { + if (parent_intc) { irqno = irq_find_mapping(parent_intc->domain, irq_data->parent_irq); s3c_irq_unmask(irq_get_irq_data(irqno)); @@ -115,14 +132,37 @@ static void s3c_irq_unmask(struct irq_data *data) static inline void s3c_irq_ack(struct irq_data *data) { - struct s3c_irq_intc *intc = data->domain->host_data; - unsigned long bitval = 1UL << data->hwirq; + struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); + struct s3c_irq_intc *intc = irq_data->intc; + unsigned long bitval = 1UL << irq_data->offset; __raw_writel(bitval, intc->reg_pending); if (intc->reg_intpnd) __raw_writel(bitval, intc->reg_intpnd); } +static int s3c_irq_type(struct irq_data *data, unsigned int type) +{ + switch (type) { + case IRQ_TYPE_NONE: + break; + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_EDGE_BOTH: + irq_set_handler(data->irq, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_LOW: + case IRQ_TYPE_LEVEL_HIGH: + irq_set_handler(data->irq, handle_level_irq); + break; + default: + pr_err("No such irq type %d", type); + return -EINVAL; + } + + return 0; +} + static int s3c_irqext_type_set(void __iomem *gpcon_reg, void __iomem *extint_reg, unsigned long gpcon_offset, @@ -175,8 +215,7 @@ static int s3c_irqext_type_set(void __iomem *gpcon_reg, return 0; } -/* FIXME: make static when it's out of plat-samsung/irq.h */ -int s3c_irqext_type(struct irq_data *data, unsigned int type) +static int s3c_irqext_type(struct irq_data *data, unsigned int type) { void __iomem *extint_reg; void __iomem *gpcon_reg; @@ -224,19 +263,21 @@ static int s3c_irqext0_type(struct irq_data *data, unsigned int type) extint_offset, type); } -struct irq_chip s3c_irq_chip = { +static struct irq_chip s3c_irq_chip = { .name = "s3c", .irq_ack = s3c_irq_ack, .irq_mask = s3c_irq_mask, .irq_unmask = s3c_irq_unmask, + .irq_set_type = s3c_irq_type, .irq_set_wake = s3c_irq_wake }; -struct irq_chip s3c_irq_level_chip = { +static struct irq_chip s3c_irq_level_chip = { .name = "s3c-level", .irq_mask = s3c_irq_mask, .irq_unmask = s3c_irq_unmask, .irq_ack = s3c_irq_ack, + .irq_set_type = s3c_irq_type, }; static struct irq_chip s3c_irqext_chip = { @@ -260,12 +301,19 @@ static struct irq_chip s3c_irq_eint0t4 = { static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); - struct s3c_irq_intc *intc = desc->irq_data.domain->host_data; - struct s3c_irq_data *irq_data = &intc->irqs[desc->irq_data.hwirq]; + struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc); + struct s3c_irq_intc *intc = irq_data->intc; struct s3c_irq_intc *sub_intc = irq_data->sub_intc; unsigned long src; unsigned long msk; unsigned int n; + unsigned int offset; + + /* we're using individual domains for the non-dt case + * and one big domain for the dt case where the subintc + * starts at hwirq number 32. + */ + offset = (intc->domain->of_node) ? 32 : 0; chained_irq_enter(chip, desc); @@ -278,12 +326,64 @@ static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc) while (src) { n = __ffs(src); src &= ~(1 << n); - generic_handle_irq(irq_find_mapping(sub_intc->domain, n)); + irq = irq_find_mapping(sub_intc->domain, offset + n); + generic_handle_irq(irq); } chained_irq_exit(chip, desc); } +static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc, + struct pt_regs *regs, int intc_offset) +{ + int pnd; + int offset; + int irq; + + pnd = __raw_readl(intc->reg_intpnd); + if (!pnd) + return false; + + /* non-dt machines use individual domains */ + if (!intc->domain->of_node) + intc_offset = 0; + + /* We have a problem that the INTOFFSET register does not always + * show one interrupt. Occasionally we get two interrupts through + * the prioritiser, and this causes the INTOFFSET register to show + * what looks like the logical-or of the two interrupt numbers. + * + * Thanks to Klaus, Shannon, et al for helping to debug this problem + */ + offset = __raw_readl(intc->reg_intpnd + 4); + + /* Find the bit manually, when the offset is wrong. + * The pending register only ever contains the one bit of the next + * interrupt to handle. + */ + if (!(pnd & (1 << offset))) + offset = __ffs(pnd); + + irq = irq_find_mapping(intc->domain, intc_offset + offset); + handle_IRQ(irq, regs); + return true; +} + +asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs) +{ + do { + if (likely(s3c_intc[0])) + if (s3c24xx_handle_intc(s3c_intc[0], regs, 0)) + continue; + + if (s3c_intc[2]) + if (s3c24xx_handle_intc(s3c_intc[2], regs, 64)) + continue; + + break; + } while (1); +} + #ifdef CONFIG_FIQ /** * s3c24xx_set_fiq - set the FIQ routing @@ -326,25 +426,21 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, struct s3c_irq_data *parent_irq_data; unsigned int irqno; - if (!intc) { - pr_err("irq-s3c24xx: no controller found for hwirq %lu\n", hw); - return -EINVAL; - } - - if (!irq_data) { - pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n", hw); - return -EINVAL; - } - /* attach controller pointer to irq_data */ irq_data->intc = intc; + irq_data->offset = hw; + + parent_intc = intc->parent; /* set handler and flags */ switch (irq_data->type) { case S3C_IRQTYPE_NONE: return 0; case S3C_IRQTYPE_EINT: - if (irq_data->parent_irq) + /* On the S3C2412, the EINT0to3 have a parent irq + * but need the s3c_irq_eint0t4 chip + */ + if (parent_intc && (!soc_is_s3c2412() || hw >= 4)) irq_set_chip_and_handler(virq, &s3c_irqext_chip, handle_edge_irq); else @@ -352,8 +448,7 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, handle_edge_irq); break; case S3C_IRQTYPE_EDGE: - if (irq_data->parent_irq || - intc->reg_pending == S3C2416_SRCPND2) + if (parent_intc || intc->reg_pending == S3C2416_SRCPND2) irq_set_chip_and_handler(virq, &s3c_irq_level_chip, handle_edge_irq); else @@ -361,7 +456,7 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, handle_edge_irq); break; case S3C_IRQTYPE_LEVEL: - if (irq_data->parent_irq) + if (parent_intc) irq_set_chip_and_handler(virq, &s3c_irq_level_chip, handle_level_irq); else @@ -372,23 +467,19 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type); return -EINVAL; } + + irq_set_chip_data(virq, irq_data); + set_irq_flags(virq, IRQF_VALID); - if (irq_data->parent_irq) { - parent_intc = intc->parent; - if (!parent_intc) { - pr_err("irq-s3c24xx: no parent controller found for hwirq %lu\n", - hw); + if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) { + if (irq_data->parent_irq > 31) { + pr_err("irq-s3c24xx: parent irq %lu is out of range\n", + irq_data->parent_irq); goto err; } parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; - if (!irq_data) { - pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n", - hw); - goto err; - } - parent_irq_data->sub_intc = intc; parent_irq_data->sub_bits |= (1UL << hw); @@ -443,7 +534,7 @@ static void s3c24xx_clear_intc(struct s3c_irq_intc *intc) } } -struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, +static struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, struct s3c_irq_data *irq_data, struct s3c_irq_intc *parent, unsigned long address) @@ -452,7 +543,6 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, void __iomem *base = (void *)0xf6000000; /* static mapping */ int irq_num; int irq_start; - int irq_offset; int ret; intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); @@ -476,7 +566,6 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, intc->reg_intpnd = base + 0x10; irq_num = 32; irq_start = S3C2410_IRQ(0); - irq_offset = 0; break; case 0x4a000018: pr_debug("irq: found subintc\n"); @@ -484,7 +573,6 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, intc->reg_mask = base + 0x1c; irq_num = 29; irq_start = S3C2410_IRQSUB(0); - irq_offset = 0; break; case 0x4a000040: pr_debug("irq: found intc2\n"); @@ -493,7 +581,6 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, intc->reg_intpnd = base + 0x50; irq_num = 8; irq_start = S3C2416_IRQ(0); - irq_offset = 0; break; case 0x560000a4: pr_debug("irq: found eintc\n"); @@ -501,9 +588,8 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, intc->reg_mask = base + 0xa4; intc->reg_pending = base + 0x08; - irq_num = 20; + irq_num = 24; irq_start = S3C2410_IRQ(32); - irq_offset = 4; break; default: pr_err("irq: unsupported controller address\n"); @@ -514,7 +600,7 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, /* now that all the data is complete, init the irq-domain */ s3c24xx_clear_intc(intc); intc->domain = irq_domain_add_legacy(np, irq_num, irq_start, - irq_offset, &s3c24xx_irq_ops, + 0, &s3c24xx_irq_ops, intc); if (!intc->domain) { pr_err("irq: could not create irq-domain\n"); @@ -522,6 +608,8 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, goto err; } + set_handle_irq(s3c24xx_handle_irq); + return intc; err: @@ -529,12 +617,35 @@ err: return ERR_PTR(ret); } -/* s3c24xx_init_irq - * - * Initialise S3C2410 IRQ system -*/ +static struct s3c_irq_data init_eint[32] = { + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */ +}; -static struct s3c_irq_data init_base[32] = { +#ifdef CONFIG_CPU_S3C2410 +static struct s3c_irq_data init_s3c2410base[32] = { { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ @@ -569,11 +680,80 @@ static struct s3c_irq_data init_base[32] = { { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ }; -static struct s3c_irq_data init_eint[32] = { - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ +static struct s3c_irq_data init_s3c2410subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ +}; + +void __init s3c2410_init_irq(void) +{ +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2410base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2410subint[0], + s3c_intc[0], 0x4a000018); + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); +} +#endif + +#ifdef CONFIG_CPU_S3C2412 +static struct s3c_irq_data init_s3c2412base[32] = { + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT1 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT2 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* SDI/CF */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + +static struct s3c_irq_data init_s3c2412eint[32] = { + { .type = S3C_IRQTYPE_EINT, .parent_irq = 0 }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 1 }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 2 }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 3 }, /* EINT3 */ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */ @@ -596,7 +776,7 @@ static struct s3c_irq_data init_eint[32] = { { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */ }; -static struct s3c_irq_data init_subint[32] = { +static struct s3c_irq_data init_s3c2412subint[32] = { { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ @@ -608,25 +788,32 @@ static struct s3c_irq_data init_subint[32] = { { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ + { .type = S3C_IRQTYPE_NONE, }, + { .type = S3C_IRQTYPE_NONE, }, + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* SDI */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* CF */ }; -void __init s3c24xx_init_irq(void) +void s3c2412_init_irq(void) { - struct s3c_irq_intc *main_intc; + pr_info("S3C2412: IRQ Support\n"); #ifdef CONFIG_FIQ init_FIQ(FIQ_START); #endif - main_intc = s3c24xx_init_intc(NULL, &init_base[0], NULL, 0x4a000000); - if (IS_ERR(main_intc)) { + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { pr_err("irq: could not create main interrupt controller\n"); return; } - s3c24xx_init_intc(NULL, &init_subint[0], main_intc, 0x4a000018); - s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4); + s3c24xx_init_intc(NULL, &init_s3c2412eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2412subint[0], + s3c_intc[0], 0x4a000018); } +#endif #ifdef CONFIG_CPU_S3C2416 static struct s3c_irq_data init_s3c2416base[32] = { @@ -698,37 +885,185 @@ static struct s3c_irq_data init_s3c2416subint[32] = { static struct s3c_irq_data init_s3c2416_second[32] = { { .type = S3C_IRQTYPE_EDGE }, /* 2D */ - { .type = S3C_IRQTYPE_EDGE }, /* IIC1 */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ { .type = S3C_IRQTYPE_NONE }, /* reserved */ { .type = S3C_IRQTYPE_NONE }, /* reserved */ { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */ - { .type = S3C_IRQTYPE_EDGE }, /* PCM1 */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */ - { .type = S3C_IRQTYPE_EDGE }, /* I2S1 */ }; void __init s3c2416_init_irq(void) { - struct s3c_irq_intc *main_intc; - pr_info("S3C2416: IRQ Support\n"); #ifdef CONFIG_FIQ init_FIQ(FIQ_START); #endif - main_intc = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, 0x4a000000); - if (IS_ERR(main_intc)) { + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { pr_err("irq: could not create main interrupt controller\n"); return; } - s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4); - s3c24xx_init_intc(NULL, &init_s3c2416subint[0], main_intc, 0x4a000018); + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2416subint[0], + s3c_intc[0], 0x4a000018); + + s3c_intc[2] = s3c24xx_init_intc(NULL, &init_s3c2416_second[0], + NULL, 0x4a000040); +} + +#endif + +#ifdef CONFIG_CPU_S3C2440 +static struct s3c_irq_data init_s3c2440base[32] = { + { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + +static struct s3c_irq_data init_s3c2440subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ +}; + +void __init s3c2440_init_irq(void) +{ + pr_info("S3C2440: IRQ Support\n"); - s3c24xx_init_intc(NULL, &init_s3c2416_second[0], NULL, 0x4a000040); +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0], + s3c_intc[0], 0x4a000018); } +#endif +#ifdef CONFIG_CPU_S3C2442 +static struct s3c_irq_data init_s3c2442base[32] = { + { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + +static struct s3c_irq_data init_s3c2442subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ +}; + +void __init s3c2442_init_irq(void) +{ + pr_info("S3C2442: IRQ Support\n"); + +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2442subint[0], + s3c_intc[0], 0x4a000018); +} #endif #ifdef CONFIG_CPU_S3C2443 @@ -802,21 +1137,219 @@ static struct s3c_irq_data init_s3c2443subint[32] = { void __init s3c2443_init_irq(void) { - struct s3c_irq_intc *main_intc; - pr_info("S3C2443: IRQ Support\n"); #ifdef CONFIG_FIQ init_FIQ(FIQ_START); #endif - main_intc = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, 0x4a000000); - if (IS_ERR(main_intc)) { + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { pr_err("irq: could not create main interrupt controller\n"); return; } - s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4); - s3c24xx_init_intc(NULL, &init_s3c2443subint[0], main_intc, 0x4a000018); + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2443subint[0], + s3c_intc[0], 0x4a000018); +} +#endif + +#ifdef CONFIG_OF +static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + unsigned int ctrl_num = hw / 32; + unsigned int intc_hw = hw % 32; + struct s3c_irq_intc *intc = s3c_intc[ctrl_num]; + struct s3c_irq_intc *parent_intc = intc->parent; + struct s3c_irq_data *irq_data = &intc->irqs[intc_hw]; + + /* attach controller pointer to irq_data */ + irq_data->intc = intc; + irq_data->offset = intc_hw; + + if (!parent_intc) + irq_set_chip_and_handler(virq, &s3c_irq_chip, handle_edge_irq); + else + irq_set_chip_and_handler(virq, &s3c_irq_level_chip, + handle_edge_irq); + + irq_set_chip_data(virq, irq_data); + + set_irq_flags(virq, IRQF_VALID); + + return 0; +} + +/* Translate our of irq notation + * format: <ctrl_num ctrl_irq parent_irq type> + */ +static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) +{ + struct s3c_irq_intc *intc; + struct s3c_irq_intc *parent_intc; + struct s3c_irq_data *irq_data; + struct s3c_irq_data *parent_irq_data; + int irqno; + + if (WARN_ON(intsize < 4)) + return -EINVAL; + + if (intspec[0] > 2 || !s3c_intc[intspec[0]]) { + pr_err("controller number %d invalid\n", intspec[0]); + return -EINVAL; + } + intc = s3c_intc[intspec[0]]; + + *out_hwirq = intspec[0] * 32 + intspec[2]; + *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; + + parent_intc = intc->parent; + if (parent_intc) { + irq_data = &intc->irqs[intspec[2]]; + irq_data->parent_irq = intspec[1]; + parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; + parent_irq_data->sub_intc = intc; + parent_irq_data->sub_bits |= (1UL << intspec[2]); + + /* parent_intc is always s3c_intc[0], so no offset */ + irqno = irq_create_mapping(parent_intc->domain, intspec[1]); + if (irqno < 0) { + pr_err("irq: could not map parent interrupt\n"); + return irqno; + } + + irq_set_chained_handler(irqno, s3c_irq_demux); + } + + return 0; +} + +static struct irq_domain_ops s3c24xx_irq_ops_of = { + .map = s3c24xx_irq_map_of, + .xlate = s3c24xx_irq_xlate_of, +}; + +struct s3c24xx_irq_of_ctrl { + char *name; + unsigned long offset; + struct s3c_irq_intc **handle; + struct s3c_irq_intc **parent; + struct irq_domain_ops *ops; +}; + +static int __init s3c_init_intc_of(struct device_node *np, + struct device_node *interrupt_parent, + struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl) +{ + struct s3c_irq_intc *intc; + struct s3c24xx_irq_of_ctrl *ctrl; + struct irq_domain *domain; + void __iomem *reg_base; + int i; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("irq-s3c24xx: could not map irq registers\n"); + return -EINVAL; + } + + domain = irq_domain_add_linear(np, num_ctrl * 32, + &s3c24xx_irq_ops_of, NULL); + if (!domain) { + pr_err("irq: could not create irq-domain\n"); + return -EINVAL; + } + + for (i = 0; i < num_ctrl; i++) { + ctrl = &s3c_ctrl[i]; + + pr_debug("irq: found controller %s\n", ctrl->name); + + intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); + if (!intc) + return -ENOMEM; + + intc->domain = domain; + intc->irqs = kzalloc(sizeof(struct s3c_irq_data) * 32, + GFP_KERNEL); + if (!intc->irqs) { + kfree(intc); + return -ENOMEM; + } + + if (ctrl->parent) { + intc->reg_pending = reg_base + ctrl->offset; + intc->reg_mask = reg_base + ctrl->offset + 0x4; + + if (*(ctrl->parent)) { + intc->parent = *(ctrl->parent); + } else { + pr_warn("irq: parent of %s missing\n", + ctrl->name); + kfree(intc->irqs); + kfree(intc); + continue; + } + } else { + intc->reg_pending = reg_base + ctrl->offset; + intc->reg_mask = reg_base + ctrl->offset + 0x08; + intc->reg_intpnd = reg_base + ctrl->offset + 0x10; + } + + s3c24xx_clear_intc(intc); + s3c_intc[i] = intc; + } + + set_handle_irq(s3c24xx_handle_irq); + + return 0; +} + +static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = { + { + .name = "intc", + .offset = 0, + }, { + .name = "subintc", + .offset = 0x18, + .parent = &s3c_intc[0], + } +}; + +int __init s3c2410_init_intc_of(struct device_node *np, + struct device_node *interrupt_parent, + struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl) +{ + return s3c_init_intc_of(np, interrupt_parent, + s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl)); +} +IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of); + +static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = { + { + .name = "intc", + .offset = 0, + }, { + .name = "subintc", + .offset = 0x18, + .parent = &s3c_intc[0], + }, { + .name = "intc2", + .offset = 0x40, + } +}; + +int __init s3c2416_init_intc_of(struct device_node *np, + struct device_node *interrupt_parent, + struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl) +{ + return s3c_init_intc_of(np, interrupt_parent, + s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl)); } +IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of); #endif diff --git a/arch/arm/mach-vt8500/irq.c b/drivers/irqchip/irq-vt8500.c index b9cf5ce9efbb..d97059550a2c 100644 --- a/arch/arm/mach-vt8500/irq.c +++ b/drivers/irqchip/irq-vt8500.c @@ -37,6 +37,9 @@ #include <asm/irq.h> #include <asm/exception.h> +#include <asm/mach/irq.h> + +#include "irqchip.h" #define VT8500_ICPC_IRQ 0x20 #define VT8500_ICPC_FIQ 0x24 @@ -225,6 +228,8 @@ int __init vt8500_irq_init(struct device_node *node, struct device_node *parent) goto out; } + set_handle_irq(vt8500_handle_irq); + vt8500_init_irq_hw(intc[active_cnt].base); pr_info("vt8500-irq: Added interrupt controller\n"); @@ -251,3 +256,4 @@ out: return 0; } +IRQCHIP_DECLARE(vt8500_irq, "via,vt8500-intc", vt8500_irq_init); diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index d4e7567b367c..0b899cb6cda1 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -724,7 +724,7 @@ static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) if (enable) { if (is_code(code, M5MOLS_RESTYPE_MONITOR)) ret = m5mols_start_monitor(info); - if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) + else if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) ret = m5mols_start_capture(info); else ret = -EINVAL; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index ccd18e4ee789..54579e4c740b 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -250,17 +250,19 @@ static u8 SRAM_Table[][60] = vdelay start of active video in 2 * field lines relative to trailing edge of /VRESET pulse (VDELAY register). sheight height of active video in 2 * field lines. + extraheight Added to sheight for cropcap.bounds.height only videostart0 ITU-R frame line number of the line corresponding to vdelay in the first field. */ #define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \ - vdelay, sheight, videostart0) \ + vdelay, sheight, extraheight, videostart0) \ .cropcap.bounds.left = minhdelayx1, \ /* * 2 because vertically we count field lines times two, */ \ /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \ .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \ /* 4 is a safety margin at the end of the line. */ \ .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \ - .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \ + .cropcap.bounds.height = (sheight) + (extraheight) + (vdelay) - \ + MIN_VDELAY, \ .cropcap.defrect.left = hdelayx1, \ .cropcap.defrect.top = (videostart0) * 2, \ .cropcap.defrect.width = swidth, \ @@ -301,9 +303,10 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* totalwidth */ 1135, /* sqwidth */ 944, /* vdelay */ 0x20, - /* bt878 (and bt848?) can capture another - line below active video. */ - /* sheight */ (576 + 2) + 0x20 - 2, + /* sheight */ 576, + /* bt878 (and bt848?) can capture another + line below active video. */ + /* extraheight */ 2, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, @@ -330,6 +333,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 780, /* vdelay */ 0x1a, /* sheight */ 480, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_SECAM, @@ -355,6 +359,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 944, /* vdelay */ 0x20, /* sheight */ 576, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_PAL_Nc, @@ -380,6 +385,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 780, /* vdelay */ 0x1a, /* sheight */ 576, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_PAL_M, @@ -405,6 +411,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 780, /* vdelay */ 0x1a, /* sheight */ 480, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_PAL_N, @@ -430,6 +437,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 944, /* vdelay */ 0x20, /* sheight */ 576, + /* extraheight */ 0, /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_NTSC_M_JP, @@ -455,6 +463,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 780, /* vdelay */ 0x16, /* sheight */ 480, + /* extraheight */ 0, /* videostart0 */ 23) },{ /* that one hopefully works with the strange timing @@ -484,6 +493,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* sqwidth */ 944, /* vdelay */ 0x1a, /* sheight */ 480, + /* extraheight */ 0, /* videostart0 */ 23) } }; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 82d9f6ac12f3..33b5ffc8d66d 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1054,16 +1054,18 @@ static int gsc_m2m_suspend(struct gsc_dev *gsc) static int gsc_m2m_resume(struct gsc_dev *gsc) { + struct gsc_ctx *ctx; unsigned long flags; spin_lock_irqsave(&gsc->slock, flags); /* Clear for full H/W setup in first run after resume */ + ctx = gsc->m2m.ctx; gsc->m2m.ctx = NULL; spin_unlock_irqrestore(&gsc->slock, flags); if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state)) - gsc_m2m_job_finish(gsc->m2m.ctx, - VB2_BUF_STATE_ERROR); + gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); + return 0; } @@ -1204,7 +1206,7 @@ static int gsc_resume(struct device *dev) /* Do not resume if the device was idle before system suspend */ spin_lock_irqsave(&gsc->slock, flags); if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) || - !gsc_m2m_active(gsc)) { + !gsc_m2m_opened(gsc)) { spin_unlock_irqrestore(&gsc->slock, flags); return 0; } diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index e3916bde45cf..0f513dd19f86 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -850,16 +850,18 @@ static int fimc_m2m_suspend(struct fimc_dev *fimc) static int fimc_m2m_resume(struct fimc_dev *fimc) { + struct fimc_ctx *ctx; unsigned long flags; spin_lock_irqsave(&fimc->slock, flags); /* Clear for full H/W setup in first run after resume */ + ctx = fimc->m2m.ctx; fimc->m2m.ctx = NULL; spin_unlock_irqrestore(&fimc->slock, flags); if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state)) - fimc_m2m_job_finish(fimc->m2m.ctx, - VB2_BUF_STATE_ERROR); + fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); + return 0; } diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c index f0af0754a7b4..ac9663ce2a49 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c @@ -128,10 +128,10 @@ static const u32 src_pixfmt_map[8][3] = { void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) { enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code; - unsigned int i = ARRAY_SIZE(src_pixfmt_map); + int i = ARRAY_SIZE(src_pixfmt_map); u32 cfg; - while (i-- >= 0) { + while (--i >= 0) { if (src_pixfmt_map[i][0] == pixelcode) break; } @@ -224,9 +224,9 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY }, }; u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); - unsigned int i = ARRAY_SIZE(pixcode); + int i = ARRAY_SIZE(pixcode); - while (i-- >= 0) + while (--i >= 0) if (pixcode[i][0] == dev->fmt->mbus_code) break; cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK; diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index bfc4206935c8..bbc35de7db27 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -1408,6 +1408,7 @@ static const struct v4l2_ctrl_config fimc_lite_ctrl = { .id = V4L2_CTRL_CLASS_USER | 0x1001, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Test Pattern 640x480", + .step = 1, }; static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index a17fcb2d5d41..cd38d708ab58 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -827,7 +827,7 @@ static int fimc_md_link_notify(struct media_pad *source, struct fimc_pipeline *pipeline; struct v4l2_subdev *sd; struct mutex *lock; - int ret = 0; + int i, ret = 0; int ref_count; if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) @@ -854,29 +854,28 @@ static int fimc_md_link_notify(struct media_pad *source, return 0; } + mutex_lock(lock); + ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count; + if (!(flags & MEDIA_LNK_FL_ENABLED)) { - int i; - mutex_lock(lock); - ret = __fimc_pipeline_close(pipeline); + if (ref_count > 0) { + ret = __fimc_pipeline_close(pipeline); + if (!ret && fimc) + fimc_ctrls_delete(fimc->vid_cap.ctx); + } for (i = 0; i < IDX_MAX; i++) pipeline->subdevs[i] = NULL; - if (fimc) - fimc_ctrls_delete(fimc->vid_cap.ctx); - mutex_unlock(lock); - return ret; + } else if (ref_count > 0) { + /* + * Link activation. Enable power of pipeline elements only if + * the pipeline is already in use, i.e. its video node is open. + * Recreate the controls destroyed during the link deactivation. + */ + ret = __fimc_pipeline_open(pipeline, + source->entity, true); + if (!ret && fimc) + ret = fimc_capture_ctrls_create(fimc); } - /* - * Link activation. Enable power of pipeline elements only if the - * pipeline is already in use, i.e. its video node is opened. - * Recreate the controls destroyed during the link deactivation. - */ - mutex_lock(lock); - - ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count; - if (ref_count > 0) - ret = __fimc_pipeline_open(pipeline, source->entity, true); - if (!ret && fimc) - ret = fimc_capture_ctrls_create(fimc); mutex_unlock(lock); return ret ? -EPIPE : ret; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e84703c314ce..1cb6d57987c6 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -276,7 +276,7 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) unsigned int frame_type; dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); - frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx); /* If frame is same as previous then skip and do not dequeue */ if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 2356fd52a169..4f6b553c4b2d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -232,6 +232,7 @@ static struct mfc_control controls[] = { .minimum = 0, .maximum = 1, .default_value = 0, + .step = 1, .menu_skip_mask = 0, }, { diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 19f3563c61da..5a79c333d45e 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -291,7 +291,7 @@ config IR_TTUSBIR config IR_RX51 tristate "Nokia N900 IR transmitter diode" - depends on OMAP_DM_TIMER && LIRC && !ARCH_MULTIPLATFORM + depends on OMAP_DM_TIMER && ARCH_OMAP2PLUS && LIRC && !ARCH_MULTIPLATFORM ---help--- Say Y or M here if you want to enable support for the IR transmitter diode built in the Nokia N900 (RX51) device. diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index a9d355230e8e..768aaf62d5dc 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -10,7 +10,7 @@ ifeq ($(CONFIG_COMPAT),y) videodev-objs += v4l2-compat-ioctl32.o endif -obj-$(CONFIG_VIDEO_DEV) += videodev.o +obj-$(CONFIG_VIDEO_V4L2) += videodev.o obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 45ea7185c003..642c6223fa6c 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -152,6 +152,20 @@ static void mei_me_intr_disable(struct mei_device *dev) } /** + * mei_me_hw_reset_release - release device from the reset + * + * @dev: the device structure + */ +static void mei_me_hw_reset_release(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + u32 hcsr = mei_hcsr_read(hw); + + hcsr |= H_IG; + hcsr &= ~H_RST; + mei_hcsr_set(hw, hcsr); +} +/** * mei_me_hw_reset - resets fw via mei csr register. * * @dev: the device structure @@ -169,18 +183,14 @@ static void mei_me_hw_reset(struct mei_device *dev, bool intr_enable) if (intr_enable) hcsr |= H_IE; else - hcsr &= ~H_IE; - - mei_hcsr_set(hw, hcsr); - - hcsr = mei_hcsr_read(hw) | H_IG; - hcsr &= ~H_RST; + hcsr |= ~H_IE; mei_hcsr_set(hw, hcsr); - hcsr = mei_hcsr_read(hw); + if (dev->dev_state == MEI_DEV_POWER_DOWN) + mei_me_hw_reset_release(dev); - dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr); + dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", mei_hcsr_read(hw)); } /** @@ -466,7 +476,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) mutex_unlock(&dev->device_lock); return IRQ_HANDLED; } else { - dev_dbg(&dev->pdev->dev, "FW not ready.\n"); + dev_dbg(&dev->pdev->dev, "Reset Completed.\n"); + mei_me_hw_reset_release(dev); mutex_unlock(&dev->device_lock); return IRQ_HANDLED; } diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 6ec530168afb..356179991a2e 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -183,6 +183,24 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) mei_cl_all_write_clear(dev); } +void mei_stop(struct mei_device *dev) +{ + dev_dbg(&dev->pdev->dev, "stopping the device.\n"); + + mutex_lock(&dev->device_lock); + + cancel_delayed_work(&dev->timer_work); + + mei_wd_stop(dev); + + dev->dev_state = MEI_DEV_POWER_DOWN; + mei_reset(dev, 0); + + mutex_unlock(&dev->device_lock); + + flush_scheduled_work(); +} + diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index cb80166161f0..97873812e33b 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -381,6 +381,7 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec) void mei_device_init(struct mei_device *dev); void mei_reset(struct mei_device *dev, int interrupts); int mei_hw_init(struct mei_device *dev); +void mei_stop(struct mei_device *dev); /* * MEI interrupt functions prototype diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index b40ec0601ab0..b8b5c9c3ad03 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -247,44 +247,14 @@ static void mei_remove(struct pci_dev *pdev) hw = to_me_hw(dev); - mutex_lock(&dev->device_lock); - - cancel_delayed_work(&dev->timer_work); - mei_wd_stop(dev); + dev_err(&pdev->dev, "stop\n"); + mei_stop(dev); mei_pdev = NULL; - if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) { - dev->iamthif_cl.state = MEI_FILE_DISCONNECTING; - mei_cl_disconnect(&dev->iamthif_cl); - } - if (dev->wd_cl.state == MEI_FILE_CONNECTED) { - dev->wd_cl.state = MEI_FILE_DISCONNECTING; - mei_cl_disconnect(&dev->wd_cl); - } - - /* Unregistering watchdog device */ mei_watchdog_unregister(dev); - /* remove entry if already in list */ - dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); - - if (dev->open_handle_count > 0) - dev->open_handle_count--; - mei_cl_unlink(&dev->wd_cl); - - if (dev->open_handle_count > 0) - dev->open_handle_count--; - mei_cl_unlink(&dev->iamthif_cl); - - dev->iamthif_current_cb = NULL; - dev->me_clients_num = 0; - - mutex_unlock(&dev->device_lock); - - flush_scheduled_work(); - /* disable interrupts */ mei_disable_interrupts(dev); @@ -308,28 +278,20 @@ static int mei_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct mei_device *dev = pci_get_drvdata(pdev); - int err; if (!dev) return -ENODEV; - mutex_lock(&dev->device_lock); - cancel_delayed_work(&dev->timer_work); + dev_err(&pdev->dev, "suspend\n"); - /* Stop watchdog if exists */ - err = mei_wd_stop(dev); - /* Set new mei state */ - if (dev->dev_state == MEI_DEV_ENABLED || - dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) { - dev->dev_state = MEI_DEV_POWER_DOWN; - mei_reset(dev, 0); - } - mutex_unlock(&dev->device_lock); + mei_stop(dev); + + mei_disable_interrupts(dev); free_irq(pdev->irq, dev); pci_disable_msi(pdev); - return err; + return 0; } static int mei_pci_resume(struct device *device) diff --git a/drivers/misc/vmw_vmci/vmci_datagram.c b/drivers/misc/vmw_vmci/vmci_datagram.c index ed5c433cd493..f3cdd904fe4d 100644 --- a/drivers/misc/vmw_vmci/vmci_datagram.c +++ b/drivers/misc/vmw_vmci/vmci_datagram.c @@ -42,9 +42,11 @@ struct datagram_entry { struct delayed_datagram_info { struct datagram_entry *entry; - struct vmci_datagram msg; struct work_struct work; bool in_dg_host_queue; + /* msg and msg_payload must be together. */ + struct vmci_datagram msg; + u8 msg_payload[]; }; /* Number of in-flight host->host datagrams */ diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 63fb265e0da6..8d6794cdf899 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -25,14 +25,93 @@ #include <mach/dma.h> -#include <mach/regs-sdi.h> - #include <linux/platform_data/mmc-s3cmci.h> #include "s3cmci.h" #define DRIVER_NAME "s3c-mci" +#define S3C2410_SDICON (0x00) +#define S3C2410_SDIPRE (0x04) +#define S3C2410_SDICMDARG (0x08) +#define S3C2410_SDICMDCON (0x0C) +#define S3C2410_SDICMDSTAT (0x10) +#define S3C2410_SDIRSP0 (0x14) +#define S3C2410_SDIRSP1 (0x18) +#define S3C2410_SDIRSP2 (0x1C) +#define S3C2410_SDIRSP3 (0x20) +#define S3C2410_SDITIMER (0x24) +#define S3C2410_SDIBSIZE (0x28) +#define S3C2410_SDIDCON (0x2C) +#define S3C2410_SDIDCNT (0x30) +#define S3C2410_SDIDSTA (0x34) +#define S3C2410_SDIFSTA (0x38) + +#define S3C2410_SDIDATA (0x3C) +#define S3C2410_SDIIMSK (0x40) + +#define S3C2440_SDIDATA (0x40) +#define S3C2440_SDIIMSK (0x3C) + +#define S3C2440_SDICON_SDRESET (1 << 8) +#define S3C2410_SDICON_SDIOIRQ (1 << 3) +#define S3C2410_SDICON_FIFORESET (1 << 1) +#define S3C2410_SDICON_CLOCKTYPE (1 << 0) + +#define S3C2410_SDICMDCON_LONGRSP (1 << 10) +#define S3C2410_SDICMDCON_WAITRSP (1 << 9) +#define S3C2410_SDICMDCON_CMDSTART (1 << 8) +#define S3C2410_SDICMDCON_SENDERHOST (1 << 6) +#define S3C2410_SDICMDCON_INDEX (0x3f) + +#define S3C2410_SDICMDSTAT_CRCFAIL (1 << 12) +#define S3C2410_SDICMDSTAT_CMDSENT (1 << 11) +#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1 << 10) +#define S3C2410_SDICMDSTAT_RSPFIN (1 << 9) + +#define S3C2440_SDIDCON_DS_WORD (2 << 22) +#define S3C2410_SDIDCON_TXAFTERRESP (1 << 20) +#define S3C2410_SDIDCON_RXAFTERCMD (1 << 19) +#define S3C2410_SDIDCON_BLOCKMODE (1 << 17) +#define S3C2410_SDIDCON_WIDEBUS (1 << 16) +#define S3C2410_SDIDCON_DMAEN (1 << 15) +#define S3C2410_SDIDCON_STOP (1 << 14) +#define S3C2440_SDIDCON_DATSTART (1 << 14) + +#define S3C2410_SDIDCON_XFER_RXSTART (2 << 12) +#define S3C2410_SDIDCON_XFER_TXSTART (3 << 12) + +#define S3C2410_SDIDCON_BLKNUM_MASK (0xFFF) + +#define S3C2410_SDIDSTA_SDIOIRQDETECT (1 << 9) +#define S3C2410_SDIDSTA_FIFOFAIL (1 << 8) +#define S3C2410_SDIDSTA_CRCFAIL (1 << 7) +#define S3C2410_SDIDSTA_RXCRCFAIL (1 << 6) +#define S3C2410_SDIDSTA_DATATIMEOUT (1 << 5) +#define S3C2410_SDIDSTA_XFERFINISH (1 << 4) +#define S3C2410_SDIDSTA_TXDATAON (1 << 1) +#define S3C2410_SDIDSTA_RXDATAON (1 << 0) + +#define S3C2440_SDIFSTA_FIFORESET (1 << 16) +#define S3C2440_SDIFSTA_FIFOFAIL (3 << 14) +#define S3C2410_SDIFSTA_TFDET (1 << 13) +#define S3C2410_SDIFSTA_RFDET (1 << 12) +#define S3C2410_SDIFSTA_COUNTMASK (0x7f) + +#define S3C2410_SDIIMSK_RESPONSECRC (1 << 17) +#define S3C2410_SDIIMSK_CMDSENT (1 << 16) +#define S3C2410_SDIIMSK_CMDTIMEOUT (1 << 15) +#define S3C2410_SDIIMSK_RESPONSEND (1 << 14) +#define S3C2410_SDIIMSK_SDIOIRQ (1 << 12) +#define S3C2410_SDIIMSK_FIFOFAIL (1 << 11) +#define S3C2410_SDIIMSK_CRCSTATUS (1 << 10) +#define S3C2410_SDIIMSK_DATACRC (1 << 9) +#define S3C2410_SDIIMSK_DATATIMEOUT (1 << 8) +#define S3C2410_SDIIMSK_DATAFINISH (1 << 7) +#define S3C2410_SDIIMSK_TXFIFOHALF (1 << 4) +#define S3C2410_SDIIMSK_RXFIFOLAST (1 << 2) +#define S3C2410_SDIIMSK_RXFIFOHALF (1 << 0) + enum dbg_channels { dbg_err = (1 << 0), dbg_debug = (1 << 1), diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 1c9e09fbdff8..db103e03ba05 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -183,6 +183,11 @@ int bond_create_slave_symlinks(struct net_device *master, sprintf(linkname, "slave_%s", slave->name); ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj), linkname); + + /* free the master link created earlier in case of error */ + if (ret) + sysfs_remove_link(&(slave->dev.kobj), "master"); + return ret; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index 568205436a15..91ecd6a00d05 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -2139,12 +2139,12 @@ static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) break; default: BNX2X_ERR("Non valid capability ID\n"); - rval = -EINVAL; + rval = 1; break; } } else { DP(BNX2X_MSG_DCB, "DCB disabled\n"); - rval = -EINVAL; + rval = 1; } DP(BNX2X_MSG_DCB, "capid %d:%x\n", capid, *cap); @@ -2170,12 +2170,12 @@ static int bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num) break; default: BNX2X_ERR("Non valid TC-ID\n"); - rval = -EINVAL; + rval = 1; break; } } else { DP(BNX2X_MSG_DCB, "DCB disabled\n"); - rval = -EINVAL; + rval = 1; } return rval; @@ -2188,7 +2188,7 @@ static int bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num) return -EINVAL; } -static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev) +static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev) { struct bnx2x *bp = netdev_priv(netdev); DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcbx_local_feat.pfc.enabled); @@ -2390,12 +2390,12 @@ static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid, break; default: BNX2X_ERR("Non valid featrue-ID\n"); - rval = -EINVAL; + rval = 1; break; } } else { DP(BNX2X_MSG_DCB, "DCB disabled\n"); - rval = -EINVAL; + rval = 1; } return rval; @@ -2431,12 +2431,12 @@ static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid, break; default: BNX2X_ERR("Non valid featrue-ID\n"); - rval = -EINVAL; + rval = 1; break; } } else { DP(BNX2X_MSG_DCB, "dcbnl call not valid\n"); - rval = -EINVAL; + rval = 1; } return rval; diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index e3f39372ce25..911d0253dbb2 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -1332,7 +1332,7 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) static void fec_enet_free_buffers(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - int i; + unsigned int i; struct sk_buff *skb; struct bufdesc *bdp; @@ -1356,7 +1356,7 @@ static void fec_enet_free_buffers(struct net_device *ndev) static int fec_enet_alloc_buffers(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - int i; + unsigned int i; struct sk_buff *skb; struct bufdesc *bdp; @@ -1598,7 +1598,7 @@ static int fec_enet_init(struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); struct bufdesc *cbd_base; struct bufdesc *bdp; - int i; + unsigned int i; /* Allocate memory for buffer descriptors. */ cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 1f17ca0f2201..0d8df400a479 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -128,6 +128,7 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev) spin_unlock_irqrestore(&fep->tmreg_lock, flags); } +EXPORT_SYMBOL(fec_ptp_start_cyclecounter); /** * fec_ptp_adjfreq - adjust ptp cycle frequency @@ -318,6 +319,7 @@ int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; } +EXPORT_SYMBOL(fec_ptp_ioctl); /** * fec_time_keep - call timecounter_read every second to avoid timer overrun @@ -383,3 +385,4 @@ void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev) pr_info("registered PHC device on %s\n", ndev->name); } } +EXPORT_SYMBOL(fec_ptp_init); diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index b64542acfa34..12b1d8480808 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -1818,27 +1818,32 @@ out: **/ void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf) { - u32 dtxswc; + u32 reg_val, reg_offset; switch (hw->mac.type) { case e1000_82576: + reg_offset = E1000_DTXSWC; + break; case e1000_i350: - dtxswc = rd32(E1000_DTXSWC); - if (enable) { - dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK | - E1000_DTXSWC_VLAN_SPOOF_MASK); - /* The PF can spoof - it has to in order to - * support emulation mode NICs */ - dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS)); - } else { - dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK | - E1000_DTXSWC_VLAN_SPOOF_MASK); - } - wr32(E1000_DTXSWC, dtxswc); + reg_offset = E1000_TXSWC; break; default: - break; + return; + } + + reg_val = rd32(reg_offset); + if (enable) { + reg_val |= (E1000_DTXSWC_MAC_SPOOF_MASK | + E1000_DTXSWC_VLAN_SPOOF_MASK); + /* The PF can spoof - it has to in order to + * support emulation mode NICs + */ + reg_val ^= (1 << pf | 1 << (pf + MAX_NUM_VFS)); + } else { + reg_val &= ~(E1000_DTXSWC_MAC_SPOOF_MASK | + E1000_DTXSWC_VLAN_SPOOF_MASK); } + wr32(reg_offset, reg_val); } /** diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index 4623502054d5..0478a1abe541 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -39,7 +39,7 @@ #include <linux/pci.h> #ifdef CONFIG_IGB_HWMON -struct i2c_board_info i350_sensor_info = { +static struct i2c_board_info i350_sensor_info = { I2C_BOARD_INFO("i350bb", (0Xf8 >> 1)), }; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 4dbd62968c7a..8496adfc6a68 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2542,8 +2542,8 @@ static void igb_probe_vfs(struct igb_adapter *adapter) if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) return; - igb_enable_sriov(pdev, max_vfs); pci_sriov_set_totalvfs(pdev, 7); + igb_enable_sriov(pdev, max_vfs); #endif /* CONFIG_PCI_IOV */ } @@ -2652,7 +2652,7 @@ static int igb_sw_init(struct igb_adapter *adapter) if (max_vfs > 7) { dev_warn(&pdev->dev, "Maximum of 7 VFs per PF, using max\n"); - adapter->vfs_allocated_count = 7; + max_vfs = adapter->vfs_allocated_count = 7; } else adapter->vfs_allocated_count = max_vfs; if (adapter->vfs_allocated_count) diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 0987822359f0..0a237507ee85 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -740,7 +740,7 @@ void igb_ptp_init(struct igb_adapter *adapter) case e1000_82576: snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); adapter->ptp_caps.owner = THIS_MODULE; - adapter->ptp_caps.max_adj = 1000000000; + adapter->ptp_caps.max_adj = 999999881; adapter->ptp_caps.n_ext_ts = 0; adapter->ptp_caps.pps = 0; adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index c3db6cd69b68..2b6cb5ca48ee 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -944,9 +944,17 @@ free_queue_irqs: free_irq(adapter->msix_entries[vector].vector, adapter->q_vector[vector]); } - pci_disable_msix(adapter->pdev); - kfree(adapter->msix_entries); - adapter->msix_entries = NULL; + /* This failure is non-recoverable - it indicates the system is + * out of MSIX vector resources and the VF driver cannot run + * without them. Set the number of msix vectors to zero + * indicating that not enough can be allocated. The error + * will be returned to the user indicating device open failed. + * Any further attempts to force the driver to open will also + * fail. The only way to recover is to unload the driver and + * reload it again. If the system has recovered some MSIX + * vectors then it may succeed. + */ + adapter->num_msix_vectors = 0; return err; } @@ -2572,6 +2580,15 @@ static int ixgbevf_open(struct net_device *netdev) struct ixgbe_hw *hw = &adapter->hw; int err; + /* A previous failure to open the device because of a lack of + * available MSIX vector resources may have reset the number + * of msix vectors variable to zero. The only way to recover + * is to unload/reload the driver and hope that the system has + * been able to recover some MSIX vector resources. + */ + if (!adapter->num_msix_vectors) + return -ENOMEM; + /* disallow open during test */ if (test_bit(__IXGBEVF_TESTING, &adapter->state)) return -EBUSY; @@ -2628,7 +2645,6 @@ static int ixgbevf_open(struct net_device *netdev) err_req_irq: ixgbevf_down(adapter); - ixgbevf_free_irq(adapter); err_setup_rx: ixgbevf_free_all_rx_resources(adapter); err_setup_tx: diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 6a2127489af7..bfdb06860397 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -769,7 +769,7 @@ ltq_etop_probe(struct platform_device *pdev) return 0; err_free: - kfree(dev); + free_netdev(dev); err_out: return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 995d4b6d5c1e..f278b10ef714 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1637,6 +1637,17 @@ void mlx4_en_stop_port(struct net_device *dev, int detach) /* Flush multicast filter */ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); + /* Remove flow steering rules for the port*/ + if (mdev->dev->caps.steering_mode == + MLX4_STEERING_MODE_DEVICE_MANAGED) { + ASSERT_RTNL(); + list_for_each_entry_safe(flow, tmp_flow, + &priv->ethtool_list, list) { + mlx4_flow_detach(mdev->dev, flow->id); + list_del(&flow->list); + } + } + mlx4_en_destroy_drop_qp(priv); /* Free TX Rings */ @@ -1657,17 +1668,6 @@ void mlx4_en_stop_port(struct net_device *dev, int detach) if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN)) mdev->mac_removed[priv->port] = 1; - /* Remove flow steering rules for the port*/ - if (mdev->dev->caps.steering_mode == - MLX4_STEERING_MODE_DEVICE_MANAGED) { - ASSERT_RTNL(); - list_for_each_entry_safe(flow, tmp_flow, - &priv->ethtool_list, list) { - mlx4_flow_detach(mdev->dev, flow->id); - list_del(&flow->list); - } - } - /* Free RX Rings */ for (i = 0; i < priv->rx_ring_num; i++) { mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 251ae2f93116..8e3123a1df88 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -771,7 +771,7 @@ int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_slave_event_eq_info *event_eq = priv->mfunc.master.slave_state[slave].event_eq; u32 in_modifier = vhcr->in_modifier; - u32 eqn = in_modifier & 0x1FF; + u32 eqn = in_modifier & 0x3FF; u64 in_param = vhcr->in_param; int err = 0; int i; diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 2995687f1aee..1391b52f443a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -99,6 +99,7 @@ struct res_qp { struct list_head mcg_list; spinlock_t mcg_spl; int local_qpn; + atomic_t ref_count; }; enum res_mtt_states { @@ -197,6 +198,7 @@ enum res_fs_rule_states { struct res_fs_rule { struct res_common com; + int qpn; }; static void *res_tracker_lookup(struct rb_root *root, u64 res_id) @@ -355,7 +357,7 @@ static int mpt_mask(struct mlx4_dev *dev) return dev->caps.num_mpts - 1; } -static void *find_res(struct mlx4_dev *dev, int res_id, +static void *find_res(struct mlx4_dev *dev, u64 res_id, enum mlx4_resource type) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -447,6 +449,7 @@ static struct res_common *alloc_qp_tr(int id) ret->local_qpn = id; INIT_LIST_HEAD(&ret->mcg_list); spin_lock_init(&ret->mcg_spl); + atomic_set(&ret->ref_count, 0); return &ret->com; } @@ -554,7 +557,7 @@ static struct res_common *alloc_xrcdn_tr(int id) return &ret->com; } -static struct res_common *alloc_fs_rule_tr(u64 id) +static struct res_common *alloc_fs_rule_tr(u64 id, int qpn) { struct res_fs_rule *ret; @@ -564,7 +567,7 @@ static struct res_common *alloc_fs_rule_tr(u64 id) ret->com.res_id = id; ret->com.state = RES_FS_RULE_ALLOCATED; - + ret->qpn = qpn; return &ret->com; } @@ -602,7 +605,7 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave, ret = alloc_xrcdn_tr(id); break; case RES_FS_RULE: - ret = alloc_fs_rule_tr(id); + ret = alloc_fs_rule_tr(id, extra); break; default: return NULL; @@ -671,10 +674,14 @@ undo: static int remove_qp_ok(struct res_qp *res) { - if (res->com.state == RES_QP_BUSY) + if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) || + !list_empty(&res->mcg_list)) { + pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n", + res->com.state, atomic_read(&res->ref_count)); return -EBUSY; - else if (res->com.state != RES_QP_RESERVED) + } else if (res->com.state != RES_QP_RESERVED) { return -EPERM; + } return 0; } @@ -3124,6 +3131,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC]; int err; int qpn; + struct res_qp *rqp; struct mlx4_net_trans_rule_hw_ctrl *ctrl; struct _rule_hw *rule_header; int header_id; @@ -3134,7 +3142,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; - err = get_res(dev, slave, qpn, RES_QP, NULL); + err = get_res(dev, slave, qpn, RES_QP, &rqp); if (err) { pr_err("Steering rule with qpn 0x%x rejected.\n", qpn); return err; @@ -3175,14 +3183,16 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, if (err) goto err_put; - err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, 0); + err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn); if (err) { mlx4_err(dev, "Fail to add flow steering resources.\n "); /* detach rule*/ mlx4_cmd(dev, vhcr->out_param, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); + goto err_put; } + atomic_inc(&rqp->ref_count); err_put: put_res(dev, slave, qpn, RES_QP); return err; @@ -3195,20 +3205,35 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_info *cmd) { int err; + struct res_qp *rqp; + struct res_fs_rule *rrule; if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) return -EOPNOTSUPP; + err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule); + if (err) + return err; + /* Release the rule form busy state before removal */ + put_res(dev, slave, vhcr->in_param, RES_FS_RULE); + err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp); + if (err) + return err; + err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0); if (err) { mlx4_err(dev, "Fail to remove flow steering resources.\n "); - return err; + goto out; } err = mlx4_cmd(dev, vhcr->in_param, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); + if (!err) + atomic_dec(&rqp->ref_count); +out: + put_res(dev, slave, rrule->qpn, RES_QP); return err; } @@ -3806,6 +3831,7 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); /*VLAN*/ rem_slave_macs(dev, slave); + rem_slave_fs_rule(dev, slave); rem_slave_qps(dev, slave); rem_slave_srqs(dev, slave); rem_slave_cqs(dev, slave); @@ -3814,6 +3840,5 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) rem_slave_mtts(dev, slave); rem_slave_counters(dev, slave); rem_slave_xrcdns(dev, slave); - rem_slave_fs_rule(dev, slave); mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); } diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index c4122c86f829..efa29b712d5f 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1472,7 +1472,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, ndev); - if (lpc_mii_init(pldat) != 0) + ret = lpc_mii_init(pldat); + if (ret) goto err_out_unregister_netdev; netdev_info(ndev, "LPC mac at 0x%08x irq %d\n", diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 39ab4d09faaa..73ce7dd6b954 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -1726,9 +1726,9 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) - skb->ip_summed = CHECKSUM_NONE; - else skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; napi_gro_receive(&adapter->napi, skb); (*work_done)++; diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 33e96176e4d8..bf5e3cf97c4d 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2220,6 +2220,7 @@ static void sh_eth_tsu_init(struct sh_eth_private *mdp) /* MDIO bus release function */ static int sh_mdio_release(struct net_device *ndev) { + struct sh_eth_private *mdp = netdev_priv(ndev); struct mii_bus *bus = dev_get_drvdata(&ndev->dev); /* unregister mdio bus */ @@ -2234,6 +2235,9 @@ static int sh_mdio_release(struct net_device *ndev) /* free bitbang info */ free_mdio_bitbang(bus); + /* free bitbang memory */ + kfree(mdp->bitbang); + return 0; } @@ -2262,6 +2266,7 @@ static int sh_mdio_init(struct net_device *ndev, int id, bitbang->ctrl.ops = &bb_ops; /* MII controller setting */ + mdp->bitbang = bitbang; mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl); if (!mdp->mii_bus) { ret = -ENOMEM; @@ -2441,6 +2446,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev) } mdp->tsu_addr = ioremap(rtsu->start, resource_size(rtsu)); + if (mdp->tsu_addr == NULL) { + ret = -ENOMEM; + dev_err(&pdev->dev, "TSU ioremap failed.\n"); + goto out_release; + } mdp->port = devno % 2; ndev->features = NETIF_F_HW_VLAN_FILTER; } diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index bae84fd2e73a..e6655678458e 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -705,6 +705,7 @@ struct sh_eth_private { const u16 *reg_offset; void __iomem *addr; void __iomem *tsu_addr; + struct bb_info *bitbang; u32 num_rx_ring; u32 num_tx_ring; dma_addr_t rx_desc_dma; diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 75c48558e6fd..df32a090d08e 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1364,7 +1364,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, struct platform_device *mdio; parp = of_get_property(slave_node, "phy_id", &lenp); - if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) { + if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) { pr_err("Missing slave[%d] phy_id property\n", i); ret = -EINVAL; goto error_ret; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4cc13940c895..f76c3ca07a45 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1023,6 +1023,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, AR_PHY_AGC_CONTROL_FLTR_CAL | AR_PHY_AGC_CONTROL_PKDET_CAL; + /* Use chip chainmask only for calibration */ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); if (rtt) { @@ -1150,6 +1151,9 @@ skip_tx_iqcal: ar9003_hw_rtt_disable(ah); } + /* Revert chainmask to runtime parameters */ + ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + /* Initialize list pointers */ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index ade3afb21f91..39c84ecf6a42 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -28,21 +28,21 @@ void ath_tx_complete_poll_work(struct work_struct *work) int i; bool needreset = false; - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) { - txq = &sc->tx.txq[i]; - ath_txq_lock(sc, txq); - if (txq->axq_depth) { - if (txq->axq_tx_inprogress) { - needreset = true; - ath_txq_unlock(sc, txq); - break; - } else { - txq->axq_tx_inprogress = true; - } + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + txq = sc->tx.txq_map[i]; + + ath_txq_lock(sc, txq); + if (txq->axq_depth) { + if (txq->axq_tx_inprogress) { + needreset = true; + ath_txq_unlock(sc, txq); + break; + } else { + txq->axq_tx_inprogress = true; } - ath_txq_unlock_complete(sc, txq); } + ath_txq_unlock_complete(sc, txq); + } if (needreset) { ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 3630a41df50d..c353b5f19c8c 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -475,6 +475,7 @@ il3945_tx_skb(struct il_priv *il, dma_addr_t txcmd_phys; int txq_id = skb_get_queue_mapping(skb); u16 len, idx, hdr_len; + u16 firstlen, secondlen; u8 id; u8 unicast; u8 sta_id; @@ -589,21 +590,22 @@ il3945_tx_skb(struct il_priv *il, len = sizeof(struct il3945_tx_cmd) + sizeof(struct il_cmd_header) + hdr_len; - len = (len + 3) & ~3; + firstlen = (len + 3) & ~3; /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ txcmd_phys = - pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); + pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, + PCI_DMA_TODEVICE); if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) goto drop_unlock; /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ - len = skb->len - hdr_len; - if (len) { + secondlen = skb->len - hdr_len; + if (secondlen > 0) { phys_addr = - pci_map_single(il->pci_dev, skb->data + hdr_len, len, + pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, PCI_DMA_TODEVICE); if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) goto drop_unlock; @@ -611,12 +613,12 @@ il3945_tx_skb(struct il_priv *il, /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ - il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); + il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0); dma_unmap_addr_set(out_meta, mapping, txcmd_phys); - dma_unmap_len_set(out_meta, len, len); - if (len) - il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, - U32_PAD(len)); + dma_unmap_len_set(out_meta, len, firstlen); + if (secondlen > 0) + il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, 0, + U32_PAD(secondlen)); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 20a6c5555873..b5c8b962ce12 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -157,6 +157,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, return -1; } + cmd_code = le16_to_cpu(host_cmd->command); + cmd_size = le16_to_cpu(host_cmd->size); + + if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET && + cmd_code != HostCmd_CMD_FUNC_SHUTDOWN && + cmd_code != HostCmd_CMD_FUNC_INIT) { + dev_err(adapter->dev, + "DNLD_CMD: FW in reset state, ignore cmd %#x\n", + cmd_code); + mwifiex_complete_cmd(adapter, cmd_node); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } + /* Set command sequence number */ adapter->seq_num++; host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO @@ -168,9 +182,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, adapter->curr_cmd = cmd_node; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - cmd_code = le16_to_cpu(host_cmd->command); - cmd_size = le16_to_cpu(host_cmd->size); - /* Adjust skb length */ if (cmd_node->cmd_skb->len > cmd_size) /* @@ -484,8 +495,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, data_buf); - if (!ret) - ret = mwifiex_wait_queue_complete(adapter); return ret; } @@ -588,9 +597,10 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, if (cmd_no == HostCmd_CMD_802_11_SCAN) { mwifiex_queue_scan_cmd(priv, cmd_node); } else { - adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); queue_work(adapter->workqueue, &adapter->main_work); + if (cmd_node->wait_q_enabled) + ret = mwifiex_wait_queue_complete(adapter, cmd_node); } return ret; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e38aa9b3663d..0ff4c37ab42a 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -709,6 +709,14 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) return ret; } + /* cancel current command */ + if (adapter->curr_cmd) { + dev_warn(adapter->dev, "curr_cmd is still in processing\n"); + del_timer(&adapter->cmd_timer); + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + adapter->curr_cmd = NULL; + } + /* shut down mwifiex */ dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 553adfb0aa81..7035ade9af74 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -723,7 +723,6 @@ struct mwifiex_adapter { u16 cmd_wait_q_required; struct mwifiex_wait_queue cmd_wait_q; u8 scan_wait_q_woken; - struct cmd_ctrl_node *cmd_queued; spinlock_t queue_lock; /* lock for tx queues */ struct completion fw_load; u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; @@ -1018,7 +1017,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, struct mwifiex_multicast_list *mcast_list); int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, struct net_device *dev); -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_queued); int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, struct cfg80211_ssid *req_ssid); int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index bb60c2754a97..d215b4d3c51b 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1388,10 +1388,13 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); - adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); queue_work(adapter->workqueue, &adapter->main_work); + + /* Perform internal scan synchronously */ + if (!priv->scan_request) + mwifiex_wait_queue_complete(adapter, cmd_node); } else { spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); @@ -1946,9 +1949,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv, /* Normal scan */ ret = mwifiex_scan_networks(priv, NULL); - if (!ret) - ret = mwifiex_wait_queue_complete(priv->adapter); - up(&priv->async_sem); return ret; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 9f33c92c90f5..13100f8de3db 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -54,16 +54,10 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, * This function waits on a cmd wait queue. It also cancels the pending * request after waking up, in case of errors. */ -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_queued) { int status; - struct cmd_ctrl_node *cmd_queued; - - if (!adapter->cmd_queued) - return 0; - - cmd_queued = adapter->cmd_queued; - adapter->cmd_queued = NULL; dev_dbg(adapter->dev, "cmd pending\n"); atomic_inc(&adapter->cmd_pending); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 156b52732f3d..5847d6d0881e 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -851,6 +851,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, if (unlikely(!_urb)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't allocate urb. Drop skb!\n"); + kfree_skb(skb); return; } _rtl_submit_tx_urb(hw, _urb); diff --git a/drivers/of/base.c b/drivers/of/base.c index 321d3ef05006..c6443de58fb0 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -746,6 +746,64 @@ struct device_node *of_find_node_by_phandle(phandle handle) EXPORT_SYMBOL(of_find_node_by_phandle); /** + * of_find_property_value_of_size + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @len: requested length of property value + * + * Search for a property in a device node and valid the requested size. + * Returns the property value on success, -EINVAL if the property does not + * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + */ +static void *of_find_property_value_of_size(const struct device_node *np, + const char *propname, u32 len) +{ + struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return ERR_PTR(-EINVAL); + if (!prop->value) + return ERR_PTR(-ENODATA); + if (len > prop->length) + return ERR_PTR(-EOVERFLOW); + + return prop->value; +} + +/** + * of_property_read_u32_index - Find and read a u32 from a multi-value property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the u32 in the list of values + * @out_value: pointer to return value, modified only if no error. + * + * Search for a property in a device node and read nth 32-bit value from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_value is modified only if a valid u32 value can be decoded. + */ +int of_property_read_u32_index(const struct device_node *np, + const char *propname, + u32 index, u32 *out_value) +{ + const u32 *val = of_find_property_value_of_size(np, propname, + ((index + 1) * sizeof(*out_value))); + + if (IS_ERR(val)) + return PTR_ERR(val); + + *out_value = be32_to_cpup(((__be32 *)val) + index); + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u32_index); + +/** * of_property_read_u8_array - Find and read an array of u8 from a property. * * @np: device node from which the property value is to be read. @@ -766,17 +824,12 @@ EXPORT_SYMBOL(of_find_node_by_phandle); int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz) { - struct property *prop = of_find_property(np, propname, NULL); - const u8 *val; + const u8 *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - if ((sz * sizeof(*out_values)) > prop->length) - return -EOVERFLOW; + if (IS_ERR(val)) + return PTR_ERR(val); - val = prop->value; while (sz--) *out_values++ = *val++; return 0; @@ -804,17 +857,12 @@ EXPORT_SYMBOL_GPL(of_property_read_u8_array); int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz) { - struct property *prop = of_find_property(np, propname, NULL); - const __be16 *val; + const __be16 *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - if ((sz * sizeof(*out_values)) > prop->length) - return -EOVERFLOW; + if (IS_ERR(val)) + return PTR_ERR(val); - val = prop->value; while (sz--) *out_values++ = be16_to_cpup(val++); return 0; @@ -841,17 +889,12 @@ int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz) { - struct property *prop = of_find_property(np, propname, NULL); - const __be32 *val; + const __be32 *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - if ((sz * sizeof(*out_values)) > prop->length) - return -EOVERFLOW; + if (IS_ERR(val)) + return PTR_ERR(val); - val = prop->value; while (sz--) *out_values++ = be32_to_cpup(val++); return 0; @@ -874,15 +917,13 @@ EXPORT_SYMBOL_GPL(of_property_read_u32_array); int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value) { - struct property *prop = of_find_property(np, propname, NULL); + const __be32 *val = of_find_property_value_of_size(np, propname, + sizeof(*out_value)); - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - if (sizeof(*out_value) > prop->length) - return -EOVERFLOW; - *out_value = of_read_number(prop->value, 2); + if (IS_ERR(val)) + return PTR_ERR(val); + + *out_value = of_read_number(val, 2); return 0; } EXPORT_SYMBOL_GPL(of_property_read_u64); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 34f51d2d90d2..35e94009829b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -229,6 +229,7 @@ config PINCTRL_EXYNOS5440 source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/sh-pfc/Kconfig" source "drivers/pinctrl/spear/Kconfig" +source "drivers/pinctrl/vt8500/Kconfig" config PINCTRL_XWAY bool diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f82cc5baf767..a5a52c83c13a 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -52,3 +52,4 @@ obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/ obj-$(CONFIG_SUPERH) += sh-pfc/ obj-$(CONFIG_PLAT_SPEAR) += spear/ +obj-$(CONFIG_ARCH_VT8500) += vt8500/ diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index c689c04a4f52..2d2f0a43d36b 100644 --- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -620,7 +620,7 @@ int mvebu_pinctrl_probe(struct platform_device *pdev) /* special soc specific control */ if (ctrl->mpp_get || ctrl->mpp_set) { - if (!ctrl->name || !ctrl->mpp_set || !ctrl->mpp_set) { + if (!ctrl->name || !ctrl->mpp_get || !ctrl->mpp_set) { dev_err(&pdev->dev, "wrong soc control info\n"); return -EINVAL; } diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index ac8d382a79bb..d611ecfcbf70 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -622,7 +622,7 @@ static const struct file_operations pinconf_dbg_pinname_fops = { static int pinconf_dbg_state_print(struct seq_file *s, void *d) { if (strlen(dbg_state_name)) - seq_printf(s, "%s\n", dbg_pinname); + seq_printf(s, "%s\n", dbg_state_name); else seq_printf(s, "No pin state set\n"); return 0; diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index e3ed8cb072a5..bfda73d64eed 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -90,7 +90,7 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot, * pin config. */ -#ifdef CONFIG_GENERIC_PINCONF +#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_DEBUG_FS) void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin); diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c index caecdd373061..c542a97c82f3 100644 --- a/drivers/pinctrl/pinctrl-abx500.c +++ b/drivers/pinctrl/pinctrl-abx500.c @@ -422,7 +422,7 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip, } /* check if pin use AlternateFunction register */ - if ((af.alt_bit1 == UNUSED) && (af.alt_bit1 == UNUSED)) + if ((af.alt_bit1 == UNUSED) && (af.alt_bit2 == UNUSED)) return mode; /* * if pin GPIOSEL bit is set and pin supports alternate function, diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c index 4eb6d2c4e4df..2a2e427d765e 100644 --- a/drivers/pinctrl/pinctrl-bcm2835.c +++ b/drivers/pinctrl/pinctrl-bcm2835.c @@ -699,11 +699,6 @@ static int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc, return 0; } -static inline u32 prop_u32(struct property *p, int i) -{ - return be32_to_cpup(((__be32 *)p->value) + i); -} - static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned *num_maps) @@ -761,7 +756,9 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, return -ENOMEM; for (i = 0; i < num_pins; i++) { - pin = prop_u32(pins, i); + err = of_property_read_u32_index(np, "brcm,pins", i, &pin); + if (err) + goto out; if (pin >= ARRAY_SIZE(bcm2835_gpio_pins)) { dev_err(pc->dev, "%s: invalid brcm,pins value %d\n", of_node_full_name(np), pin); @@ -770,14 +767,20 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, } if (num_funcs) { - func = prop_u32(funcs, (num_funcs > 1) ? i : 0); + err = of_property_read_u32_index(np, "brcm,function", + (num_funcs > 1) ? i : 0, &func); + if (err) + goto out; err = bcm2835_pctl_dt_node_to_map_func(pc, np, pin, func, &cur_map); if (err) goto out; } if (num_pulls) { - pull = prop_u32(pulls, (num_pulls > 1) ? i : 0); + err = of_property_read_u32_index(np, "brcm,pull", + (num_funcs > 1) ? i : 0, &pull); + if (err) + goto out; err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin, pull, &cur_map); if (err) diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 538b9ddaadf7..8738933a57d7 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -677,3 +677,111 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .label = "exynos4x12-gpio-ctrl3", }, }; + +/* pin banks of exynos5250 pin-controller 0 */ +static struct samsung_pin_bank exynos5250_pin_banks0[] = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08), + EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c), + EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpb1", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpb2", 0x14), + EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpb3", 0x18), + EXYNOS_PIN_BANK_EINTG(7, 0x0E0, "gpc0", 0x1c), + EXYNOS_PIN_BANK_EINTG(4, 0x100, "gpc1", 0x20), + EXYNOS_PIN_BANK_EINTG(7, 0x120, "gpc2", 0x24), + EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpc3", 0x28), + EXYNOS_PIN_BANK_EINTG(4, 0x160, "gpd0", 0x2c), + EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpd1", 0x30), + EXYNOS_PIN_BANK_EINTG(7, 0x2E0, "gpc4", 0x34), + EXYNOS_PIN_BANK_EINTN(6, 0x1A0, "gpy0"), + EXYNOS_PIN_BANK_EINTN(4, 0x1C0, "gpy1"), + EXYNOS_PIN_BANK_EINTN(6, 0x1E0, "gpy2"), + EXYNOS_PIN_BANK_EINTN(8, 0x200, "gpy3"), + EXYNOS_PIN_BANK_EINTN(8, 0x220, "gpy4"), + EXYNOS_PIN_BANK_EINTN(8, 0x240, "gpy5"), + EXYNOS_PIN_BANK_EINTN(8, 0x260, "gpy6"), + EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c), +}; + +/* pin banks of exynos5250 pin-controller 1 */ +static struct samsung_pin_bank exynos5250_pin_banks1[] = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00), + EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04), + EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpf0", 0x08), + EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpf1", 0x0c), + EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpg0", 0x10), + EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpg1", 0x14), + EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpg2", 0x18), + EXYNOS_PIN_BANK_EINTG(4, 0x0E0, "gph0", 0x1c), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gph1", 0x20), +}; + +/* pin banks of exynos5250 pin-controller 2 */ +static struct samsung_pin_bank exynos5250_pin_banks2[] = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00), + EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04), + EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08), + EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpv3", 0x0c), + EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpv4", 0x10), +}; + +/* pin banks of exynos5250 pin-controller 3 */ +static struct samsung_pin_bank exynos5250_pin_banks3[] = { + EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), +}; + +/* + * Samsung pinctrl driver data for Exynos5250 SoC. Exynos5250 SoC includes + * four gpio/pin-mux/pinconfig controllers. + */ +struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { + { + /* pin-controller instance 0 data */ + .pin_banks = exynos5250_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos5250_pin_banks0), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .weint_con = EXYNOS_WKUP_ECON_OFFSET, + .weint_mask = EXYNOS_WKUP_EMASK_OFFSET, + .weint_pend = EXYNOS_WKUP_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .label = "exynos5250-gpio-ctrl0", + }, { + /* pin-controller instance 1 data */ + .pin_banks = exynos5250_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos5250_pin_banks1), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .label = "exynos5250-gpio-ctrl1", + }, { + /* pin-controller instance 2 data */ + .pin_banks = exynos5250_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos5250_pin_banks2), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .label = "exynos5250-gpio-ctrl2", + }, { + /* pin-controller instance 3 data */ + .pin_banks = exynos5250_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos5250_pin_banks3), + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .label = "exynos5250-gpio-ctrl3", + }, +}; diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index f206df175656..3d5cf639aa46 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -948,6 +948,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { .data = (void *)exynos4210_pin_ctrl }, { .compatible = "samsung,exynos4x12-pinctrl", .data = (void *)exynos4x12_pin_ctrl }, + { .compatible = "samsung,exynos5250-pinctrl", + .data = (void *)exynos5250_pin_ctrl }, {}, }; MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index e2d4e67f7e88..ee964aadce0c 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -237,5 +237,6 @@ struct samsung_pmx_func { /* list of all exported SoC specific data */ extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; +extern struct samsung_pin_ctrl exynos5250_pin_ctrl[]; #endif /* __PINCTRL_SAMSUNG_H */ diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 1a00658b3ea0..bd83c8b01cd1 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -194,6 +194,11 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin, } if (!gpio_range) { + /* + * A pin should not be freed more times than allocated. + */ + if (WARN_ON(!desc->mux_usecount)) + return NULL; desc->mux_usecount--; if (desc->mux_usecount) return NULL; diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index 709008e94124..6f15c03077a0 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -2733,9 +2733,9 @@ static struct pinmux_data_reg pinmux_data_regs[] = { { }, }; -/* IRQ pins through INTCS with IRQ0->15 from 0x200 and IRQ16-31 from 0x3200 */ -#define EXT_IRQ16L(n) intcs_evt2irq(0x200 + ((n) << 5)) -#define EXT_IRQ16H(n) intcs_evt2irq(0x3200 + ((n - 16) << 5)) +/* External IRQ pins mapped at IRQPIN_BASE */ +#define EXT_IRQ16L(n) irq_pin(n) +#define EXT_IRQ16H(n) irq_pin(n) static struct pinmux_irq pinmux_irqs[] = { PINMUX_IRQ(EXT_IRQ16H(19), PORT9_FN0), diff --git a/drivers/pinctrl/vt8500/Kconfig b/drivers/pinctrl/vt8500/Kconfig new file mode 100644 index 000000000000..55724a73d94a --- /dev/null +++ b/drivers/pinctrl/vt8500/Kconfig @@ -0,0 +1,52 @@ +# +# VIA/Wondermedia PINCTRL drivers +# + +if ARCH_VT8500 + +config PINCTRL_WMT + bool + select PINMUX + select GENERIC_PINCONF + +config PINCTRL_VT8500 + bool "VIA VT8500 pin controller driver" + depends on ARCH_WM8505 + select PINCTRL_WMT + help + Say yes here to support the gpio/pin control module on + VIA VT8500 SoCs. + +config PINCTRL_WM8505 + bool "Wondermedia WM8505 pin controller driver" + depends on ARCH_WM8505 + select PINCTRL_WMT + help + Say yes here to support the gpio/pin control module on + Wondermedia WM8505 SoCs. + +config PINCTRL_WM8650 + bool "Wondermedia WM8650 pin controller driver" + depends on ARCH_WM8505 + select PINCTRL_WMT + help + Say yes here to support the gpio/pin control module on + Wondermedia WM8650 SoCs. + +config PINCTRL_WM8750 + bool "Wondermedia WM8750 pin controller driver" + depends on ARCH_WM8750 + select PINCTRL_WMT + help + Say yes here to support the gpio/pin control module on + Wondermedia WM8750 SoCs. + +config PINCTRL_WM8850 + bool "Wondermedia WM8850 pin controller driver" + depends on ARCH_WM8850 + select PINCTRL_WMT + help + Say yes here to support the gpio/pin control module on + Wondermedia WM8850 SoCs. + +endif diff --git a/drivers/pinctrl/vt8500/Makefile b/drivers/pinctrl/vt8500/Makefile new file mode 100644 index 000000000000..24ec45dd0d80 --- /dev/null +++ b/drivers/pinctrl/vt8500/Makefile @@ -0,0 +1,8 @@ +# VIA/Wondermedia pinctrl support + +obj-$(CONFIG_PINCTRL_WMT) += pinctrl-wmt.o +obj-$(CONFIG_PINCTRL_VT8500) += pinctrl-vt8500.o +obj-$(CONFIG_PINCTRL_WM8505) += pinctrl-wm8505.o +obj-$(CONFIG_PINCTRL_WM8650) += pinctrl-wm8650.o +obj-$(CONFIG_PINCTRL_WM8750) += pinctrl-wm8750.o +obj-$(CONFIG_PINCTRL_WM8850) += pinctrl-wm8850.o diff --git a/drivers/pinctrl/vt8500/pinctrl-vt8500.c b/drivers/pinctrl/vt8500/pinctrl-vt8500.c new file mode 100644 index 000000000000..f2fe9f85cfa6 --- /dev/null +++ b/drivers/pinctrl/vt8500/pinctrl-vt8500.c @@ -0,0 +1,501 @@ +/* + * Pinctrl data for VIA VT8500 SoC + * + * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> + * + * 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. + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "pinctrl-wmt.h" + +/* + * Describe the register offsets within the GPIO memory space + * The dedicated external GPIO's should always be listed in bank 0 + * so they are exported in the 0..31 range which is what users + * expect. + * + * Do not reorder these banks as it will change the pin numbering + */ +static const struct wmt_pinctrl_bank_registers vt8500_banks[] = { + WMT_PINCTRL_BANK(NO_REG, 0x3C, 0x5C, 0x7C, NO_REG, NO_REG), /* 0 */ + WMT_PINCTRL_BANK(0x00, 0x20, 0x40, 0x60, NO_REG, NO_REG), /* 1 */ + WMT_PINCTRL_BANK(0x04, 0x24, 0x44, 0x64, NO_REG, NO_REG), /* 2 */ + WMT_PINCTRL_BANK(0x08, 0x28, 0x48, 0x68, NO_REG, NO_REG), /* 3 */ + WMT_PINCTRL_BANK(0x0C, 0x2C, 0x4C, 0x6C, NO_REG, NO_REG), /* 4 */ + WMT_PINCTRL_BANK(0x10, 0x30, 0x50, 0x70, NO_REG, NO_REG), /* 5 */ + WMT_PINCTRL_BANK(0x14, 0x34, 0x54, 0x74, NO_REG, NO_REG), /* 6 */ +}; + +/* Please keep sorted by bank/bit */ +#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0) +#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1) +#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2) +#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3) +#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4) +#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5) +#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6) +#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7) +#define WMT_PIN_EXTGPIO8 WMT_PIN(0, 8) +#define WMT_PIN_UART0RTS WMT_PIN(1, 0) +#define WMT_PIN_UART0TXD WMT_PIN(1, 1) +#define WMT_PIN_UART0CTS WMT_PIN(1, 2) +#define WMT_PIN_UART0RXD WMT_PIN(1, 3) +#define WMT_PIN_UART1RTS WMT_PIN(1, 4) +#define WMT_PIN_UART1TXD WMT_PIN(1, 5) +#define WMT_PIN_UART1CTS WMT_PIN(1, 6) +#define WMT_PIN_UART1RXD WMT_PIN(1, 7) +#define WMT_PIN_SPI0CLK WMT_PIN(1, 8) +#define WMT_PIN_SPI0SS WMT_PIN(1, 9) +#define WMT_PIN_SPI0MISO WMT_PIN(1, 10) +#define WMT_PIN_SPI0MOSI WMT_PIN(1, 11) +#define WMT_PIN_SPI1CLK WMT_PIN(1, 12) +#define WMT_PIN_SPI1SS WMT_PIN(1, 13) +#define WMT_PIN_SPI1MISO WMT_PIN(1, 14) +#define WMT_PIN_SPI1MOSI WMT_PIN(1, 15) +#define WMT_PIN_SPI2CLK WMT_PIN(1, 16) +#define WMT_PIN_SPI2SS WMT_PIN(1, 17) +#define WMT_PIN_SPI2MISO WMT_PIN(1, 18) +#define WMT_PIN_SPI2MOSI WMT_PIN(1, 19) +#define WMT_PIN_SDDATA0 WMT_PIN(2, 0) +#define WMT_PIN_SDDATA1 WMT_PIN(2, 1) +#define WMT_PIN_SDDATA2 WMT_PIN(2, 2) +#define WMT_PIN_SDDATA3 WMT_PIN(2, 3) +#define WMT_PIN_MMCDATA0 WMT_PIN(2, 4) +#define WMT_PIN_MMCDATA1 WMT_PIN(2, 5) +#define WMT_PIN_MMCDATA2 WMT_PIN(2, 6) +#define WMT_PIN_MMCDATA3 WMT_PIN(2, 7) +#define WMT_PIN_SDCLK WMT_PIN(2, 8) +#define WMT_PIN_SDWP WMT_PIN(2, 9) +#define WMT_PIN_SDCMD WMT_PIN(2, 10) +#define WMT_PIN_MSDATA0 WMT_PIN(2, 16) +#define WMT_PIN_MSDATA1 WMT_PIN(2, 17) +#define WMT_PIN_MSDATA2 WMT_PIN(2, 18) +#define WMT_PIN_MSDATA3 WMT_PIN(2, 19) +#define WMT_PIN_MSCLK WMT_PIN(2, 20) +#define WMT_PIN_MSBS WMT_PIN(2, 21) +#define WMT_PIN_MSINS WMT_PIN(2, 22) +#define WMT_PIN_I2C0SCL WMT_PIN(2, 24) +#define WMT_PIN_I2C0SDA WMT_PIN(2, 25) +#define WMT_PIN_I2C1SCL WMT_PIN(2, 26) +#define WMT_PIN_I2C1SDA WMT_PIN(2, 27) +#define WMT_PIN_MII0RXD0 WMT_PIN(3, 0) +#define WMT_PIN_MII0RXD1 WMT_PIN(3, 1) +#define WMT_PIN_MII0RXD2 WMT_PIN(3, 2) +#define WMT_PIN_MII0RXD3 WMT_PIN(3, 3) +#define WMT_PIN_MII0RXCLK WMT_PIN(3, 4) +#define WMT_PIN_MII0RXDV WMT_PIN(3, 5) +#define WMT_PIN_MII0RXERR WMT_PIN(3, 6) +#define WMT_PIN_MII0PHYRST WMT_PIN(3, 7) +#define WMT_PIN_MII0TXD0 WMT_PIN(3, 8) +#define WMT_PIN_MII0TXD1 WMT_PIN(3, 9) +#define WMT_PIN_MII0TXD2 WMT_PIN(3, 10) +#define WMT_PIN_MII0TXD3 WMT_PIN(3, 11) +#define WMT_PIN_MII0TXCLK WMT_PIN(3, 12) +#define WMT_PIN_MII0TXEN WMT_PIN(3, 13) +#define WMT_PIN_MII0TXERR WMT_PIN(3, 14) +#define WMT_PIN_MII0PHYPD WMT_PIN(3, 15) +#define WMT_PIN_MII0COL WMT_PIN(3, 16) +#define WMT_PIN_MII0CRS WMT_PIN(3, 17) +#define WMT_PIN_MII0MDIO WMT_PIN(3, 18) +#define WMT_PIN_MII0MDC WMT_PIN(3, 19) +#define WMT_PIN_SEECS WMT_PIN(3, 20) +#define WMT_PIN_SEECK WMT_PIN(3, 21) +#define WMT_PIN_SEEDI WMT_PIN(3, 22) +#define WMT_PIN_SEEDO WMT_PIN(3, 23) +#define WMT_PIN_IDEDREQ0 WMT_PIN(3, 24) +#define WMT_PIN_IDEDREQ1 WMT_PIN(3, 25) +#define WMT_PIN_IDEIOW WMT_PIN(3, 26) +#define WMT_PIN_IDEIOR WMT_PIN(3, 27) +#define WMT_PIN_IDEDACK WMT_PIN(3, 28) +#define WMT_PIN_IDEIORDY WMT_PIN(3, 29) +#define WMT_PIN_IDEINTRQ WMT_PIN(3, 30) +#define WMT_PIN_VDIN0 WMT_PIN(4, 0) +#define WMT_PIN_VDIN1 WMT_PIN(4, 1) +#define WMT_PIN_VDIN2 WMT_PIN(4, 2) +#define WMT_PIN_VDIN3 WMT_PIN(4, 3) +#define WMT_PIN_VDIN4 WMT_PIN(4, 4) +#define WMT_PIN_VDIN5 WMT_PIN(4, 5) +#define WMT_PIN_VDIN6 WMT_PIN(4, 6) +#define WMT_PIN_VDIN7 WMT_PIN(4, 7) +#define WMT_PIN_VDOUT0 WMT_PIN(4, 8) +#define WMT_PIN_VDOUT1 WMT_PIN(4, 9) +#define WMT_PIN_VDOUT2 WMT_PIN(4, 10) +#define WMT_PIN_VDOUT3 WMT_PIN(4, 11) +#define WMT_PIN_VDOUT4 WMT_PIN(4, 12) +#define WMT_PIN_VDOUT5 WMT_PIN(4, 13) +#define WMT_PIN_NANDCLE0 WMT_PIN(4, 14) +#define WMT_PIN_NANDCLE1 WMT_PIN(4, 15) +#define WMT_PIN_VDOUT6_7 WMT_PIN(4, 16) +#define WMT_PIN_VHSYNC WMT_PIN(4, 17) +#define WMT_PIN_VVSYNC WMT_PIN(4, 18) +#define WMT_PIN_TSDIN0 WMT_PIN(5, 8) +#define WMT_PIN_TSDIN1 WMT_PIN(5, 9) +#define WMT_PIN_TSDIN2 WMT_PIN(5, 10) +#define WMT_PIN_TSDIN3 WMT_PIN(5, 11) +#define WMT_PIN_TSDIN4 WMT_PIN(5, 12) +#define WMT_PIN_TSDIN5 WMT_PIN(5, 13) +#define WMT_PIN_TSDIN6 WMT_PIN(5, 14) +#define WMT_PIN_TSDIN7 WMT_PIN(5, 15) +#define WMT_PIN_TSSYNC WMT_PIN(5, 16) +#define WMT_PIN_TSVALID WMT_PIN(5, 17) +#define WMT_PIN_TSCLK WMT_PIN(5, 18) +#define WMT_PIN_LCDD0 WMT_PIN(6, 0) +#define WMT_PIN_LCDD1 WMT_PIN(6, 1) +#define WMT_PIN_LCDD2 WMT_PIN(6, 2) +#define WMT_PIN_LCDD3 WMT_PIN(6, 3) +#define WMT_PIN_LCDD4 WMT_PIN(6, 4) +#define WMT_PIN_LCDD5 WMT_PIN(6, 5) +#define WMT_PIN_LCDD6 WMT_PIN(6, 6) +#define WMT_PIN_LCDD7 WMT_PIN(6, 7) +#define WMT_PIN_LCDD8 WMT_PIN(6, 8) +#define WMT_PIN_LCDD9 WMT_PIN(6, 9) +#define WMT_PIN_LCDD10 WMT_PIN(6, 10) +#define WMT_PIN_LCDD11 WMT_PIN(6, 11) +#define WMT_PIN_LCDD12 WMT_PIN(6, 12) +#define WMT_PIN_LCDD13 WMT_PIN(6, 13) +#define WMT_PIN_LCDD14 WMT_PIN(6, 14) +#define WMT_PIN_LCDD15 WMT_PIN(6, 15) +#define WMT_PIN_LCDD16 WMT_PIN(6, 16) +#define WMT_PIN_LCDD17 WMT_PIN(6, 17) +#define WMT_PIN_LCDCLK WMT_PIN(6, 18) +#define WMT_PIN_LCDDEN WMT_PIN(6, 19) +#define WMT_PIN_LCDLINE WMT_PIN(6, 20) +#define WMT_PIN_LCDFRM WMT_PIN(6, 21) +#define WMT_PIN_LCDBIAS WMT_PIN(6, 22) + +static const struct pinctrl_pin_desc vt8500_pins[] = { + PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"), + PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"), + PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"), + PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"), + PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"), + PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"), + PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"), + PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"), + PINCTRL_PIN(WMT_PIN_EXTGPIO8, "extgpio8"), + PINCTRL_PIN(WMT_PIN_UART0RTS, "uart0_rts"), + PINCTRL_PIN(WMT_PIN_UART0TXD, "uart0_txd"), + PINCTRL_PIN(WMT_PIN_UART0CTS, "uart0_cts"), + PINCTRL_PIN(WMT_PIN_UART0RXD, "uart0_rxd"), + PINCTRL_PIN(WMT_PIN_UART1RTS, "uart1_rts"), + PINCTRL_PIN(WMT_PIN_UART1TXD, "uart1_txd"), + PINCTRL_PIN(WMT_PIN_UART1CTS, "uart1_cts"), + PINCTRL_PIN(WMT_PIN_UART1RXD, "uart1_rxd"), + PINCTRL_PIN(WMT_PIN_SPI0CLK, "spi0_clk"), + PINCTRL_PIN(WMT_PIN_SPI0SS, "spi0_ss"), + PINCTRL_PIN(WMT_PIN_SPI0MISO, "spi0_miso"), + PINCTRL_PIN(WMT_PIN_SPI0MOSI, "spi0_mosi"), + PINCTRL_PIN(WMT_PIN_SPI1CLK, "spi1_clk"), + PINCTRL_PIN(WMT_PIN_SPI1SS, "spi1_ss"), + PINCTRL_PIN(WMT_PIN_SPI1MISO, "spi1_miso"), + PINCTRL_PIN(WMT_PIN_SPI1MOSI, "spi1_mosi"), + PINCTRL_PIN(WMT_PIN_SPI2CLK, "spi2_clk"), + PINCTRL_PIN(WMT_PIN_SPI2SS, "spi2_ss"), + PINCTRL_PIN(WMT_PIN_SPI2MISO, "spi2_miso"), + PINCTRL_PIN(WMT_PIN_SPI2MOSI, "spi2_mosi"), + PINCTRL_PIN(WMT_PIN_SDDATA0, "sd_data0"), + PINCTRL_PIN(WMT_PIN_SDDATA1, "sd_data1"), + PINCTRL_PIN(WMT_PIN_SDDATA2, "sd_data2"), + PINCTRL_PIN(WMT_PIN_SDDATA3, "sd_data3"), + PINCTRL_PIN(WMT_PIN_MMCDATA0, "mmc_data0"), + PINCTRL_PIN(WMT_PIN_MMCDATA1, "mmc_data1"), + PINCTRL_PIN(WMT_PIN_MMCDATA2, "mmc_data2"), + PINCTRL_PIN(WMT_PIN_MMCDATA3, "mmc_data3"), + PINCTRL_PIN(WMT_PIN_SDCLK, "sd_clk"), + PINCTRL_PIN(WMT_PIN_SDWP, "sd_wp"), + PINCTRL_PIN(WMT_PIN_SDCMD, "sd_cmd"), + PINCTRL_PIN(WMT_PIN_MSDATA0, "ms_data0"), + PINCTRL_PIN(WMT_PIN_MSDATA1, "ms_data1"), + PINCTRL_PIN(WMT_PIN_MSDATA2, "ms_data2"), + PINCTRL_PIN(WMT_PIN_MSDATA3, "ms_data3"), + PINCTRL_PIN(WMT_PIN_MSCLK, "ms_clk"), + PINCTRL_PIN(WMT_PIN_MSBS, "ms_bs"), + PINCTRL_PIN(WMT_PIN_MSINS, "ms_ins"), + PINCTRL_PIN(WMT_PIN_I2C0SCL, "i2c0_scl"), + PINCTRL_PIN(WMT_PIN_I2C0SDA, "i2c0_sda"), + PINCTRL_PIN(WMT_PIN_I2C1SCL, "i2c1_scl"), + PINCTRL_PIN(WMT_PIN_I2C1SDA, "i2c1_sda"), + PINCTRL_PIN(WMT_PIN_MII0RXD0, "mii0_rxd0"), + PINCTRL_PIN(WMT_PIN_MII0RXD1, "mii0_rxd1"), + PINCTRL_PIN(WMT_PIN_MII0RXD2, "mii0_rxd2"), + PINCTRL_PIN(WMT_PIN_MII0RXD3, "mii0_rxd3"), + PINCTRL_PIN(WMT_PIN_MII0RXCLK, "mii0_rxclk"), + PINCTRL_PIN(WMT_PIN_MII0RXDV, "mii0_rxdv"), + PINCTRL_PIN(WMT_PIN_MII0RXERR, "mii0_rxerr"), + PINCTRL_PIN(WMT_PIN_MII0PHYRST, "mii0_phyrst"), + PINCTRL_PIN(WMT_PIN_MII0TXD0, "mii0_txd0"), + PINCTRL_PIN(WMT_PIN_MII0TXD1, "mii0_txd1"), + PINCTRL_PIN(WMT_PIN_MII0TXD2, "mii0_txd2"), + PINCTRL_PIN(WMT_PIN_MII0TXD3, "mii0_txd3"), + PINCTRL_PIN(WMT_PIN_MII0TXCLK, "mii0_txclk"), + PINCTRL_PIN(WMT_PIN_MII0TXEN, "mii0_txen"), + PINCTRL_PIN(WMT_PIN_MII0TXERR, "mii0_txerr"), + PINCTRL_PIN(WMT_PIN_MII0PHYPD, "mii0_phypd"), + PINCTRL_PIN(WMT_PIN_MII0COL, "mii0_col"), + PINCTRL_PIN(WMT_PIN_MII0CRS, "mii0_crs"), + PINCTRL_PIN(WMT_PIN_MII0MDIO, "mii0_mdio"), + PINCTRL_PIN(WMT_PIN_MII0MDC, "mii0_mdc"), + PINCTRL_PIN(WMT_PIN_SEECS, "see_cs"), + PINCTRL_PIN(WMT_PIN_SEECK, "see_ck"), + PINCTRL_PIN(WMT_PIN_SEEDI, "see_di"), + PINCTRL_PIN(WMT_PIN_SEEDO, "see_do"), + PINCTRL_PIN(WMT_PIN_IDEDREQ0, "ide_dreq0"), + PINCTRL_PIN(WMT_PIN_IDEDREQ1, "ide_dreq1"), + PINCTRL_PIN(WMT_PIN_IDEIOW, "ide_iow"), + PINCTRL_PIN(WMT_PIN_IDEIOR, "ide_ior"), + PINCTRL_PIN(WMT_PIN_IDEDACK, "ide_dack"), + PINCTRL_PIN(WMT_PIN_IDEIORDY, "ide_iordy"), + PINCTRL_PIN(WMT_PIN_IDEINTRQ, "ide_intrq"), + PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"), + PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"), + PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"), + PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"), + PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"), + PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"), + PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"), + PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"), + PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"), + PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"), + PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"), + PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"), + PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"), + PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"), + PINCTRL_PIN(WMT_PIN_NANDCLE0, "nand_cle0"), + PINCTRL_PIN(WMT_PIN_NANDCLE1, "nand_cle1"), + PINCTRL_PIN(WMT_PIN_VDOUT6_7, "vdout6_7"), + PINCTRL_PIN(WMT_PIN_VHSYNC, "vhsync"), + PINCTRL_PIN(WMT_PIN_VVSYNC, "vvsync"), + PINCTRL_PIN(WMT_PIN_TSDIN0, "tsdin0"), + PINCTRL_PIN(WMT_PIN_TSDIN1, "tsdin1"), + PINCTRL_PIN(WMT_PIN_TSDIN2, "tsdin2"), + PINCTRL_PIN(WMT_PIN_TSDIN3, "tsdin3"), + PINCTRL_PIN(WMT_PIN_TSDIN4, "tsdin4"), + PINCTRL_PIN(WMT_PIN_TSDIN5, "tsdin5"), + PINCTRL_PIN(WMT_PIN_TSDIN6, "tsdin6"), + PINCTRL_PIN(WMT_PIN_TSDIN7, "tsdin7"), + PINCTRL_PIN(WMT_PIN_TSSYNC, "tssync"), + PINCTRL_PIN(WMT_PIN_TSVALID, "tsvalid"), + PINCTRL_PIN(WMT_PIN_TSCLK, "tsclk"), + PINCTRL_PIN(WMT_PIN_LCDD0, "lcd_d0"), + PINCTRL_PIN(WMT_PIN_LCDD1, "lcd_d1"), + PINCTRL_PIN(WMT_PIN_LCDD2, "lcd_d2"), + PINCTRL_PIN(WMT_PIN_LCDD3, "lcd_d3"), + PINCTRL_PIN(WMT_PIN_LCDD4, "lcd_d4"), + PINCTRL_PIN(WMT_PIN_LCDD5, "lcd_d5"), + PINCTRL_PIN(WMT_PIN_LCDD6, "lcd_d6"), + PINCTRL_PIN(WMT_PIN_LCDD7, "lcd_d7"), + PINCTRL_PIN(WMT_PIN_LCDD8, "lcd_d8"), + PINCTRL_PIN(WMT_PIN_LCDD9, "lcd_d9"), + PINCTRL_PIN(WMT_PIN_LCDD10, "lcd_d10"), + PINCTRL_PIN(WMT_PIN_LCDD11, "lcd_d11"), + PINCTRL_PIN(WMT_PIN_LCDD12, "lcd_d12"), + PINCTRL_PIN(WMT_PIN_LCDD13, "lcd_d13"), + PINCTRL_PIN(WMT_PIN_LCDD14, "lcd_d14"), + PINCTRL_PIN(WMT_PIN_LCDD15, "lcd_d15"), + PINCTRL_PIN(WMT_PIN_LCDD16, "lcd_d16"), + PINCTRL_PIN(WMT_PIN_LCDD17, "lcd_d17"), + PINCTRL_PIN(WMT_PIN_LCDCLK, "lcd_clk"), + PINCTRL_PIN(WMT_PIN_LCDDEN, "lcd_den"), + PINCTRL_PIN(WMT_PIN_LCDLINE, "lcd_line"), + PINCTRL_PIN(WMT_PIN_LCDFRM, "lcd_frm"), + PINCTRL_PIN(WMT_PIN_LCDBIAS, "lcd_bias"), +}; + +/* Order of these names must match the above list */ +static const char * const vt8500_groups[] = { + "extgpio0", + "extgpio1", + "extgpio2", + "extgpio3", + "extgpio4", + "extgpio5", + "extgpio6", + "extgpio7", + "extgpio8", + "uart0_rts", + "uart0_txd", + "uart0_cts", + "uart0_rxd", + "uart1_rts", + "uart1_txd", + "uart1_cts", + "uart1_rxd", + "spi0_clk", + "spi0_ss", + "spi0_miso", + "spi0_mosi", + "spi1_clk", + "spi1_ss", + "spi1_miso", + "spi1_mosi", + "spi2_clk", + "spi2_ss", + "spi2_miso", + "spi2_mosi", + "sd_data0", + "sd_data1", + "sd_data2", + "sd_data3", + "mmc_data0", + "mmc_data1", + "mmc_data2", + "mmc_data3", + "sd_clk", + "sd_wp", + "sd_cmd", + "ms_data0", + "ms_data1", + "ms_data2", + "ms_data3", + "ms_clk", + "ms_bs", + "ms_ins", + "i2c0_scl", + "i2c0_sda", + "i2c1_scl", + "i2c1_sda", + "mii0_rxd0", + "mii0_rxd1", + "mii0_rxd2", + "mii0_rxd3", + "mii0_rxclk", + "mii0_rxdv", + "mii0_rxerr", + "mii0_phyrst", + "mii0_txd0", + "mii0_txd1", + "mii0_txd2", + "mii0_txd3", + "mii0_txclk", + "mii0_txen", + "mii0_txerr", + "mii0_phypd", + "mii0_col", + "mii0_crs", + "mii0_mdio", + "mii0_mdc", + "see_cs", + "see_ck", + "see_di", + "see_do", + "ide_dreq0", + "ide_dreq1", + "ide_iow", + "ide_ior", + "ide_dack", + "ide_iordy", + "ide_intrq", + "vdin0", + "vdin1", + "vdin2", + "vdin3", + "vdin4", + "vdin5", + "vdin6", + "vdin7", + "vdout0", + "vdout1", + "vdout2", + "vdout3", + "vdout4", + "vdout5", + "nand_cle0", + "nand_cle1", + "vdout6_7", + "vhsync", + "vvsync", + "tsdin0", + "tsdin1", + "tsdin2", + "tsdin3", + "tsdin4", + "tsdin5", + "tsdin6", + "tsdin7", + "tssync", + "tsvalid", + "tsclk", + "lcd_d0", + "lcd_d1", + "lcd_d2", + "lcd_d3", + "lcd_d4", + "lcd_d5", + "lcd_d6", + "lcd_d7", + "lcd_d8", + "lcd_d9", + "lcd_d10", + "lcd_d11", + "lcd_d12", + "lcd_d13", + "lcd_d14", + "lcd_d15", + "lcd_d16", + "lcd_d17", + "lcd_clk", + "lcd_den", + "lcd_line", + "lcd_frm", + "lcd_bias", +}; + +static int vt8500_pinctrl_probe(struct platform_device *pdev) +{ + struct wmt_pinctrl_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "failed to allocate data\n"); + return -ENOMEM; + } + + data->banks = vt8500_banks; + data->nbanks = ARRAY_SIZE(vt8500_banks); + data->pins = vt8500_pins; + data->npins = ARRAY_SIZE(vt8500_pins); + data->groups = vt8500_groups; + data->ngroups = ARRAY_SIZE(vt8500_groups); + + return wmt_pinctrl_probe(pdev, data); +} + +static int vt8500_pinctrl_remove(struct platform_device *pdev) +{ + return wmt_pinctrl_remove(pdev); +} + +static struct of_device_id wmt_pinctrl_of_match[] = { + { .compatible = "via,vt8500-pinctrl" }, + { /* sentinel */ }, +}; + +static struct platform_driver wmt_pinctrl_driver = { + .probe = vt8500_pinctrl_probe, + .remove = vt8500_pinctrl_remove, + .driver = { + .name = "pinctrl-vt8500", + .owner = THIS_MODULE, + .of_match_table = wmt_pinctrl_of_match, + }, +}; + +module_platform_driver(wmt_pinctrl_driver); + +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_DESCRIPTION("VIA VT8500 Pincontrol driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match); diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8505.c b/drivers/pinctrl/vt8500/pinctrl-wm8505.c new file mode 100644 index 000000000000..483ba732694e --- /dev/null +++ b/drivers/pinctrl/vt8500/pinctrl-wm8505.c @@ -0,0 +1,532 @@ +/* + * Pinctrl data for Wondermedia WM8505 SoC + * + * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> + * + * 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. + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "pinctrl-wmt.h" + +/* + * Describe the register offsets within the GPIO memory space + * The dedicated external GPIO's should always be listed in bank 0 + * so they are exported in the 0..31 range which is what users + * expect. + * + * Do not reorder these banks as it will change the pin numbering + */ +static const struct wmt_pinctrl_bank_registers wm8505_banks[] = { + WMT_PINCTRL_BANK(0x64, 0x8C, 0xB4, 0xDC, NO_REG, NO_REG), /* 0 */ + WMT_PINCTRL_BANK(0x40, 0x68, 0x90, 0xB8, NO_REG, NO_REG), /* 1 */ + WMT_PINCTRL_BANK(0x44, 0x6C, 0x94, 0xBC, NO_REG, NO_REG), /* 2 */ + WMT_PINCTRL_BANK(0x48, 0x70, 0x98, 0xC0, NO_REG, NO_REG), /* 3 */ + WMT_PINCTRL_BANK(0x4C, 0x74, 0x9C, 0xC4, NO_REG, NO_REG), /* 4 */ + WMT_PINCTRL_BANK(0x50, 0x78, 0xA0, 0xC8, NO_REG, NO_REG), /* 5 */ + WMT_PINCTRL_BANK(0x54, 0x7C, 0xA4, 0xD0, NO_REG, NO_REG), /* 6 */ + WMT_PINCTRL_BANK(0x58, 0x80, 0xA8, 0xD4, NO_REG, NO_REG), /* 7 */ + WMT_PINCTRL_BANK(0x5C, 0x84, 0xAC, 0xD8, NO_REG, NO_REG), /* 8 */ + WMT_PINCTRL_BANK(0x60, 0x88, 0xB0, 0xDC, NO_REG, NO_REG), /* 9 */ + WMT_PINCTRL_BANK(0x500, 0x504, 0x508, 0x50C, NO_REG, NO_REG), /* 10 */ +}; + +/* Please keep sorted by bank/bit */ +#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0) +#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1) +#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2) +#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3) +#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4) +#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5) +#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6) +#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7) +#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16) +#define WMT_PIN_WAKEUP1 WMT_PIN(0, 17) +#define WMT_PIN_WAKEUP2 WMT_PIN(0, 18) +#define WMT_PIN_WAKEUP3 WMT_PIN(0, 19) +#define WMT_PIN_SUSGPIO0 WMT_PIN(0, 21) +#define WMT_PIN_SDDATA0 WMT_PIN(1, 0) +#define WMT_PIN_SDDATA1 WMT_PIN(1, 1) +#define WMT_PIN_SDDATA2 WMT_PIN(1, 2) +#define WMT_PIN_SDDATA3 WMT_PIN(1, 3) +#define WMT_PIN_MMCDATA0 WMT_PIN(1, 4) +#define WMT_PIN_MMCDATA1 WMT_PIN(1, 5) +#define WMT_PIN_MMCDATA2 WMT_PIN(1, 6) +#define WMT_PIN_MMCDATA3 WMT_PIN(1, 7) +#define WMT_PIN_VDIN0 WMT_PIN(2, 0) +#define WMT_PIN_VDIN1 WMT_PIN(2, 1) +#define WMT_PIN_VDIN2 WMT_PIN(2, 2) +#define WMT_PIN_VDIN3 WMT_PIN(2, 3) +#define WMT_PIN_VDIN4 WMT_PIN(2, 4) +#define WMT_PIN_VDIN5 WMT_PIN(2, 5) +#define WMT_PIN_VDIN6 WMT_PIN(2, 6) +#define WMT_PIN_VDIN7 WMT_PIN(2, 7) +#define WMT_PIN_VDOUT0 WMT_PIN(2, 8) +#define WMT_PIN_VDOUT1 WMT_PIN(2, 9) +#define WMT_PIN_VDOUT2 WMT_PIN(2, 10) +#define WMT_PIN_VDOUT3 WMT_PIN(2, 11) +#define WMT_PIN_VDOUT4 WMT_PIN(2, 12) +#define WMT_PIN_VDOUT5 WMT_PIN(2, 13) +#define WMT_PIN_VDOUT6 WMT_PIN(2, 14) +#define WMT_PIN_VDOUT7 WMT_PIN(2, 15) +#define WMT_PIN_VDOUT8 WMT_PIN(2, 16) +#define WMT_PIN_VDOUT9 WMT_PIN(2, 17) +#define WMT_PIN_VDOUT10 WMT_PIN(2, 18) +#define WMT_PIN_VDOUT11 WMT_PIN(2, 19) +#define WMT_PIN_VDOUT12 WMT_PIN(2, 20) +#define WMT_PIN_VDOUT13 WMT_PIN(2, 21) +#define WMT_PIN_VDOUT14 WMT_PIN(2, 22) +#define WMT_PIN_VDOUT15 WMT_PIN(2, 23) +#define WMT_PIN_VDOUT16 WMT_PIN(2, 24) +#define WMT_PIN_VDOUT17 WMT_PIN(2, 25) +#define WMT_PIN_VDOUT18 WMT_PIN(2, 26) +#define WMT_PIN_VDOUT19 WMT_PIN(2, 27) +#define WMT_PIN_VDOUT20 WMT_PIN(2, 28) +#define WMT_PIN_VDOUT21 WMT_PIN(2, 29) +#define WMT_PIN_VDOUT22 WMT_PIN(2, 30) +#define WMT_PIN_VDOUT23 WMT_PIN(2, 31) +#define WMT_PIN_VHSYNC WMT_PIN(3, 0) +#define WMT_PIN_VVSYNC WMT_PIN(3, 1) +#define WMT_PIN_VGAHSYNC WMT_PIN(3, 2) +#define WMT_PIN_VGAVSYNC WMT_PIN(3, 3) +#define WMT_PIN_VDHSYNC WMT_PIN(3, 4) +#define WMT_PIN_VDVSYNC WMT_PIN(3, 5) +#define WMT_PIN_NORD0 WMT_PIN(4, 0) +#define WMT_PIN_NORD1 WMT_PIN(4, 1) +#define WMT_PIN_NORD2 WMT_PIN(4, 2) +#define WMT_PIN_NORD3 WMT_PIN(4, 3) +#define WMT_PIN_NORD4 WMT_PIN(4, 4) +#define WMT_PIN_NORD5 WMT_PIN(4, 5) +#define WMT_PIN_NORD6 WMT_PIN(4, 6) +#define WMT_PIN_NORD7 WMT_PIN(4, 7) +#define WMT_PIN_NORD8 WMT_PIN(4, 8) +#define WMT_PIN_NORD9 WMT_PIN(4, 9) +#define WMT_PIN_NORD10 WMT_PIN(4, 10) +#define WMT_PIN_NORD11 WMT_PIN(4, 11) +#define WMT_PIN_NORD12 WMT_PIN(4, 12) +#define WMT_PIN_NORD13 WMT_PIN(4, 13) +#define WMT_PIN_NORD14 WMT_PIN(4, 14) +#define WMT_PIN_NORD15 WMT_PIN(4, 15) +#define WMT_PIN_NORA0 WMT_PIN(5, 0) +#define WMT_PIN_NORA1 WMT_PIN(5, 1) +#define WMT_PIN_NORA2 WMT_PIN(5, 2) +#define WMT_PIN_NORA3 WMT_PIN(5, 3) +#define WMT_PIN_NORA4 WMT_PIN(5, 4) +#define WMT_PIN_NORA5 WMT_PIN(5, 5) +#define WMT_PIN_NORA6 WMT_PIN(5, 6) +#define WMT_PIN_NORA7 WMT_PIN(5, 7) +#define WMT_PIN_NORA8 WMT_PIN(5, 8) +#define WMT_PIN_NORA9 WMT_PIN(5, 9) +#define WMT_PIN_NORA10 WMT_PIN(5, 10) +#define WMT_PIN_NORA11 WMT_PIN(5, 11) +#define WMT_PIN_NORA12 WMT_PIN(5, 12) +#define WMT_PIN_NORA13 WMT_PIN(5, 13) +#define WMT_PIN_NORA14 WMT_PIN(5, 14) +#define WMT_PIN_NORA15 WMT_PIN(5, 15) +#define WMT_PIN_NORA16 WMT_PIN(5, 16) +#define WMT_PIN_NORA17 WMT_PIN(5, 17) +#define WMT_PIN_NORA18 WMT_PIN(5, 18) +#define WMT_PIN_NORA19 WMT_PIN(5, 19) +#define WMT_PIN_NORA20 WMT_PIN(5, 20) +#define WMT_PIN_NORA21 WMT_PIN(5, 21) +#define WMT_PIN_NORA22 WMT_PIN(5, 22) +#define WMT_PIN_NORA23 WMT_PIN(5, 23) +#define WMT_PIN_NORA24 WMT_PIN(5, 24) +#define WMT_PIN_AC97SDI WMT_PIN(6, 0) +#define WMT_PIN_AC97SYNC WMT_PIN(6, 1) +#define WMT_PIN_AC97SDO WMT_PIN(6, 2) +#define WMT_PIN_AC97BCLK WMT_PIN(6, 3) +#define WMT_PIN_AC97RST WMT_PIN(6, 4) +#define WMT_PIN_SFDO WMT_PIN(7, 0) +#define WMT_PIN_SFCS0 WMT_PIN(7, 1) +#define WMT_PIN_SFCS1 WMT_PIN(7, 2) +#define WMT_PIN_SFCLK WMT_PIN(7, 3) +#define WMT_PIN_SFDI WMT_PIN(7, 4) +#define WMT_PIN_SPI0CLK WMT_PIN(8, 0) +#define WMT_PIN_SPI0MISO WMT_PIN(8, 1) +#define WMT_PIN_SPI0MOSI WMT_PIN(8, 2) +#define WMT_PIN_SPI0SS WMT_PIN(8, 3) +#define WMT_PIN_SPI1CLK WMT_PIN(8, 4) +#define WMT_PIN_SPI1MISO WMT_PIN(8, 5) +#define WMT_PIN_SPI1MOSI WMT_PIN(8, 6) +#define WMT_PIN_SPI1SS WMT_PIN(8, 7) +#define WMT_PIN_SPI2CLK WMT_PIN(8, 8) +#define WMT_PIN_SPI2MISO WMT_PIN(8, 9) +#define WMT_PIN_SPI2MOSI WMT_PIN(8, 10) +#define WMT_PIN_SPI2SS WMT_PIN(8, 11) +#define WMT_PIN_UART0_RTS WMT_PIN(9, 0) +#define WMT_PIN_UART0_TXD WMT_PIN(9, 1) +#define WMT_PIN_UART0_CTS WMT_PIN(9, 2) +#define WMT_PIN_UART0_RXD WMT_PIN(9, 3) +#define WMT_PIN_UART1_RTS WMT_PIN(9, 4) +#define WMT_PIN_UART1_TXD WMT_PIN(9, 5) +#define WMT_PIN_UART1_CTS WMT_PIN(9, 6) +#define WMT_PIN_UART1_RXD WMT_PIN(9, 7) +#define WMT_PIN_UART2_RTS WMT_PIN(9, 8) +#define WMT_PIN_UART2_TXD WMT_PIN(9, 9) +#define WMT_PIN_UART2_CTS WMT_PIN(9, 10) +#define WMT_PIN_UART2_RXD WMT_PIN(9, 11) +#define WMT_PIN_UART3_RTS WMT_PIN(9, 12) +#define WMT_PIN_UART3_TXD WMT_PIN(9, 13) +#define WMT_PIN_UART3_CTS WMT_PIN(9, 14) +#define WMT_PIN_UART3_RXD WMT_PIN(9, 15) +#define WMT_PIN_I2C0SCL WMT_PIN(10, 0) +#define WMT_PIN_I2C0SDA WMT_PIN(10, 1) +#define WMT_PIN_I2C1SCL WMT_PIN(10, 2) +#define WMT_PIN_I2C1SDA WMT_PIN(10, 3) +#define WMT_PIN_I2C2SCL WMT_PIN(10, 4) +#define WMT_PIN_I2C2SDA WMT_PIN(10, 5) + +static const struct pinctrl_pin_desc wm8505_pins[] = { + PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"), + PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"), + PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"), + PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"), + PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"), + PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"), + PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"), + PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"), + PINCTRL_PIN(WMT_PIN_WAKEUP0, "wakeup0"), + PINCTRL_PIN(WMT_PIN_WAKEUP1, "wakeup1"), + PINCTRL_PIN(WMT_PIN_WAKEUP2, "wakeup2"), + PINCTRL_PIN(WMT_PIN_WAKEUP3, "wakeup3"), + PINCTRL_PIN(WMT_PIN_SUSGPIO0, "susgpio0"), + PINCTRL_PIN(WMT_PIN_SDDATA0, "sd_data0"), + PINCTRL_PIN(WMT_PIN_SDDATA1, "sd_data1"), + PINCTRL_PIN(WMT_PIN_SDDATA2, "sd_data2"), + PINCTRL_PIN(WMT_PIN_SDDATA3, "sd_data3"), + PINCTRL_PIN(WMT_PIN_MMCDATA0, "mmc_data0"), + PINCTRL_PIN(WMT_PIN_MMCDATA1, "mmc_data1"), + PINCTRL_PIN(WMT_PIN_MMCDATA2, "mmc_data2"), + PINCTRL_PIN(WMT_PIN_MMCDATA3, "mmc_data3"), + PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"), + PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"), + PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"), + PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"), + PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"), + PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"), + PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"), + PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"), + PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"), + PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"), + PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"), + PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"), + PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"), + PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"), + PINCTRL_PIN(WMT_PIN_VDOUT6, "vdout6"), + PINCTRL_PIN(WMT_PIN_VDOUT7, "vdout7"), + PINCTRL_PIN(WMT_PIN_VDOUT8, "vdout8"), + PINCTRL_PIN(WMT_PIN_VDOUT9, "vdout9"), + PINCTRL_PIN(WMT_PIN_VDOUT10, "vdout10"), + PINCTRL_PIN(WMT_PIN_VDOUT11, "vdout11"), + PINCTRL_PIN(WMT_PIN_VDOUT12, "vdout12"), + PINCTRL_PIN(WMT_PIN_VDOUT13, "vdout13"), + PINCTRL_PIN(WMT_PIN_VDOUT14, "vdout14"), + PINCTRL_PIN(WMT_PIN_VDOUT15, "vdout15"), + PINCTRL_PIN(WMT_PIN_VDOUT16, "vdout16"), + PINCTRL_PIN(WMT_PIN_VDOUT17, "vdout17"), + PINCTRL_PIN(WMT_PIN_VDOUT18, "vdout18"), + PINCTRL_PIN(WMT_PIN_VDOUT19, "vdout19"), + PINCTRL_PIN(WMT_PIN_VDOUT20, "vdout20"), + PINCTRL_PIN(WMT_PIN_VDOUT21, "vdout21"), + PINCTRL_PIN(WMT_PIN_VDOUT22, "vdout22"), + PINCTRL_PIN(WMT_PIN_VDOUT23, "vdout23"), + PINCTRL_PIN(WMT_PIN_VHSYNC, "v_hsync"), + PINCTRL_PIN(WMT_PIN_VVSYNC, "v_vsync"), + PINCTRL_PIN(WMT_PIN_VGAHSYNC, "vga_hsync"), + PINCTRL_PIN(WMT_PIN_VGAVSYNC, "vga_vsync"), + PINCTRL_PIN(WMT_PIN_VDHSYNC, "vd_hsync"), + PINCTRL_PIN(WMT_PIN_VDVSYNC, "vd_vsync"), + PINCTRL_PIN(WMT_PIN_NORD0, "nor_d0"), + PINCTRL_PIN(WMT_PIN_NORD1, "nor_d1"), + PINCTRL_PIN(WMT_PIN_NORD2, "nor_d2"), + PINCTRL_PIN(WMT_PIN_NORD3, "nor_d3"), + PINCTRL_PIN(WMT_PIN_NORD4, "nor_d4"), + PINCTRL_PIN(WMT_PIN_NORD5, "nor_d5"), + PINCTRL_PIN(WMT_PIN_NORD6, "nor_d6"), + PINCTRL_PIN(WMT_PIN_NORD7, "nor_d7"), + PINCTRL_PIN(WMT_PIN_NORD8, "nor_d8"), + PINCTRL_PIN(WMT_PIN_NORD9, "nor_d9"), + PINCTRL_PIN(WMT_PIN_NORD10, "nor_d10"), + PINCTRL_PIN(WMT_PIN_NORD11, "nor_d11"), + PINCTRL_PIN(WMT_PIN_NORD12, "nor_d12"), + PINCTRL_PIN(WMT_PIN_NORD13, "nor_d13"), + PINCTRL_PIN(WMT_PIN_NORD14, "nor_d14"), + PINCTRL_PIN(WMT_PIN_NORD15, "nor_d15"), + PINCTRL_PIN(WMT_PIN_NORA0, "nor_a0"), + PINCTRL_PIN(WMT_PIN_NORA1, "nor_a1"), + PINCTRL_PIN(WMT_PIN_NORA2, "nor_a2"), + PINCTRL_PIN(WMT_PIN_NORA3, "nor_a3"), + PINCTRL_PIN(WMT_PIN_NORA4, "nor_a4"), + PINCTRL_PIN(WMT_PIN_NORA5, "nor_a5"), + PINCTRL_PIN(WMT_PIN_NORA6, "nor_a6"), + PINCTRL_PIN(WMT_PIN_NORA7, "nor_a7"), + PINCTRL_PIN(WMT_PIN_NORA8, "nor_a8"), + PINCTRL_PIN(WMT_PIN_NORA9, "nor_a9"), + PINCTRL_PIN(WMT_PIN_NORA10, "nor_a10"), + PINCTRL_PIN(WMT_PIN_NORA11, "nor_a11"), + PINCTRL_PIN(WMT_PIN_NORA12, "nor_a12"), + PINCTRL_PIN(WMT_PIN_NORA13, "nor_a13"), + PINCTRL_PIN(WMT_PIN_NORA14, "nor_a14"), + PINCTRL_PIN(WMT_PIN_NORA15, "nor_a15"), + PINCTRL_PIN(WMT_PIN_NORA16, "nor_a16"), + PINCTRL_PIN(WMT_PIN_NORA17, "nor_a17"), + PINCTRL_PIN(WMT_PIN_NORA18, "nor_a18"), + PINCTRL_PIN(WMT_PIN_NORA19, "nor_a19"), + PINCTRL_PIN(WMT_PIN_NORA20, "nor_a20"), + PINCTRL_PIN(WMT_PIN_NORA21, "nor_a21"), + PINCTRL_PIN(WMT_PIN_NORA22, "nor_a22"), + PINCTRL_PIN(WMT_PIN_NORA23, "nor_a23"), + PINCTRL_PIN(WMT_PIN_NORA24, "nor_a24"), + PINCTRL_PIN(WMT_PIN_AC97SDI, "ac97_sdi"), + PINCTRL_PIN(WMT_PIN_AC97SYNC, "ac97_sync"), + PINCTRL_PIN(WMT_PIN_AC97SDO, "ac97_sdo"), + PINCTRL_PIN(WMT_PIN_AC97BCLK, "ac97_bclk"), + PINCTRL_PIN(WMT_PIN_AC97RST, "ac97_rst"), + PINCTRL_PIN(WMT_PIN_SFDO, "sf_do"), + PINCTRL_PIN(WMT_PIN_SFCS0, "sf_cs0"), + PINCTRL_PIN(WMT_PIN_SFCS1, "sf_cs1"), + PINCTRL_PIN(WMT_PIN_SFCLK, "sf_clk"), + PINCTRL_PIN(WMT_PIN_SFDI, "sf_di"), + PINCTRL_PIN(WMT_PIN_SPI0CLK, "spi0_clk"), + PINCTRL_PIN(WMT_PIN_SPI0MISO, "spi0_miso"), + PINCTRL_PIN(WMT_PIN_SPI0MOSI, "spi0_mosi"), + PINCTRL_PIN(WMT_PIN_SPI0SS, "spi0_ss"), + PINCTRL_PIN(WMT_PIN_SPI1CLK, "spi1_clk"), + PINCTRL_PIN(WMT_PIN_SPI1MISO, "spi1_miso"), + PINCTRL_PIN(WMT_PIN_SPI1MOSI, "spi1_mosi"), + PINCTRL_PIN(WMT_PIN_SPI1SS, "spi1_ss"), + PINCTRL_PIN(WMT_PIN_SPI2CLK, "spi2_clk"), + PINCTRL_PIN(WMT_PIN_SPI2MISO, "spi2_miso"), + PINCTRL_PIN(WMT_PIN_SPI2MOSI, "spi2_mosi"), + PINCTRL_PIN(WMT_PIN_SPI2SS, "spi2_ss"), + PINCTRL_PIN(WMT_PIN_UART0_RTS, "uart0_rts"), + PINCTRL_PIN(WMT_PIN_UART0_TXD, "uart0_txd"), + PINCTRL_PIN(WMT_PIN_UART0_CTS, "uart0_cts"), + PINCTRL_PIN(WMT_PIN_UART0_RXD, "uart0_rxd"), + PINCTRL_PIN(WMT_PIN_UART1_RTS, "uart1_rts"), + PINCTRL_PIN(WMT_PIN_UART1_TXD, "uart1_txd"), + PINCTRL_PIN(WMT_PIN_UART1_CTS, "uart1_cts"), + PINCTRL_PIN(WMT_PIN_UART1_RXD, "uart1_rxd"), + PINCTRL_PIN(WMT_PIN_UART2_RTS, "uart2_rts"), + PINCTRL_PIN(WMT_PIN_UART2_TXD, "uart2_txd"), + PINCTRL_PIN(WMT_PIN_UART2_CTS, "uart2_cts"), + PINCTRL_PIN(WMT_PIN_UART2_RXD, "uart2_rxd"), + PINCTRL_PIN(WMT_PIN_UART3_RTS, "uart3_rts"), + PINCTRL_PIN(WMT_PIN_UART3_TXD, "uart3_txd"), + PINCTRL_PIN(WMT_PIN_UART3_CTS, "uart3_cts"), + PINCTRL_PIN(WMT_PIN_UART3_RXD, "uart3_rxd"), + PINCTRL_PIN(WMT_PIN_I2C0SCL, "i2c0_scl"), + PINCTRL_PIN(WMT_PIN_I2C0SDA, "i2c0_sda"), + PINCTRL_PIN(WMT_PIN_I2C1SCL, "i2c1_scl"), + PINCTRL_PIN(WMT_PIN_I2C1SDA, "i2c1_sda"), + PINCTRL_PIN(WMT_PIN_I2C2SCL, "i2c2_scl"), + PINCTRL_PIN(WMT_PIN_I2C2SDA, "i2c2_sda"), +}; + +/* Order of these names must match the above list */ +static const char * const wm8505_groups[] = { + "extgpio0", + "extgpio1", + "extgpio2", + "extgpio3", + "extgpio4", + "extgpio5", + "extgpio6", + "extgpio7", + "wakeup0", + "wakeup1", + "wakeup2", + "wakeup3", + "susgpio0", + "sd_data0", + "sd_data1", + "sd_data2", + "sd_data3", + "mmc_data0", + "mmc_data1", + "mmc_data2", + "mmc_data3", + "vdin0", + "vdin1", + "vdin2", + "vdin3", + "vdin4", + "vdin5", + "vdin6", + "vdin7", + "vdout0", + "vdout1", + "vdout2", + "vdout3", + "vdout4", + "vdout5", + "vdout6", + "vdout7", + "vdout8", + "vdout9", + "vdout10", + "vdout11", + "vdout12", + "vdout13", + "vdout14", + "vdout15", + "vdout16", + "vdout17", + "vdout18", + "vdout19", + "vdout20", + "vdout21", + "vdout22", + "vdout23", + "v_hsync", + "v_vsync", + "vga_hsync", + "vga_vsync", + "vd_hsync", + "vd_vsync", + "nor_d0", + "nor_d1", + "nor_d2", + "nor_d3", + "nor_d4", + "nor_d5", + "nor_d6", + "nor_d7", + "nor_d8", + "nor_d9", + "nor_d10", + "nor_d11", + "nor_d12", + "nor_d13", + "nor_d14", + "nor_d15", + "nor_a0", + "nor_a1", + "nor_a2", + "nor_a3", + "nor_a4", + "nor_a5", + "nor_a6", + "nor_a7", + "nor_a8", + "nor_a9", + "nor_a10", + "nor_a11", + "nor_a12", + "nor_a13", + "nor_a14", + "nor_a15", + "nor_a16", + "nor_a17", + "nor_a18", + "nor_a19", + "nor_a20", + "nor_a21", + "nor_a22", + "nor_a23", + "nor_a24", + "ac97_sdi", + "ac97_sync", + "ac97_sdo", + "ac97_bclk", + "ac97_rst", + "sf_do", + "sf_cs0", + "sf_cs1", + "sf_clk", + "sf_di", + "spi0_clk", + "spi0_miso", + "spi0_mosi", + "spi0_ss", + "spi1_clk", + "spi1_miso", + "spi1_mosi", + "spi1_ss", + "spi2_clk", + "spi2_miso", + "spi2_mosi", + "spi2_ss", + "uart0_rts", + "uart0_txd", + "uart0_cts", + "uart0_rxd", + "uart1_rts", + "uart1_txd", + "uart1_cts", + "uart1_rxd", + "uart2_rts", + "uart2_txd", + "uart2_cts", + "uart2_rxd", + "uart3_rts", + "uart3_txd", + "uart3_cts", + "uart3_rxd", + "i2c0_scl", + "i2c0_sda", + "i2c1_scl", + "i2c1_sda", + "i2c2_scl", + "i2c2_sda", +}; + +static int wm8505_pinctrl_probe(struct platform_device *pdev) +{ + struct wmt_pinctrl_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "failed to allocate data\n"); + return -ENOMEM; + } + + data->banks = wm8505_banks; + data->nbanks = ARRAY_SIZE(wm8505_banks); + data->pins = wm8505_pins; + data->npins = ARRAY_SIZE(wm8505_pins); + data->groups = wm8505_groups; + data->ngroups = ARRAY_SIZE(wm8505_groups); + + return wmt_pinctrl_probe(pdev, data); +} + +static int wm8505_pinctrl_remove(struct platform_device *pdev) +{ + return wmt_pinctrl_remove(pdev); +} + +static struct of_device_id wmt_pinctrl_of_match[] = { + { .compatible = "wm,wm8505-pinctrl" }, + { /* sentinel */ }, +}; + +static struct platform_driver wmt_pinctrl_driver = { + .probe = wm8505_pinctrl_probe, + .remove = wm8505_pinctrl_remove, + .driver = { + .name = "pinctrl-wm8505", + .owner = THIS_MODULE, + .of_match_table = wmt_pinctrl_of_match, + }, +}; + +module_platform_driver(wmt_pinctrl_driver); + +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_DESCRIPTION("Wondermedia WM8505 Pincontrol driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match); diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8650.c b/drivers/pinctrl/vt8500/pinctrl-wm8650.c new file mode 100644 index 000000000000..7de57f063153 --- /dev/null +++ b/drivers/pinctrl/vt8500/pinctrl-wm8650.c @@ -0,0 +1,370 @@ +/* + * Pinctrl data for Wondermedia WM8650 SoC + * + * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> + * + * 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. + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "pinctrl-wmt.h" + +/* + * Describe the register offsets within the GPIO memory space + * The dedicated external GPIO's should always be listed in bank 0 + * so they are exported in the 0..31 range which is what users + * expect. + * + * Do not reorder these banks as it will change the pin numbering + */ +static const struct wmt_pinctrl_bank_registers wm8650_banks[] = { + WMT_PINCTRL_BANK(0x40, 0x80, 0xC0, 0x00, 0x480, 0x4C0), /* 0 */ + WMT_PINCTRL_BANK(0x44, 0x84, 0xC4, 0x04, 0x484, 0x4C4), /* 1 */ + WMT_PINCTRL_BANK(0x48, 0x88, 0xC8, 0x08, 0x488, 0x4C8), /* 2 */ + WMT_PINCTRL_BANK(0x4C, 0x8C, 0xCC, 0x0C, 0x48C, 0x4CC), /* 3 */ + WMT_PINCTRL_BANK(0x50, 0x90, 0xD0, 0x10, 0x490, 0x4D0), /* 4 */ + WMT_PINCTRL_BANK(0x54, 0x94, 0xD4, 0x14, 0x494, 0x4D4), /* 5 */ + WMT_PINCTRL_BANK(0x58, 0x98, 0xD8, 0x18, 0x498, 0x4D8), /* 6 */ + WMT_PINCTRL_BANK(0x5C, 0x9C, 0xDC, 0x1C, 0x49C, 0x4DC), /* 7 */ +}; + +/* Please keep sorted by bank/bit */ +#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0) +#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1) +#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2) +#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3) +#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4) +#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5) +#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6) +#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7) +#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16) +#define WMT_PIN_WAKEUP1 WMT_PIN(0, 17) +#define WMT_PIN_SUSGPIO0 WMT_PIN(0, 21) +#define WMT_PIN_SD0CD WMT_PIN(0, 28) +#define WMT_PIN_SD1CD WMT_PIN(0, 29) +#define WMT_PIN_VDOUT0 WMT_PIN(1, 0) +#define WMT_PIN_VDOUT1 WMT_PIN(1, 1) +#define WMT_PIN_VDOUT2 WMT_PIN(1, 2) +#define WMT_PIN_VDOUT3 WMT_PIN(1, 3) +#define WMT_PIN_VDOUT4 WMT_PIN(1, 4) +#define WMT_PIN_VDOUT5 WMT_PIN(1, 5) +#define WMT_PIN_VDOUT6 WMT_PIN(1, 6) +#define WMT_PIN_VDOUT7 WMT_PIN(1, 7) +#define WMT_PIN_VDOUT8 WMT_PIN(1, 8) +#define WMT_PIN_VDOUT9 WMT_PIN(1, 9) +#define WMT_PIN_VDOUT10 WMT_PIN(1, 10) +#define WMT_PIN_VDOUT11 WMT_PIN(1, 11) +#define WMT_PIN_VDOUT12 WMT_PIN(1, 12) +#define WMT_PIN_VDOUT13 WMT_PIN(1, 13) +#define WMT_PIN_VDOUT14 WMT_PIN(1, 14) +#define WMT_PIN_VDOUT15 WMT_PIN(1, 15) +#define WMT_PIN_VDOUT16 WMT_PIN(1, 16) +#define WMT_PIN_VDOUT17 WMT_PIN(1, 17) +#define WMT_PIN_VDOUT18 WMT_PIN(1, 18) +#define WMT_PIN_VDOUT19 WMT_PIN(1, 19) +#define WMT_PIN_VDOUT20 WMT_PIN(1, 20) +#define WMT_PIN_VDOUT21 WMT_PIN(1, 21) +#define WMT_PIN_VDOUT22 WMT_PIN(1, 22) +#define WMT_PIN_VDOUT23 WMT_PIN(1, 23) +#define WMT_PIN_VDIN0 WMT_PIN(2, 0) +#define WMT_PIN_VDIN1 WMT_PIN(2, 1) +#define WMT_PIN_VDIN2 WMT_PIN(2, 2) +#define WMT_PIN_VDIN3 WMT_PIN(2, 3) +#define WMT_PIN_VDIN4 WMT_PIN(2, 4) +#define WMT_PIN_VDIN5 WMT_PIN(2, 5) +#define WMT_PIN_VDIN6 WMT_PIN(2, 6) +#define WMT_PIN_VDIN7 WMT_PIN(2, 7) +#define WMT_PIN_I2C1SCL WMT_PIN(2, 12) +#define WMT_PIN_I2C1SDA WMT_PIN(2, 13) +#define WMT_PIN_SPI0MOSI WMT_PIN(2, 24) +#define WMT_PIN_SPI0MISO WMT_PIN(2, 25) +#define WMT_PIN_SPI0SS0 WMT_PIN(2, 26) +#define WMT_PIN_SPI0CLK WMT_PIN(2, 27) +#define WMT_PIN_SD0DATA0 WMT_PIN(3, 8) +#define WMT_PIN_SD0DATA1 WMT_PIN(3, 9) +#define WMT_PIN_SD0DATA2 WMT_PIN(3, 10) +#define WMT_PIN_SD0DATA3 WMT_PIN(3, 11) +#define WMT_PIN_SD0CLK WMT_PIN(3, 12) +#define WMT_PIN_SD0WP WMT_PIN(3, 13) +#define WMT_PIN_SD0CMD WMT_PIN(3, 14) +#define WMT_PIN_SD1DATA0 WMT_PIN(3, 24) +#define WMT_PIN_SD1DATA1 WMT_PIN(3, 25) +#define WMT_PIN_SD1DATA2 WMT_PIN(3, 26) +#define WMT_PIN_SD1DATA3 WMT_PIN(3, 27) +#define WMT_PIN_SD1DATA4 WMT_PIN(3, 28) +#define WMT_PIN_SD1DATA5 WMT_PIN(3, 29) +#define WMT_PIN_SD1DATA6 WMT_PIN(3, 30) +#define WMT_PIN_SD1DATA7 WMT_PIN(3, 31) +#define WMT_PIN_I2C0SCL WMT_PIN(5, 8) +#define WMT_PIN_I2C0SDA WMT_PIN(5, 9) +#define WMT_PIN_UART0RTS WMT_PIN(5, 16) +#define WMT_PIN_UART0TXD WMT_PIN(5, 17) +#define WMT_PIN_UART0CTS WMT_PIN(5, 18) +#define WMT_PIN_UART0RXD WMT_PIN(5, 19) +#define WMT_PIN_UART1RTS WMT_PIN(5, 20) +#define WMT_PIN_UART1TXD WMT_PIN(5, 21) +#define WMT_PIN_UART1CTS WMT_PIN(5, 22) +#define WMT_PIN_UART1RXD WMT_PIN(5, 23) +#define WMT_PIN_UART2RTS WMT_PIN(5, 24) +#define WMT_PIN_UART2TXD WMT_PIN(5, 25) +#define WMT_PIN_UART2CTS WMT_PIN(5, 26) +#define WMT_PIN_UART2RXD WMT_PIN(5, 27) +#define WMT_PIN_UART3RTS WMT_PIN(5, 28) +#define WMT_PIN_UART3TXD WMT_PIN(5, 29) +#define WMT_PIN_UART3CTS WMT_PIN(5, 30) +#define WMT_PIN_UART3RXD WMT_PIN(5, 31) +#define WMT_PIN_KPADROW0 WMT_PIN(6, 16) +#define WMT_PIN_KPADROW1 WMT_PIN(6, 17) +#define WMT_PIN_KPADCOL0 WMT_PIN(6, 18) +#define WMT_PIN_KPADCOL1 WMT_PIN(6, 19) +#define WMT_PIN_SD1CLK WMT_PIN(7, 0) +#define WMT_PIN_SD1CMD WMT_PIN(7, 1) +#define WMT_PIN_SD1WP WMT_PIN(7, 13) + +static const struct pinctrl_pin_desc wm8650_pins[] = { + PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"), + PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"), + PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"), + PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"), + PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"), + PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"), + PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"), + PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"), + PINCTRL_PIN(WMT_PIN_WAKEUP0, "wakeup0"), + PINCTRL_PIN(WMT_PIN_WAKEUP1, "wakeup1"), + PINCTRL_PIN(WMT_PIN_SUSGPIO0, "susgpio0"), + PINCTRL_PIN(WMT_PIN_SD0CD, "sd0_cd"), + PINCTRL_PIN(WMT_PIN_SD1CD, "sd1_cd"), + PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"), + PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"), + PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"), + PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"), + PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"), + PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"), + PINCTRL_PIN(WMT_PIN_VDOUT6, "vdout6"), + PINCTRL_PIN(WMT_PIN_VDOUT7, "vdout7"), + PINCTRL_PIN(WMT_PIN_VDOUT8, "vdout8"), + PINCTRL_PIN(WMT_PIN_VDOUT9, "vdout9"), + PINCTRL_PIN(WMT_PIN_VDOUT10, "vdout10"), + PINCTRL_PIN(WMT_PIN_VDOUT11, "vdout11"), + PINCTRL_PIN(WMT_PIN_VDOUT12, "vdout12"), + PINCTRL_PIN(WMT_PIN_VDOUT13, "vdout13"), + PINCTRL_PIN(WMT_PIN_VDOUT14, "vdout14"), + PINCTRL_PIN(WMT_PIN_VDOUT15, "vdout15"), + PINCTRL_PIN(WMT_PIN_VDOUT16, "vdout16"), + PINCTRL_PIN(WMT_PIN_VDOUT17, "vdout17"), + PINCTRL_PIN(WMT_PIN_VDOUT18, "vdout18"), + PINCTRL_PIN(WMT_PIN_VDOUT19, "vdout19"), + PINCTRL_PIN(WMT_PIN_VDOUT20, "vdout20"), + PINCTRL_PIN(WMT_PIN_VDOUT21, "vdout21"), + PINCTRL_PIN(WMT_PIN_VDOUT22, "vdout22"), + PINCTRL_PIN(WMT_PIN_VDOUT23, "vdout23"), + PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"), + PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"), + PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"), + PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"), + PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"), + PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"), + PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"), + PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"), + PINCTRL_PIN(WMT_PIN_I2C1SCL, "i2c1_scl"), + PINCTRL_PIN(WMT_PIN_I2C1SDA, "i2c1_sda"), + PINCTRL_PIN(WMT_PIN_SPI0MOSI, "spi0_mosi"), + PINCTRL_PIN(WMT_PIN_SPI0MISO, "spi0_miso"), + PINCTRL_PIN(WMT_PIN_SPI0SS0, "spi0_ss0"), + PINCTRL_PIN(WMT_PIN_SPI0CLK, "spi0_clk"), + PINCTRL_PIN(WMT_PIN_SD0DATA0, "sd0_data0"), + PINCTRL_PIN(WMT_PIN_SD0DATA1, "sd0_data1"), + PINCTRL_PIN(WMT_PIN_SD0DATA2, "sd0_data2"), + PINCTRL_PIN(WMT_PIN_SD0DATA3, "sd0_data3"), + PINCTRL_PIN(WMT_PIN_SD0CLK, "sd0_clk"), + PINCTRL_PIN(WMT_PIN_SD0WP, "sd0_wp"), + PINCTRL_PIN(WMT_PIN_SD0CMD, "sd0_cmd"), + PINCTRL_PIN(WMT_PIN_SD1DATA0, "sd1_data0"), + PINCTRL_PIN(WMT_PIN_SD1DATA1, "sd1_data1"), + PINCTRL_PIN(WMT_PIN_SD1DATA2, "sd1_data2"), + PINCTRL_PIN(WMT_PIN_SD1DATA3, "sd1_data3"), + PINCTRL_PIN(WMT_PIN_SD1DATA4, "sd1_data4"), + PINCTRL_PIN(WMT_PIN_SD1DATA5, "sd1_data5"), + PINCTRL_PIN(WMT_PIN_SD1DATA6, "sd1_data6"), + PINCTRL_PIN(WMT_PIN_SD1DATA7, "sd1_data7"), + PINCTRL_PIN(WMT_PIN_I2C0SCL, "i2c0_scl"), + PINCTRL_PIN(WMT_PIN_I2C0SDA, "i2c0_sda"), + PINCTRL_PIN(WMT_PIN_UART0RTS, "uart0_rts"), + PINCTRL_PIN(WMT_PIN_UART0TXD, "uart0_txd"), + PINCTRL_PIN(WMT_PIN_UART0CTS, "uart0_cts"), + PINCTRL_PIN(WMT_PIN_UART0RXD, "uart0_rxd"), + PINCTRL_PIN(WMT_PIN_UART1RTS, "uart1_rts"), + PINCTRL_PIN(WMT_PIN_UART1TXD, "uart1_txd"), + PINCTRL_PIN(WMT_PIN_UART1CTS, "uart1_cts"), + PINCTRL_PIN(WMT_PIN_UART1RXD, "uart1_rxd"), + PINCTRL_PIN(WMT_PIN_UART2RTS, "uart2_rts"), + PINCTRL_PIN(WMT_PIN_UART2TXD, "uart2_txd"), + PINCTRL_PIN(WMT_PIN_UART2CTS, "uart2_cts"), + PINCTRL_PIN(WMT_PIN_UART2RXD, "uart2_rxd"), + PINCTRL_PIN(WMT_PIN_UART3RTS, "uart3_rts"), + PINCTRL_PIN(WMT_PIN_UART3TXD, "uart3_txd"), + PINCTRL_PIN(WMT_PIN_UART3CTS, "uart3_cts"), + PINCTRL_PIN(WMT_PIN_UART3RXD, "uart3_rxd"), + PINCTRL_PIN(WMT_PIN_KPADROW0, "kpadrow0"), + PINCTRL_PIN(WMT_PIN_KPADROW1, "kpadrow1"), + PINCTRL_PIN(WMT_PIN_KPADCOL0, "kpadcol0"), + PINCTRL_PIN(WMT_PIN_KPADCOL1, "kpadcol1"), + PINCTRL_PIN(WMT_PIN_SD1CLK, "sd1_clk"), + PINCTRL_PIN(WMT_PIN_SD1CMD, "sd1_cmd"), + PINCTRL_PIN(WMT_PIN_SD1WP, "sd1_wp"), +}; + +/* Order of these names must match the above list */ +static const char * const wm8650_groups[] = { + "extgpio0", + "extgpio1", + "extgpio2", + "extgpio3", + "extgpio4", + "extgpio5", + "extgpio6", + "extgpio7", + "wakeup0", + "wakeup1", + "susgpio0", + "sd0_cd", + "sd1_cd", + "vdout0", + "vdout1", + "vdout2", + "vdout3", + "vdout4", + "vdout5", + "vdout6", + "vdout7", + "vdout8", + "vdout9", + "vdout10", + "vdout11", + "vdout12", + "vdout13", + "vdout14", + "vdout15", + "vdout16", + "vdout17", + "vdout18", + "vdout19", + "vdout20", + "vdout21", + "vdout22", + "vdout23", + "vdin0", + "vdin1", + "vdin2", + "vdin3", + "vdin4", + "vdin5", + "vdin6", + "vdin7", + "i2c1_scl", + "i2c1_sda", + "spi0_mosi", + "spi0_miso", + "spi0_ss0", + "spi0_clk", + "sd0_data0", + "sd0_data1", + "sd0_data2", + "sd0_data3", + "sd0_clk", + "sd0_wp", + "sd0_cmd", + "sd1_data0", + "sd1_data1", + "sd1_data2", + "sd1_data3", + "sd1_data4", + "sd1_data5", + "sd1_data6", + "sd1_data7", + "i2c0_scl", + "i2c0_sda", + "uart0_rts", + "uart0_txd", + "uart0_cts", + "uart0_rxd", + "uart1_rts", + "uart1_txd", + "uart1_cts", + "uart1_rxd", + "uart2_rts", + "uart2_txd", + "uart2_cts", + "uart2_rxd", + "uart3_rts", + "uart3_txd", + "uart3_cts", + "uart3_rxd", + "kpadrow0", + "kpadrow1", + "kpadcol0", + "kpadcol1", + "sd1_clk", + "sd1_cmd", + "sd1_wp", +}; + +static int wm8650_pinctrl_probe(struct platform_device *pdev) +{ + struct wmt_pinctrl_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "failed to allocate data\n"); + return -ENOMEM; + } + + data->banks = wm8650_banks; + data->nbanks = ARRAY_SIZE(wm8650_banks); + data->pins = wm8650_pins; + data->npins = ARRAY_SIZE(wm8650_pins); + data->groups = wm8650_groups; + data->ngroups = ARRAY_SIZE(wm8650_groups); + + return wmt_pinctrl_probe(pdev, data); +} + +static int wm8650_pinctrl_remove(struct platform_device *pdev) +{ + return wmt_pinctrl_remove(pdev); +} + +static struct of_device_id wmt_pinctrl_of_match[] = { + { .compatible = "wm,wm8650-pinctrl" }, + { /* sentinel */ }, +}; + +static struct platform_driver wmt_pinctrl_driver = { + .probe = wm8650_pinctrl_probe, + .remove = wm8650_pinctrl_remove, + .driver = { + .name = "pinctrl-wm8650", + .owner = THIS_MODULE, + .of_match_table = wmt_pinctrl_of_match, + }, +}; + +module_platform_driver(wmt_pinctrl_driver); + +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_DESCRIPTION("Wondermedia WM8650 Pincontrol driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match); diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8750.c b/drivers/pinctrl/vt8500/pinctrl-wm8750.c new file mode 100644 index 000000000000..b964cc550568 --- /dev/null +++ b/drivers/pinctrl/vt8500/pinctrl-wm8750.c @@ -0,0 +1,409 @@ +/* + * Pinctrl data for Wondermedia WM8750 SoC + * + * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> + * + * 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. + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "pinctrl-wmt.h" + +/* + * Describe the register offsets within the GPIO memory space + * The dedicated external GPIO's should always be listed in bank 0 + * so they are exported in the 0..31 range which is what users + * expect. + * + * Do not reorder these banks as it will change the pin numbering + */ +static const struct wmt_pinctrl_bank_registers wm8750_banks[] = { + WMT_PINCTRL_BANK(0x40, 0x80, 0xC0, 0x00, 0x480, 0x4C0), /* 0 */ + WMT_PINCTRL_BANK(0x44, 0x84, 0xC4, 0x04, 0x484, 0x4C4), /* 1 */ + WMT_PINCTRL_BANK(0x48, 0x88, 0xC8, 0x08, 0x488, 0x4C8), /* 2 */ + WMT_PINCTRL_BANK(0x4C, 0x8C, 0xCC, 0x0C, 0x48C, 0x4CC), /* 3 */ + WMT_PINCTRL_BANK(0x50, 0x90, 0xD0, 0x10, 0x490, 0x4D0), /* 4 */ + WMT_PINCTRL_BANK(0x54, 0x94, 0xD4, 0x14, 0x494, 0x4D4), /* 5 */ + WMT_PINCTRL_BANK(0x58, 0x98, 0xD8, 0x18, 0x498, 0x4D8), /* 6 */ + WMT_PINCTRL_BANK(0x5C, 0x9C, 0xDC, 0x1C, 0x49C, 0x4DC), /* 7 */ + WMT_PINCTRL_BANK(0x60, 0xA0, 0xE0, 0x20, 0x4A0, 0x4E0), /* 8 */ + WMT_PINCTRL_BANK(0x70, 0xB0, 0xF0, 0x30, 0x4B0, 0x4F0), /* 9 */ + WMT_PINCTRL_BANK(0x7C, 0xBC, 0xDC, 0x3C, 0x4BC, 0x4FC), /* 10 */ +}; + +/* Please keep sorted by bank/bit */ +#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0) +#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1) +#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2) +#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3) +#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4) +#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5) +#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6) +#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7) +#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16) +#define WMT_PIN_WAKEUP1 WMT_PIN(0, 16) +#define WMT_PIN_SD0CD WMT_PIN(0, 28) +#define WMT_PIN_VDOUT0 WMT_PIN(1, 0) +#define WMT_PIN_VDOUT1 WMT_PIN(1, 1) +#define WMT_PIN_VDOUT2 WMT_PIN(1, 2) +#define WMT_PIN_VDOUT3 WMT_PIN(1, 3) +#define WMT_PIN_VDOUT4 WMT_PIN(1, 4) +#define WMT_PIN_VDOUT5 WMT_PIN(1, 5) +#define WMT_PIN_VDOUT6 WMT_PIN(1, 6) +#define WMT_PIN_VDOUT7 WMT_PIN(1, 7) +#define WMT_PIN_VDOUT8 WMT_PIN(1, 8) +#define WMT_PIN_VDOUT9 WMT_PIN(1, 9) +#define WMT_PIN_VDOUT10 WMT_PIN(1, 10) +#define WMT_PIN_VDOUT11 WMT_PIN(1, 11) +#define WMT_PIN_VDOUT12 WMT_PIN(1, 12) +#define WMT_PIN_VDOUT13 WMT_PIN(1, 13) +#define WMT_PIN_VDOUT14 WMT_PIN(1, 14) +#define WMT_PIN_VDOUT15 WMT_PIN(1, 15) +#define WMT_PIN_VDOUT16 WMT_PIN(1, 16) +#define WMT_PIN_VDOUT17 WMT_PIN(1, 17) +#define WMT_PIN_VDOUT18 WMT_PIN(1, 18) +#define WMT_PIN_VDOUT19 WMT_PIN(1, 19) +#define WMT_PIN_VDOUT20 WMT_PIN(1, 20) +#define WMT_PIN_VDOUT21 WMT_PIN(1, 21) +#define WMT_PIN_VDOUT22 WMT_PIN(1, 22) +#define WMT_PIN_VDOUT23 WMT_PIN(1, 23) +#define WMT_PIN_VDIN0 WMT_PIN(2, 0) +#define WMT_PIN_VDIN1 WMT_PIN(2, 1) +#define WMT_PIN_VDIN2 WMT_PIN(2, 2) +#define WMT_PIN_VDIN3 WMT_PIN(2, 3) +#define WMT_PIN_VDIN4 WMT_PIN(2, 4) +#define WMT_PIN_VDIN5 WMT_PIN(2, 5) +#define WMT_PIN_VDIN6 WMT_PIN(2, 6) +#define WMT_PIN_VDIN7 WMT_PIN(2, 7) +#define WMT_PIN_SPI0_MOSI WMT_PIN(2, 24) +#define WMT_PIN_SPI0_MISO WMT_PIN(2, 25) +#define WMT_PIN_SPI0_SS WMT_PIN(2, 26) +#define WMT_PIN_SPI0_CLK WMT_PIN(2, 27) +#define WMT_PIN_SPI0_SSB WMT_PIN(2, 28) +#define WMT_PIN_SD0CLK WMT_PIN(3, 17) +#define WMT_PIN_SD0CMD WMT_PIN(3, 18) +#define WMT_PIN_SD0WP WMT_PIN(3, 19) +#define WMT_PIN_SD0DATA0 WMT_PIN(3, 20) +#define WMT_PIN_SD0DATA1 WMT_PIN(3, 21) +#define WMT_PIN_SD0DATA2 WMT_PIN(3, 22) +#define WMT_PIN_SD0DATA3 WMT_PIN(3, 23) +#define WMT_PIN_SD1DATA0 WMT_PIN(3, 24) +#define WMT_PIN_SD1DATA1 WMT_PIN(3, 25) +#define WMT_PIN_SD1DATA2 WMT_PIN(3, 26) +#define WMT_PIN_SD1DATA3 WMT_PIN(3, 27) +#define WMT_PIN_SD1DATA4 WMT_PIN(3, 28) +#define WMT_PIN_SD1DATA5 WMT_PIN(3, 29) +#define WMT_PIN_SD1DATA6 WMT_PIN(3, 30) +#define WMT_PIN_SD1DATA7 WMT_PIN(3, 31) +#define WMT_PIN_I2C0_SCL WMT_PIN(5, 8) +#define WMT_PIN_I2C0_SDA WMT_PIN(5, 9) +#define WMT_PIN_I2C1_SCL WMT_PIN(5, 10) +#define WMT_PIN_I2C1_SDA WMT_PIN(5, 11) +#define WMT_PIN_I2C2_SCL WMT_PIN(5, 12) +#define WMT_PIN_I2C2_SDA WMT_PIN(5, 13) +#define WMT_PIN_UART0_RTS WMT_PIN(5, 16) +#define WMT_PIN_UART0_TXD WMT_PIN(5, 17) +#define WMT_PIN_UART0_CTS WMT_PIN(5, 18) +#define WMT_PIN_UART0_RXD WMT_PIN(5, 19) +#define WMT_PIN_UART1_RTS WMT_PIN(5, 20) +#define WMT_PIN_UART1_TXD WMT_PIN(5, 21) +#define WMT_PIN_UART1_CTS WMT_PIN(5, 22) +#define WMT_PIN_UART1_RXD WMT_PIN(5, 23) +#define WMT_PIN_UART2_RTS WMT_PIN(5, 24) +#define WMT_PIN_UART2_TXD WMT_PIN(5, 25) +#define WMT_PIN_UART2_CTS WMT_PIN(5, 26) +#define WMT_PIN_UART2_RXD WMT_PIN(5, 27) +#define WMT_PIN_UART3_RTS WMT_PIN(5, 28) +#define WMT_PIN_UART3_TXD WMT_PIN(5, 29) +#define WMT_PIN_UART3_CTS WMT_PIN(5, 30) +#define WMT_PIN_UART3_RXD WMT_PIN(5, 31) +#define WMT_PIN_SD2CD WMT_PIN(6, 0) +#define WMT_PIN_SD2DATA3 WMT_PIN(6, 1) +#define WMT_PIN_SD2DATA0 WMT_PIN(6, 2) +#define WMT_PIN_SD2WP WMT_PIN(6, 3) +#define WMT_PIN_SD2DATA1 WMT_PIN(6, 4) +#define WMT_PIN_SD2DATA2 WMT_PIN(6, 5) +#define WMT_PIN_SD2CMD WMT_PIN(6, 6) +#define WMT_PIN_SD2CLK WMT_PIN(6, 7) +#define WMT_PIN_SD2PWR WMT_PIN(6, 9) +#define WMT_PIN_SD1CLK WMT_PIN(7, 0) +#define WMT_PIN_SD1CMD WMT_PIN(7, 1) +#define WMT_PIN_SD1PWR WMT_PIN(7, 10) +#define WMT_PIN_SD1WP WMT_PIN(7, 11) +#define WMT_PIN_SD1CD WMT_PIN(7, 12) +#define WMT_PIN_SPI0SS3 WMT_PIN(7, 24) +#define WMT_PIN_SPI0SS2 WMT_PIN(7, 25) +#define WMT_PIN_PWMOUT1 WMT_PIN(7, 26) +#define WMT_PIN_PWMOUT0 WMT_PIN(7, 27) + +static const struct pinctrl_pin_desc wm8750_pins[] = { + PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"), + PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"), + PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"), + PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"), + PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"), + PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"), + PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"), + PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"), + PINCTRL_PIN(WMT_PIN_WAKEUP0, "wakeup0"), + PINCTRL_PIN(WMT_PIN_WAKEUP1, "wakeup1"), + PINCTRL_PIN(WMT_PIN_SD0CD, "sd0_cd"), + PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"), + PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"), + PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"), + PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"), + PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"), + PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"), + PINCTRL_PIN(WMT_PIN_VDOUT6, "vdout6"), + PINCTRL_PIN(WMT_PIN_VDOUT7, "vdout7"), + PINCTRL_PIN(WMT_PIN_VDOUT8, "vdout8"), + PINCTRL_PIN(WMT_PIN_VDOUT9, "vdout9"), + PINCTRL_PIN(WMT_PIN_VDOUT10, "vdout10"), + PINCTRL_PIN(WMT_PIN_VDOUT11, "vdout11"), + PINCTRL_PIN(WMT_PIN_VDOUT12, "vdout12"), + PINCTRL_PIN(WMT_PIN_VDOUT13, "vdout13"), + PINCTRL_PIN(WMT_PIN_VDOUT14, "vdout14"), + PINCTRL_PIN(WMT_PIN_VDOUT15, "vdout15"), + PINCTRL_PIN(WMT_PIN_VDOUT16, "vdout16"), + PINCTRL_PIN(WMT_PIN_VDOUT17, "vdout17"), + PINCTRL_PIN(WMT_PIN_VDOUT18, "vdout18"), + PINCTRL_PIN(WMT_PIN_VDOUT19, "vdout19"), + PINCTRL_PIN(WMT_PIN_VDOUT20, "vdout20"), + PINCTRL_PIN(WMT_PIN_VDOUT21, "vdout21"), + PINCTRL_PIN(WMT_PIN_VDOUT22, "vdout22"), + PINCTRL_PIN(WMT_PIN_VDOUT23, "vdout23"), + PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"), + PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"), + PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"), + PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"), + PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"), + PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"), + PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"), + PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"), + PINCTRL_PIN(WMT_PIN_SPI0_MOSI, "spi0_mosi"), + PINCTRL_PIN(WMT_PIN_SPI0_MISO, "spi0_miso"), + PINCTRL_PIN(WMT_PIN_SPI0_SS, "spi0_ss"), + PINCTRL_PIN(WMT_PIN_SPI0_CLK, "spi0_clk"), + PINCTRL_PIN(WMT_PIN_SPI0_SSB, "spi0_ssb"), + PINCTRL_PIN(WMT_PIN_SD0CLK, "sd0_clk"), + PINCTRL_PIN(WMT_PIN_SD0CMD, "sd0_cmd"), + PINCTRL_PIN(WMT_PIN_SD0WP, "sd0_wp"), + PINCTRL_PIN(WMT_PIN_SD0DATA0, "sd0_data0"), + PINCTRL_PIN(WMT_PIN_SD0DATA1, "sd0_data1"), + PINCTRL_PIN(WMT_PIN_SD0DATA2, "sd0_data2"), + PINCTRL_PIN(WMT_PIN_SD0DATA3, "sd0_data3"), + PINCTRL_PIN(WMT_PIN_SD1DATA0, "sd1_data0"), + PINCTRL_PIN(WMT_PIN_SD1DATA1, "sd1_data1"), + PINCTRL_PIN(WMT_PIN_SD1DATA2, "sd1_data2"), + PINCTRL_PIN(WMT_PIN_SD1DATA3, "sd1_data3"), + PINCTRL_PIN(WMT_PIN_SD1DATA4, "sd1_data4"), + PINCTRL_PIN(WMT_PIN_SD1DATA5, "sd1_data5"), + PINCTRL_PIN(WMT_PIN_SD1DATA6, "sd1_data6"), + PINCTRL_PIN(WMT_PIN_SD1DATA7, "sd1_data7"), + PINCTRL_PIN(WMT_PIN_I2C0_SCL, "i2c0_scl"), + PINCTRL_PIN(WMT_PIN_I2C0_SDA, "i2c0_sda"), + PINCTRL_PIN(WMT_PIN_I2C1_SCL, "i2c1_scl"), + PINCTRL_PIN(WMT_PIN_I2C1_SDA, "i2c1_sda"), + PINCTRL_PIN(WMT_PIN_I2C2_SCL, "i2c2_scl"), + PINCTRL_PIN(WMT_PIN_I2C2_SDA, "i2c2_sda"), + PINCTRL_PIN(WMT_PIN_UART0_RTS, "uart0_rts"), + PINCTRL_PIN(WMT_PIN_UART0_TXD, "uart0_txd"), + PINCTRL_PIN(WMT_PIN_UART0_CTS, "uart0_cts"), + PINCTRL_PIN(WMT_PIN_UART0_RXD, "uart0_rxd"), + PINCTRL_PIN(WMT_PIN_UART1_RTS, "uart1_rts"), + PINCTRL_PIN(WMT_PIN_UART1_TXD, "uart1_txd"), + PINCTRL_PIN(WMT_PIN_UART1_CTS, "uart1_cts"), + PINCTRL_PIN(WMT_PIN_UART1_RXD, "uart1_rxd"), + PINCTRL_PIN(WMT_PIN_UART2_RTS, "uart2_rts"), + PINCTRL_PIN(WMT_PIN_UART2_TXD, "uart2_txd"), + PINCTRL_PIN(WMT_PIN_UART2_CTS, "uart2_cts"), + PINCTRL_PIN(WMT_PIN_UART2_RXD, "uart2_rxd"), + PINCTRL_PIN(WMT_PIN_UART3_RTS, "uart3_rts"), + PINCTRL_PIN(WMT_PIN_UART3_TXD, "uart3_txd"), + PINCTRL_PIN(WMT_PIN_UART3_CTS, "uart3_cts"), + PINCTRL_PIN(WMT_PIN_UART3_RXD, "uart3_rxd"), + PINCTRL_PIN(WMT_PIN_SD2CD, "sd2_cd"), + PINCTRL_PIN(WMT_PIN_SD2DATA3, "sd2_data3"), + PINCTRL_PIN(WMT_PIN_SD2DATA0, "sd2_data0"), + PINCTRL_PIN(WMT_PIN_SD2WP, "sd2_wp"), + PINCTRL_PIN(WMT_PIN_SD2DATA1, "sd2_data1"), + PINCTRL_PIN(WMT_PIN_SD2DATA2, "sd2_data2"), + PINCTRL_PIN(WMT_PIN_SD2CMD, "sd2_cmd"), + PINCTRL_PIN(WMT_PIN_SD2CLK, "sd2_clk"), + PINCTRL_PIN(WMT_PIN_SD2PWR, "sd2_pwr"), + PINCTRL_PIN(WMT_PIN_SD1CLK, "sd1_clk"), + PINCTRL_PIN(WMT_PIN_SD1CMD, "sd1_cmd"), + PINCTRL_PIN(WMT_PIN_SD1PWR, "sd1_pwr"), + PINCTRL_PIN(WMT_PIN_SD1WP, "sd1_wp"), + PINCTRL_PIN(WMT_PIN_SD1CD, "sd1_cd"), + PINCTRL_PIN(WMT_PIN_SPI0SS3, "spi0_ss3"), + PINCTRL_PIN(WMT_PIN_SPI0SS2, "spi0_ss2"), + PINCTRL_PIN(WMT_PIN_PWMOUT1, "pwmout1"), + PINCTRL_PIN(WMT_PIN_PWMOUT0, "pwmout0"), +}; + +/* Order of these names must match the above list */ +static const char * const wm8750_groups[] = { + "extgpio0", + "extgpio1", + "extgpio2", + "extgpio3", + "extgpio4", + "extgpio5", + "extgpio6", + "extgpio7", + "wakeup0", + "wakeup1", + "sd0_cd", + "vdout0", + "vdout1", + "vdout2", + "vdout3", + "vdout4", + "vdout5", + "vdout6", + "vdout7", + "vdout8", + "vdout9", + "vdout10", + "vdout11", + "vdout12", + "vdout13", + "vdout14", + "vdout15", + "vdout16", + "vdout17", + "vdout18", + "vdout19", + "vdout20", + "vdout21", + "vdout22", + "vdout23", + "vdin0", + "vdin1", + "vdin2", + "vdin3", + "vdin4", + "vdin5", + "vdin6", + "vdin7", + "spi0_mosi", + "spi0_miso", + "spi0_ss", + "spi0_clk", + "spi0_ssb", + "sd0_clk", + "sd0_cmd", + "sd0_wp", + "sd0_data0", + "sd0_data1", + "sd0_data2", + "sd0_data3", + "sd1_data0", + "sd1_data1", + "sd1_data2", + "sd1_data3", + "sd1_data4", + "sd1_data5", + "sd1_data6", + "sd1_data7", + "i2c0_scl", + "i2c0_sda", + "i2c1_scl", + "i2c1_sda", + "i2c2_scl", + "i2c2_sda", + "uart0_rts", + "uart0_txd", + "uart0_cts", + "uart0_rxd", + "uart1_rts", + "uart1_txd", + "uart1_cts", + "uart1_rxd", + "uart2_rts", + "uart2_txd", + "uart2_cts", + "uart2_rxd", + "uart3_rts", + "uart3_txd", + "uart3_cts", + "uart3_rxd", + "sd2_cd", + "sd2_data3", + "sd2_data0", + "sd2_wp", + "sd2_data1", + "sd2_data2", + "sd2_cmd", + "sd2_clk", + "sd2_pwr", + "sd1_clk", + "sd1_cmd", + "sd1_pwr", + "sd1_wp", + "sd1_cd", + "spi0_ss3", + "spi0_ss2", + "pwmout1", + "pwmout0", +}; + +static int wm8750_pinctrl_probe(struct platform_device *pdev) +{ + struct wmt_pinctrl_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "failed to allocate data\n"); + return -ENOMEM; + } + + data->banks = wm8750_banks; + data->nbanks = ARRAY_SIZE(wm8750_banks); + data->pins = wm8750_pins; + data->npins = ARRAY_SIZE(wm8750_pins); + data->groups = wm8750_groups; + data->ngroups = ARRAY_SIZE(wm8750_groups); + + return wmt_pinctrl_probe(pdev, data); +} + +static int wm8750_pinctrl_remove(struct platform_device *pdev) +{ + return wmt_pinctrl_remove(pdev); +} + +static struct of_device_id wmt_pinctrl_of_match[] = { + { .compatible = "wm,wm8750-pinctrl" }, + { /* sentinel */ }, +}; + +static struct platform_driver wmt_pinctrl_driver = { + .probe = wm8750_pinctrl_probe, + .remove = wm8750_pinctrl_remove, + .driver = { + .name = "pinctrl-wm8750", + .owner = THIS_MODULE, + .of_match_table = wmt_pinctrl_of_match, + }, +}; + +module_platform_driver(wmt_pinctrl_driver); + +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_DESCRIPTION("Wondermedia WM8750 Pincontrol driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match); diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8850.c b/drivers/pinctrl/vt8500/pinctrl-wm8850.c new file mode 100644 index 000000000000..ecadce9c91d5 --- /dev/null +++ b/drivers/pinctrl/vt8500/pinctrl-wm8850.c @@ -0,0 +1,388 @@ +/* + * Pinctrl data for Wondermedia WM8850 SoC + * + * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> + * + * 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. + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "pinctrl-wmt.h" + +/* + * Describe the register offsets within the GPIO memory space + * The dedicated external GPIO's should always be listed in bank 0 + * so they are exported in the 0..31 range which is what users + * expect. + * + * Do not reorder these banks as it will change the pin numbering + */ +static const struct wmt_pinctrl_bank_registers wm8850_banks[] = { + WMT_PINCTRL_BANK(0x40, 0x80, 0xC0, 0x00, 0x480, 0x4C0), /* 0 */ + WMT_PINCTRL_BANK(0x44, 0x84, 0xC4, 0x04, 0x484, 0x4C4), /* 1 */ + WMT_PINCTRL_BANK(0x48, 0x88, 0xC8, 0x08, 0x488, 0x4C8), /* 2 */ + WMT_PINCTRL_BANK(0x4C, 0x8C, 0xCC, 0x0C, 0x48C, 0x4CC), /* 3 */ + WMT_PINCTRL_BANK(0x50, 0x90, 0xD0, 0x10, 0x490, 0x4D0), /* 4 */ + WMT_PINCTRL_BANK(0x54, 0x94, 0xD4, 0x14, 0x494, 0x4D4), /* 5 */ + WMT_PINCTRL_BANK(0x58, 0x98, 0xD8, 0x18, 0x498, 0x4D8), /* 6 */ + WMT_PINCTRL_BANK(0x5C, 0x9C, 0xDC, 0x1C, 0x49C, 0x4DC), /* 7 */ + WMT_PINCTRL_BANK(0x60, 0xA0, 0xE0, 0x20, 0x4A0, 0x4E0), /* 8 */ + WMT_PINCTRL_BANK(0x70, 0xB0, 0xF0, 0x30, 0x4B0, 0x4F0), /* 9 */ + WMT_PINCTRL_BANK(0x7C, 0xBC, 0xDC, 0x3C, 0x4BC, 0x4FC), /* 10 */ +}; + +/* Please keep sorted by bank/bit */ +#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0) +#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1) +#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2) +#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3) +#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4) +#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5) +#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6) +#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7) +#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16) +#define WMT_PIN_WAKEUP1 WMT_PIN(0, 17) +#define WMT_PIN_WAKEUP2 WMT_PIN(0, 18) +#define WMT_PIN_WAKEUP3 WMT_PIN(0, 19) +#define WMT_PIN_SUSGPIO0 WMT_PIN(0, 21) +#define WMT_PIN_SUSGPIO1 WMT_PIN(0, 22) +#define WMT_PIN_SD0CD WMT_PIN(0, 28) +#define WMT_PIN_VDOUT0 WMT_PIN(1, 0) +#define WMT_PIN_VDOUT1 WMT_PIN(1, 1) +#define WMT_PIN_VDOUT2 WMT_PIN(1, 2) +#define WMT_PIN_VDOUT3 WMT_PIN(1, 3) +#define WMT_PIN_VDOUT4 WMT_PIN(1, 4) +#define WMT_PIN_VDOUT5 WMT_PIN(1, 5) +#define WMT_PIN_VDOUT6 WMT_PIN(1, 6) +#define WMT_PIN_VDOUT7 WMT_PIN(1, 7) +#define WMT_PIN_VDOUT8 WMT_PIN(1, 8) +#define WMT_PIN_VDOUT9 WMT_PIN(1, 9) +#define WMT_PIN_VDOUT10 WMT_PIN(1, 10) +#define WMT_PIN_VDOUT11 WMT_PIN(1, 11) +#define WMT_PIN_VDOUT12 WMT_PIN(1, 12) +#define WMT_PIN_VDOUT13 WMT_PIN(1, 13) +#define WMT_PIN_VDOUT14 WMT_PIN(1, 14) +#define WMT_PIN_VDOUT15 WMT_PIN(1, 15) +#define WMT_PIN_VDOUT16 WMT_PIN(1, 16) +#define WMT_PIN_VDOUT17 WMT_PIN(1, 17) +#define WMT_PIN_VDOUT18 WMT_PIN(1, 18) +#define WMT_PIN_VDOUT19 WMT_PIN(1, 19) +#define WMT_PIN_VDOUT20 WMT_PIN(1, 20) +#define WMT_PIN_VDOUT21 WMT_PIN(1, 21) +#define WMT_PIN_VDOUT22 WMT_PIN(1, 22) +#define WMT_PIN_VDOUT23 WMT_PIN(1, 23) +#define WMT_PIN_VDIN0 WMT_PIN(2, 0) +#define WMT_PIN_VDIN1 WMT_PIN(2, 1) +#define WMT_PIN_VDIN2 WMT_PIN(2, 2) +#define WMT_PIN_VDIN3 WMT_PIN(2, 3) +#define WMT_PIN_VDIN4 WMT_PIN(2, 4) +#define WMT_PIN_VDIN5 WMT_PIN(2, 5) +#define WMT_PIN_VDIN6 WMT_PIN(2, 6) +#define WMT_PIN_VDIN7 WMT_PIN(2, 7) +#define WMT_PIN_SPI0_MOSI WMT_PIN(2, 24) +#define WMT_PIN_SPI0_MISO WMT_PIN(2, 25) +#define WMT_PIN_SPI0_SS WMT_PIN(2, 26) +#define WMT_PIN_SPI0_CLK WMT_PIN(2, 27) +#define WMT_PIN_SPI0_SSB WMT_PIN(2, 28) +#define WMT_PIN_SD0CLK WMT_PIN(3, 17) +#define WMT_PIN_SD0CMD WMT_PIN(3, 18) +#define WMT_PIN_SD0WP WMT_PIN(3, 19) +#define WMT_PIN_SD0DATA0 WMT_PIN(3, 20) +#define WMT_PIN_SD0DATA1 WMT_PIN(3, 21) +#define WMT_PIN_SD0DATA2 WMT_PIN(3, 22) +#define WMT_PIN_SD0DATA3 WMT_PIN(3, 23) +#define WMT_PIN_SD1DATA0 WMT_PIN(3, 24) +#define WMT_PIN_SD1DATA1 WMT_PIN(3, 25) +#define WMT_PIN_SD1DATA2 WMT_PIN(3, 26) +#define WMT_PIN_SD1DATA3 WMT_PIN(3, 27) +#define WMT_PIN_SD1DATA4 WMT_PIN(3, 28) +#define WMT_PIN_SD1DATA5 WMT_PIN(3, 29) +#define WMT_PIN_SD1DATA6 WMT_PIN(3, 30) +#define WMT_PIN_SD1DATA7 WMT_PIN(3, 31) +#define WMT_PIN_I2C0_SCL WMT_PIN(5, 8) +#define WMT_PIN_I2C0_SDA WMT_PIN(5, 9) +#define WMT_PIN_I2C1_SCL WMT_PIN(5, 10) +#define WMT_PIN_I2C1_SDA WMT_PIN(5, 11) +#define WMT_PIN_I2C2_SCL WMT_PIN(5, 12) +#define WMT_PIN_I2C2_SDA WMT_PIN(5, 13) +#define WMT_PIN_UART0_RTS WMT_PIN(5, 16) +#define WMT_PIN_UART0_TXD WMT_PIN(5, 17) +#define WMT_PIN_UART0_CTS WMT_PIN(5, 18) +#define WMT_PIN_UART0_RXD WMT_PIN(5, 19) +#define WMT_PIN_UART1_RTS WMT_PIN(5, 20) +#define WMT_PIN_UART1_TXD WMT_PIN(5, 21) +#define WMT_PIN_UART1_CTS WMT_PIN(5, 22) +#define WMT_PIN_UART1_RXD WMT_PIN(5, 23) +#define WMT_PIN_UART2_RTS WMT_PIN(5, 24) +#define WMT_PIN_UART2_TXD WMT_PIN(5, 25) +#define WMT_PIN_UART2_CTS WMT_PIN(5, 26) +#define WMT_PIN_UART2_RXD WMT_PIN(5, 27) +#define WMT_PIN_SD2WP WMT_PIN(6, 3) +#define WMT_PIN_SD2CMD WMT_PIN(6, 6) +#define WMT_PIN_SD2CLK WMT_PIN(6, 7) +#define WMT_PIN_SD2PWR WMT_PIN(6, 9) +#define WMT_PIN_SD1CLK WMT_PIN(7, 0) +#define WMT_PIN_SD1CMD WMT_PIN(7, 1) +#define WMT_PIN_SD1PWR WMT_PIN(7, 10) +#define WMT_PIN_SD1WP WMT_PIN(7, 11) +#define WMT_PIN_SD1CD WMT_PIN(7, 12) +#define WMT_PIN_PWMOUT1 WMT_PIN(7, 26) +#define WMT_PIN_PWMOUT0 WMT_PIN(7, 27) + +static const struct pinctrl_pin_desc wm8850_pins[] = { + PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"), + PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"), + PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"), + PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"), + PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"), + PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"), + PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"), + PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"), + PINCTRL_PIN(WMT_PIN_WAKEUP0, "wakeup0"), + PINCTRL_PIN(WMT_PIN_WAKEUP1, "wakeup1"), + PINCTRL_PIN(WMT_PIN_WAKEUP2, "wakeup2"), + PINCTRL_PIN(WMT_PIN_WAKEUP3, "wakeup3"), + PINCTRL_PIN(WMT_PIN_SUSGPIO0, "susgpio0"), + PINCTRL_PIN(WMT_PIN_SUSGPIO1, "susgpio1"), + PINCTRL_PIN(WMT_PIN_SD0CD, "sd0_cd"), + PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"), + PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"), + PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"), + PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"), + PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"), + PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"), + PINCTRL_PIN(WMT_PIN_VDOUT6, "vdout6"), + PINCTRL_PIN(WMT_PIN_VDOUT7, "vdout7"), + PINCTRL_PIN(WMT_PIN_VDOUT8, "vdout8"), + PINCTRL_PIN(WMT_PIN_VDOUT9, "vdout9"), + PINCTRL_PIN(WMT_PIN_VDOUT10, "vdout10"), + PINCTRL_PIN(WMT_PIN_VDOUT11, "vdout11"), + PINCTRL_PIN(WMT_PIN_VDOUT12, "vdout12"), + PINCTRL_PIN(WMT_PIN_VDOUT13, "vdout13"), + PINCTRL_PIN(WMT_PIN_VDOUT14, "vdout14"), + PINCTRL_PIN(WMT_PIN_VDOUT15, "vdout15"), + PINCTRL_PIN(WMT_PIN_VDOUT16, "vdout16"), + PINCTRL_PIN(WMT_PIN_VDOUT17, "vdout17"), + PINCTRL_PIN(WMT_PIN_VDOUT18, "vdout18"), + PINCTRL_PIN(WMT_PIN_VDOUT19, "vdout19"), + PINCTRL_PIN(WMT_PIN_VDOUT20, "vdout20"), + PINCTRL_PIN(WMT_PIN_VDOUT21, "vdout21"), + PINCTRL_PIN(WMT_PIN_VDOUT22, "vdout22"), + PINCTRL_PIN(WMT_PIN_VDOUT23, "vdout23"), + PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"), + PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"), + PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"), + PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"), + PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"), + PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"), + PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"), + PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"), + PINCTRL_PIN(WMT_PIN_SPI0_MOSI, "spi0_mosi"), + PINCTRL_PIN(WMT_PIN_SPI0_MISO, "spi0_miso"), + PINCTRL_PIN(WMT_PIN_SPI0_SS, "spi0_ss"), + PINCTRL_PIN(WMT_PIN_SPI0_CLK, "spi0_clk"), + PINCTRL_PIN(WMT_PIN_SPI0_SSB, "spi0_ssb"), + PINCTRL_PIN(WMT_PIN_SD0CLK, "sd0_clk"), + PINCTRL_PIN(WMT_PIN_SD0CMD, "sd0_cmd"), + PINCTRL_PIN(WMT_PIN_SD0WP, "sd0_wp"), + PINCTRL_PIN(WMT_PIN_SD0DATA0, "sd0_data0"), + PINCTRL_PIN(WMT_PIN_SD0DATA1, "sd0_data1"), + PINCTRL_PIN(WMT_PIN_SD0DATA2, "sd0_data2"), + PINCTRL_PIN(WMT_PIN_SD0DATA3, "sd0_data3"), + PINCTRL_PIN(WMT_PIN_SD1DATA0, "sd1_data0"), + PINCTRL_PIN(WMT_PIN_SD1DATA1, "sd1_data1"), + PINCTRL_PIN(WMT_PIN_SD1DATA2, "sd1_data2"), + PINCTRL_PIN(WMT_PIN_SD1DATA3, "sd1_data3"), + PINCTRL_PIN(WMT_PIN_SD1DATA4, "sd1_data4"), + PINCTRL_PIN(WMT_PIN_SD1DATA5, "sd1_data5"), + PINCTRL_PIN(WMT_PIN_SD1DATA6, "sd1_data6"), + PINCTRL_PIN(WMT_PIN_SD1DATA7, "sd1_data7"), + PINCTRL_PIN(WMT_PIN_I2C0_SCL, "i2c0_scl"), + PINCTRL_PIN(WMT_PIN_I2C0_SDA, "i2c0_sda"), + PINCTRL_PIN(WMT_PIN_I2C1_SCL, "i2c1_scl"), + PINCTRL_PIN(WMT_PIN_I2C1_SDA, "i2c1_sda"), + PINCTRL_PIN(WMT_PIN_I2C2_SCL, "i2c2_scl"), + PINCTRL_PIN(WMT_PIN_I2C2_SDA, "i2c2_sda"), + PINCTRL_PIN(WMT_PIN_UART0_RTS, "uart0_rts"), + PINCTRL_PIN(WMT_PIN_UART0_TXD, "uart0_txd"), + PINCTRL_PIN(WMT_PIN_UART0_CTS, "uart0_cts"), + PINCTRL_PIN(WMT_PIN_UART0_RXD, "uart0_rxd"), + PINCTRL_PIN(WMT_PIN_UART1_RTS, "uart1_rts"), + PINCTRL_PIN(WMT_PIN_UART1_TXD, "uart1_txd"), + PINCTRL_PIN(WMT_PIN_UART1_CTS, "uart1_cts"), + PINCTRL_PIN(WMT_PIN_UART1_RXD, "uart1_rxd"), + PINCTRL_PIN(WMT_PIN_UART2_RTS, "uart2_rts"), + PINCTRL_PIN(WMT_PIN_UART2_TXD, "uart2_txd"), + PINCTRL_PIN(WMT_PIN_UART2_CTS, "uart2_cts"), + PINCTRL_PIN(WMT_PIN_UART2_RXD, "uart2_rxd"), + PINCTRL_PIN(WMT_PIN_SD2WP, "sd2_wp"), + PINCTRL_PIN(WMT_PIN_SD2CMD, "sd2_cmd"), + PINCTRL_PIN(WMT_PIN_SD2CLK, "sd2_clk"), + PINCTRL_PIN(WMT_PIN_SD2PWR, "sd2_pwr"), + PINCTRL_PIN(WMT_PIN_SD1CLK, "sd1_clk"), + PINCTRL_PIN(WMT_PIN_SD1CMD, "sd1_cmd"), + PINCTRL_PIN(WMT_PIN_SD1PWR, "sd1_pwr"), + PINCTRL_PIN(WMT_PIN_SD1WP, "sd1_wp"), + PINCTRL_PIN(WMT_PIN_SD1CD, "sd1_cd"), + PINCTRL_PIN(WMT_PIN_PWMOUT1, "pwmout1"), + PINCTRL_PIN(WMT_PIN_PWMOUT0, "pwmout0"), +}; + +/* Order of these names must match the above list */ +static const char * const wm8850_groups[] = { + "extgpio0", + "extgpio1", + "extgpio2", + "extgpio3", + "extgpio4", + "extgpio5", + "extgpio6", + "extgpio7", + "wakeup0", + "wakeup1", + "wakeup2", + "wakeup3", + "susgpio0", + "susgpio1", + "sd0_cd", + "vdout0", + "vdout1", + "vdout2", + "vdout3", + "vdout4", + "vdout5", + "vdout6", + "vdout7", + "vdout8", + "vdout9", + "vdout10", + "vdout11", + "vdout12", + "vdout13", + "vdout14", + "vdout15", + "vdout16", + "vdout17", + "vdout18", + "vdout19", + "vdout20", + "vdout21", + "vdout22", + "vdout23", + "vdin0", + "vdin1", + "vdin2", + "vdin3", + "vdin4", + "vdin5", + "vdin6", + "vdin7", + "spi0_mosi", + "spi0_miso", + "spi0_ss", + "spi0_clk", + "spi0_ssb", + "sd0_clk", + "sd0_cmd", + "sd0_wp", + "sd0_data0", + "sd0_data1", + "sd0_data2", + "sd0_data3", + "sd1_data0", + "sd1_data1", + "sd1_data2", + "sd1_data3", + "sd1_data4", + "sd1_data5", + "sd1_data6", + "sd1_data7", + "i2c0_scl", + "i2c0_sda", + "i2c1_scl", + "i2c1_sda", + "i2c2_scl", + "i2c2_sda", + "uart0_rts", + "uart0_txd", + "uart0_cts", + "uart0_rxd", + "uart1_rts", + "uart1_txd", + "uart1_cts", + "uart1_rxd", + "uart2_rts", + "uart2_txd", + "uart2_cts", + "uart2_rxd", + "sd2_wp", + "sd2_cmd", + "sd2_clk", + "sd2_pwr", + "sd1_clk", + "sd1_cmd", + "sd1_pwr", + "sd1_wp", + "sd1_cd", + "pwmout1", + "pwmout0", +}; + +static int wm8850_pinctrl_probe(struct platform_device *pdev) +{ + struct wmt_pinctrl_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "failed to allocate data\n"); + return -ENOMEM; + } + + data->banks = wm8850_banks; + data->nbanks = ARRAY_SIZE(wm8850_banks); + data->pins = wm8850_pins; + data->npins = ARRAY_SIZE(wm8850_pins); + data->groups = wm8850_groups; + data->ngroups = ARRAY_SIZE(wm8850_groups); + + return wmt_pinctrl_probe(pdev, data); +} + +static int wm8850_pinctrl_remove(struct platform_device *pdev) +{ + return wmt_pinctrl_remove(pdev); +} + +static struct of_device_id wmt_pinctrl_of_match[] = { + { .compatible = "wm,wm8850-pinctrl" }, + { /* sentinel */ }, +}; + +static struct platform_driver wmt_pinctrl_driver = { + .probe = wm8850_pinctrl_probe, + .remove = wm8850_pinctrl_remove, + .driver = { + .name = "pinctrl-wm8850", + .owner = THIS_MODULE, + .of_match_table = wmt_pinctrl_of_match, + }, +}; + +module_platform_driver(wmt_pinctrl_driver); + +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_DESCRIPTION("Wondermedia WM8850 Pincontrol driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match); diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c new file mode 100644 index 000000000000..14400a7974bd --- /dev/null +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c @@ -0,0 +1,632 @@ +/* + * Pinctrl driver for the Wondermedia SoC's + * + * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> + * + * 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. + */ + +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "pinctrl-wmt.h" + +static inline void wmt_setbits(struct wmt_pinctrl_data *data, u32 reg, + u32 mask) +{ + u32 val; + + val = readl_relaxed(data->base + reg); + val |= mask; + writel_relaxed(val, data->base + reg); +} + +static inline void wmt_clearbits(struct wmt_pinctrl_data *data, u32 reg, + u32 mask) +{ + u32 val; + + val = readl_relaxed(data->base + reg); + val &= ~mask; + writel_relaxed(val, data->base + reg); +} + +enum wmt_func_sel { + WMT_FSEL_GPIO_IN = 0, + WMT_FSEL_GPIO_OUT = 1, + WMT_FSEL_ALT = 2, + WMT_FSEL_COUNT = 3, +}; + +static const char * const wmt_functions[WMT_FSEL_COUNT] = { + [WMT_FSEL_GPIO_IN] = "gpio_in", + [WMT_FSEL_GPIO_OUT] = "gpio_out", + [WMT_FSEL_ALT] = "alt", +}; + +static int wmt_pmx_get_functions_count(struct pinctrl_dev *pctldev) +{ + return WMT_FSEL_COUNT; +} + +static const char *wmt_pmx_get_function_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return wmt_functions[selector]; +} + +static int wmt_pmx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + + /* every pin does every function */ + *groups = data->groups; + *num_groups = data->ngroups; + + return 0; +} + +static int wmt_set_pinmux(struct wmt_pinctrl_data *data, unsigned func, + unsigned pin) +{ + u32 bank = WMT_BANK_FROM_PIN(pin); + u32 bit = WMT_BIT_FROM_PIN(pin); + u32 reg_en = data->banks[bank].reg_en; + u32 reg_dir = data->banks[bank].reg_dir; + + if (reg_dir == NO_REG) { + dev_err(data->dev, "pin:%d no direction register defined\n", + pin); + return -EINVAL; + } + + /* + * If reg_en == NO_REG, we assume it is a dedicated GPIO and cannot be + * disabled (as on VT8500) and that no alternate function is available. + */ + switch (func) { + case WMT_FSEL_GPIO_IN: + if (reg_en != NO_REG) + wmt_setbits(data, reg_en, BIT(bit)); + wmt_clearbits(data, reg_dir, BIT(bit)); + break; + case WMT_FSEL_GPIO_OUT: + if (reg_en != NO_REG) + wmt_setbits(data, reg_en, BIT(bit)); + wmt_setbits(data, reg_dir, BIT(bit)); + break; + case WMT_FSEL_ALT: + if (reg_en == NO_REG) { + dev_err(data->dev, "pin:%d no alt function available\n", + pin); + return -EINVAL; + } + wmt_clearbits(data, reg_en, BIT(bit)); + } + + return 0; +} + +static int wmt_pmx_enable(struct pinctrl_dev *pctldev, + unsigned func_selector, + unsigned group_selector) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + u32 pinnum = data->pins[group_selector].number; + + return wmt_set_pinmux(data, func_selector, pinnum); +} + +static void wmt_pmx_disable(struct pinctrl_dev *pctldev, + unsigned func_selector, + unsigned group_selector) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + u32 pinnum = data->pins[group_selector].number; + + /* disable by setting GPIO_IN */ + wmt_set_pinmux(data, WMT_FSEL_GPIO_IN, pinnum); +} + +static void wmt_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + + /* disable by setting GPIO_IN */ + wmt_set_pinmux(data, WMT_FSEL_GPIO_IN, offset); +} + +static int wmt_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset, + bool input) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + + wmt_set_pinmux(data, (input ? WMT_FSEL_GPIO_IN : WMT_FSEL_GPIO_OUT), + offset); + + return 0; +} + +static struct pinmux_ops wmt_pinmux_ops = { + .get_functions_count = wmt_pmx_get_functions_count, + .get_function_name = wmt_pmx_get_function_name, + .get_function_groups = wmt_pmx_get_function_groups, + .enable = wmt_pmx_enable, + .disable = wmt_pmx_disable, + .gpio_disable_free = wmt_pmx_gpio_disable_free, + .gpio_set_direction = wmt_pmx_gpio_set_direction, +}; + +static int wmt_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + + return data->ngroups; +} + +static const char *wmt_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + + return data->groups[selector]; +} + +static int wmt_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + + *pins = &data->pins[selector].number; + *num_pins = 1; + + return 0; +} + +static int wmt_pctl_find_group_by_pin(struct wmt_pinctrl_data *data, u32 pin) +{ + int i; + + for (i = 0; i < data->npins; i++) { + if (data->pins[i].number == pin) + return i; + } + + return -EINVAL; +} + +static int wmt_pctl_dt_node_to_map_func(struct wmt_pinctrl_data *data, + struct device_node *np, + u32 pin, u32 fnum, + struct pinctrl_map **maps) +{ + int group; + struct pinctrl_map *map = *maps; + + if (fnum >= ARRAY_SIZE(wmt_functions)) { + dev_err(data->dev, "invalid wm,function %d\n", fnum); + return -EINVAL; + } + + group = wmt_pctl_find_group_by_pin(data, pin); + if (group < 0) { + dev_err(data->dev, "unable to match pin %d to group\n", pin); + return group; + } + + map->type = PIN_MAP_TYPE_MUX_GROUP; + map->data.mux.group = data->groups[group]; + map->data.mux.function = wmt_functions[fnum]; + (*maps)++; + + return 0; +} + +static int wmt_pctl_dt_node_to_map_pull(struct wmt_pinctrl_data *data, + struct device_node *np, + u32 pin, u32 pull, + struct pinctrl_map **maps) +{ + int group; + unsigned long *configs; + struct pinctrl_map *map = *maps; + + if (pull > 2) { + dev_err(data->dev, "invalid wm,pull %d\n", pull); + return -EINVAL; + } + + group = wmt_pctl_find_group_by_pin(data, pin); + if (group < 0) { + dev_err(data->dev, "unable to match pin %d to group\n", pin); + return group; + } + + configs = kzalloc(sizeof(*configs), GFP_KERNEL); + if (!configs) + return -ENOMEM; + + configs[0] = pull; + + map->type = PIN_MAP_TYPE_CONFIGS_PIN; + map->data.configs.group_or_pin = data->groups[group]; + map->data.configs.configs = configs; + map->data.configs.num_configs = 1; + (*maps)++; + + return 0; +} + +static void wmt_pctl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *maps, + unsigned num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN) + kfree(maps[i].data.configs.configs); + + kfree(maps); +} + +static int wmt_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *num_maps) +{ + struct pinctrl_map *maps, *cur_map; + struct property *pins, *funcs, *pulls; + u32 pin, func, pull; + int num_pins, num_funcs, num_pulls, maps_per_pin; + int i, err; + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + + pins = of_find_property(np, "wm,pins", NULL); + if (!pins) { + dev_err(data->dev, "missing wmt,pins property\n"); + return -EINVAL; + } + + funcs = of_find_property(np, "wm,function", NULL); + pulls = of_find_property(np, "wm,pull", NULL); + + if (!funcs && !pulls) { + dev_err(data->dev, "neither wm,function nor wm,pull specified\n"); + return -EINVAL; + } + + /* + * The following lines calculate how many values are defined for each + * of the properties. + */ + num_pins = pins->length / sizeof(u32); + num_funcs = funcs ? (funcs->length / sizeof(u32)) : 0; + num_pulls = pulls ? (pulls->length / sizeof(u32)) : 0; + + if (num_funcs > 1 && num_funcs != num_pins) { + dev_err(data->dev, "wm,function must have 1 or %d entries\n", + num_pins); + return -EINVAL; + } + + if (num_pulls > 1 && num_pulls != num_pins) { + dev_err(data->dev, "wm,pull must have 1 or %d entries\n", + num_pins); + return -EINVAL; + } + + maps_per_pin = 0; + if (num_funcs) + maps_per_pin++; + if (num_pulls) + maps_per_pin++; + + cur_map = maps = kzalloc(num_pins * maps_per_pin * sizeof(*maps), + GFP_KERNEL); + if (!maps) + return -ENOMEM; + + for (i = 0; i < num_pins; i++) { + err = of_property_read_u32_index(np, "wm,pins", i, &pin); + if (err) + goto fail; + + if (pin >= (data->nbanks * 32)) { + dev_err(data->dev, "invalid wm,pins value\n"); + err = -EINVAL; + goto fail; + } + + if (num_funcs) { + err = of_property_read_u32_index(np, "wm,function", + (num_funcs > 1 ? i : 0), &func); + if (err) + goto fail; + + err = wmt_pctl_dt_node_to_map_func(data, np, pin, func, + &cur_map); + if (err) + goto fail; + } + + if (num_pulls) { + err = of_property_read_u32_index(np, "wm,pull", + (num_pulls > 1 ? i : 0), &pull); + if (err) + goto fail; + + err = wmt_pctl_dt_node_to_map_pull(data, np, pin, pull, + &cur_map); + if (err) + goto fail; + } + } + *map = maps; + *num_maps = num_pins * maps_per_pin; + return 0; + +/* + * The fail path removes any maps that have been allocated. The fail path is + * only called from code after maps has been kzalloc'd. It is also safe to + * pass 'num_pins * maps_per_pin' as the map count even though we probably + * failed before all the mappings were read as all maps are allocated at once, + * and configs are only allocated for .type = PIN_MAP_TYPE_CONFIGS_PIN - there + * is no failpath where a config can be allocated without .type being set. + */ +fail: + wmt_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin); + return err; +} + +static struct pinctrl_ops wmt_pctl_ops = { + .get_groups_count = wmt_get_groups_count, + .get_group_name = wmt_get_group_name, + .get_group_pins = wmt_get_group_pins, + .dt_node_to_map = wmt_pctl_dt_node_to_map, + .dt_free_map = wmt_pctl_dt_free_map, +}; + +static int wmt_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) +{ + return -ENOTSUPP; +} + +static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long config) +{ + struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(config); + u16 arg = pinconf_to_config_argument(config); + u32 bank = WMT_BANK_FROM_PIN(pin); + u32 bit = WMT_BIT_FROM_PIN(pin); + u32 reg_pull_en = data->banks[bank].reg_pull_en; + u32 reg_pull_cfg = data->banks[bank].reg_pull_cfg; + + if ((reg_pull_en == NO_REG) || (reg_pull_cfg == NO_REG)) { + dev_err(data->dev, "bias functions not supported on pin %d\n", + pin); + return -EINVAL; + } + + if ((param == PIN_CONFIG_BIAS_PULL_DOWN) || + (param == PIN_CONFIG_BIAS_PULL_UP)) { + if (arg == 0) + param = PIN_CONFIG_BIAS_DISABLE; + } + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + wmt_clearbits(data, reg_pull_en, BIT(bit)); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + wmt_clearbits(data, reg_pull_cfg, BIT(bit)); + wmt_setbits(data, reg_pull_en, BIT(bit)); + break; + case PIN_CONFIG_BIAS_PULL_UP: + wmt_setbits(data, reg_pull_cfg, BIT(bit)); + wmt_setbits(data, reg_pull_en, BIT(bit)); + break; + default: + dev_err(data->dev, "unknown pinconf param\n"); + return -EINVAL; + } + + return 0; +} + +static struct pinconf_ops wmt_pinconf_ops = { + .pin_config_get = wmt_pinconf_get, + .pin_config_set = wmt_pinconf_set, +}; + +static struct pinctrl_desc wmt_desc = { + .owner = THIS_MODULE, + .name = "pinctrl-wmt", + .pctlops = &wmt_pctl_ops, + .pmxops = &wmt_pinmux_ops, + .confops = &wmt_pinconf_ops, +}; + +static int wmt_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void wmt_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev); + u32 bank = WMT_BANK_FROM_PIN(offset); + u32 bit = WMT_BIT_FROM_PIN(offset); + u32 reg_dir = data->banks[bank].reg_dir; + u32 val; + + val = readl_relaxed(data->base + reg_dir); + if (val & BIT(bit)) + return GPIOF_DIR_OUT; + else + return GPIOF_DIR_IN; +} + +static int wmt_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int wmt_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + return pinctrl_gpio_direction_output(chip->base + offset); +} + +static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev); + u32 bank = WMT_BANK_FROM_PIN(offset); + u32 bit = WMT_BIT_FROM_PIN(offset); + u32 reg_data_in = data->banks[bank].reg_data_in; + + if (reg_data_in == NO_REG) { + dev_err(data->dev, "no data in register defined\n"); + return -EINVAL; + } + + return !!(readl_relaxed(data->base + reg_data_in) & BIT(bit)); +} + +static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev); + u32 bank = WMT_BANK_FROM_PIN(offset); + u32 bit = WMT_BIT_FROM_PIN(offset); + u32 reg_data_out = data->banks[bank].reg_data_out; + + if (reg_data_out == NO_REG) { + dev_err(data->dev, "no data out register defined\n"); + return; + } + + if (val) + wmt_setbits(data, reg_data_out, BIT(bit)); + else + wmt_clearbits(data, reg_data_out, BIT(bit)); +} + +static struct gpio_chip wmt_gpio_chip = { + .label = "gpio-wmt", + .owner = THIS_MODULE, + .request = wmt_gpio_request, + .free = wmt_gpio_free, + .get_direction = wmt_gpio_get_direction, + .direction_input = wmt_gpio_direction_input, + .direction_output = wmt_gpio_direction_output, + .get = wmt_gpio_get_value, + .set = wmt_gpio_set_value, + .can_sleep = 0, +}; + +int wmt_pinctrl_probe(struct platform_device *pdev, + struct wmt_pinctrl_data *data) +{ + int err; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_request_and_ioremap(&pdev->dev, res); + if (!data->base) { + dev_err(&pdev->dev, "failed to map memory resource\n"); + return -EBUSY; + } + + wmt_desc.pins = data->pins; + wmt_desc.npins = data->npins; + + data->gpio_chip = wmt_gpio_chip; + data->gpio_chip.dev = &pdev->dev; + data->gpio_chip.of_node = pdev->dev.of_node; + data->gpio_chip.ngpio = data->nbanks * 32; + + platform_set_drvdata(pdev, data); + + data->dev = &pdev->dev; + + data->pctl_dev = pinctrl_register(&wmt_desc, &pdev->dev, data); + if (IS_ERR(data->pctl_dev)) { + dev_err(&pdev->dev, "Failed to register pinctrl\n"); + return -EINVAL; + } + + err = gpiochip_add(&data->gpio_chip); + if (err) { + dev_err(&pdev->dev, "could not add GPIO chip\n"); + goto fail_gpio; + } + + err = gpiochip_add_pin_range(&data->gpio_chip, dev_name(data->dev), + 0, 0, data->nbanks * 32); + if (err) + goto fail_range; + + dev_info(&pdev->dev, "Pin controller initialized\n"); + + return 0; + +fail_range: + err = gpiochip_remove(&data->gpio_chip); + if (err) + dev_err(&pdev->dev, "failed to remove gpio chip\n"); +fail_gpio: + pinctrl_unregister(data->pctl_dev); + return err; +} + +int wmt_pinctrl_remove(struct platform_device *pdev) +{ + struct wmt_pinctrl_data *data = platform_get_drvdata(pdev); + int err; + + err = gpiochip_remove(&data->gpio_chip); + if (err) + dev_err(&pdev->dev, "failed to remove gpio chip\n"); + + pinctrl_unregister(data->pctl_dev); + + return 0; +} diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.h b/drivers/pinctrl/vt8500/pinctrl-wmt.h new file mode 100644 index 000000000000..41f5f2deb5d6 --- /dev/null +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.h @@ -0,0 +1,79 @@ +/* + * Pinctrl driver for the Wondermedia SoC's + * + * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> + * + * 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. + */ + +#include <linux/gpio.h> + +/* VT8500 has no enable register in the extgpio bank. */ +#define NO_REG 0xFFFF + +#define WMT_PINCTRL_BANK(__en, __dir, __dout, __din, __pen, __pcfg) \ +{ \ + .reg_en = __en, \ + .reg_dir = __dir, \ + .reg_data_out = __dout, \ + .reg_data_in = __din, \ + .reg_pull_en = __pen, \ + .reg_pull_cfg = __pcfg, \ +} + +/* Encode/decode the bank/bit pairs into a pin value */ +#define WMT_PIN(__bank, __offset) ((__bank << 5) | __offset) +#define WMT_BANK_FROM_PIN(__pin) (__pin >> 5) +#define WMT_BIT_FROM_PIN(__pin) (__pin & 0x1f) + +#define WMT_GROUP(__name, __data) \ +{ \ + .name = __name, \ + .pins = __data, \ + .npins = ARRAY_SIZE(__data), \ +} + +struct wmt_pinctrl_bank_registers { + u32 reg_en; + u32 reg_dir; + u32 reg_data_out; + u32 reg_data_in; + + u32 reg_pull_en; + u32 reg_pull_cfg; +}; + +struct wmt_pinctrl_group { + const char *name; + const unsigned int *pins; + const unsigned npins; +}; + +struct wmt_pinctrl_data { + struct device *dev; + struct pinctrl_dev *pctl_dev; + + /* must be initialized before calling wmt_pinctrl_probe */ + void __iomem *base; + const struct wmt_pinctrl_bank_registers *banks; + const struct pinctrl_pin_desc *pins; + const char * const *groups; + + u32 nbanks; + u32 npins; + u32 ngroups; + + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range gpio_range; +}; + +int wmt_pinctrl_probe(struct platform_device *pdev, + struct wmt_pinctrl_data *data); +int wmt_pinctrl_remove(struct platform_device *pdev); diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 81a1fe661579..71a73ec5af8d 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -1483,7 +1483,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_NONE: /* continous acquisition */ devpriv->ai_continous = 1; - devpriv->ai_sample_count = 0; + devpriv->ai_sample_count = 1; break; } diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig index 73582705e8c5..5c3714530961 100644 --- a/drivers/staging/zcache/Kconfig +++ b/drivers/staging/zcache/Kconfig @@ -15,7 +15,7 @@ config RAMSTER depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE=y depends on NET # must ensure struct page is 8-byte aligned - select HAVE_ALIGNED_STRUCT_PAGE if !64_BIT + select HAVE_ALIGNED_STRUCT_PAGE if !64BIT default n help RAMster allows RAM on other machines in a cluster to be utilized diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2030b608136d..3243ea790eab 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1139,8 +1139,10 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb) return ret; ret = target_check_reservation(cmd); - if (ret) + if (ret) { + cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; return ret; + } ret = dev->transport->parse_cdb(cmd); if (ret) diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250_core.c index cf6a5383748a..35f9c96aada9 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -3418,6 +3418,7 @@ MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); #endif MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); +#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS #ifndef MODULE /* This module was renamed to 8250_core in 3.7. Keep the old "8250" name * working as well for the module options so we don't break people. We @@ -3432,7 +3433,7 @@ MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); static void __used s8250_options(void) { #undef MODULE_PARAM_PREFIX -#define MODULE_PARAM_PREFIX "8250." +#define MODULE_PARAM_PREFIX "8250_core." module_param_cb(share_irqs, ¶m_ops_uint, &share_irqs, 0644); module_param_cb(nr_uarts, ¶m_ops_uint, &nr_uarts, 0644); @@ -3444,5 +3445,6 @@ static void __used s8250_options(void) #endif } #else -MODULE_ALIAS("8250"); +MODULE_ALIAS("8250_core"); +#endif #endif diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index aa76825229dc..26e3a97ab157 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1554,6 +1554,7 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 #define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d #define PCI_VENDOR_ID_WCH 0x4348 +#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253 #define PCI_DEVICE_ID_WCH_CH353_4S 0x3453 #define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 #define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 @@ -2172,6 +2173,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, + /* WCH CH352 2S card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH352_2S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch353_setup, + }, /* * ASIX devices with FIFO bug */ @@ -4870,6 +4879,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_2_115200 }, + /* * Commtech, Inc. Fastcom adapters */ diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 2ef9537bcb2c..80fe91e64a52 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -33,6 +33,23 @@ config SERIAL_8250 Most people will say Y or M here, so that they can use serial mice, modems and similar devices connecting to the standard serial ports. +config SERIAL_8250_DEPRECATED_OPTIONS + bool "Support 8250_core.* kernel options (DEPRECATED)" + depends on SERIAL_8250 + default y + ---help--- + In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to + accept kernel parameters in both forms like 8250_core.nr_uarts=4 and + 8250.nr_uarts=4. We now renamed the module back to 8250, but if + anybody noticed in 3.7 and changed their userspace we still have to + keep the 8350_core.* options around until they revert the changes + they already did. + + If 8250 is built as a module, this adds 8250_core alias instead. + + If you did not notice yet and/or you have userspace from pre-3.7, it + is safe (and recommended) to say N here. + config SERIAL_8250_PNP bool "8250/16550 PNP device support" if EXPERT depends on SERIAL_8250 && PNP diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index a23838a4d535..36d68d054307 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -2,10 +2,10 @@ # Makefile for the 8250 serial device drivers. # -obj-$(CONFIG_SERIAL_8250) += 8250_core.o -8250_core-y := 8250.o -8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o -8250_core-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o +obj-$(CONFIG_SERIAL_8250) += 8250.o +8250-y := 8250_core.o +8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o +8250-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d4a7c241b751..3467462869ce 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -158,7 +158,7 @@ struct atmel_uart_port { }; static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; -static unsigned long atmel_ports_in_use; +static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART); #ifdef SUPPORT_SYSRQ static struct console atmel_console; @@ -1769,15 +1769,14 @@ static int atmel_serial_probe(struct platform_device *pdev) if (ret < 0) /* port id not found in platform data nor device-tree aliases: * auto-enumerate it */ - ret = find_first_zero_bit(&atmel_ports_in_use, - sizeof(atmel_ports_in_use)); + ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART); - if (ret > ATMEL_MAX_UART) { + if (ret >= ATMEL_MAX_UART) { ret = -ENODEV; goto err; } - if (test_and_set_bit(ret, &atmel_ports_in_use)) { + if (test_and_set_bit(ret, atmel_ports_in_use)) { /* port already in use */ ret = -EBUSY; goto err; @@ -1857,7 +1856,7 @@ static int atmel_serial_remove(struct platform_device *pdev) /* "port" is allocated statically, so we shouldn't free it */ - clear_bit(port->line, &atmel_ports_in_use); + clear_bit(port->line, atmel_ports_in_use); clk_put(atmel_port->clk); diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index ba451c7209fc..f36bbba1ac8b 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -578,6 +578,8 @@ static int xuartps_startup(struct uart_port *port) /* Receive Timeout register is enabled with value of 10 */ xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); + /* Clear out any pending interrupts before enabling them */ + xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET); /* Set the Interrupt Registers with desired interrupts */ xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY | diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index e4ca345873c3..d7799deacb21 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -93,7 +93,7 @@ vcs_poll_data_free(struct vcs_poll_data *poll) static struct vcs_poll_data * vcs_poll_data_get(struct file *file) { - struct vcs_poll_data *poll = file->private_data; + struct vcs_poll_data *poll = file->private_data, *kill = NULL; if (poll) return poll; @@ -122,10 +122,12 @@ vcs_poll_data_get(struct file *file) file->private_data = poll; } else { /* someone else raced ahead of us */ - vcs_poll_data_free(poll); + kill = poll; poll = file->private_data; } spin_unlock(&file->f_lock); + if (kill) + vcs_poll_data_free(kill); return poll; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 99b34a30354f..f9ec44cbb82f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2412,6 +2412,14 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd); +int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1) +{ + if (!hcd->driver->find_raw_port_number) + return port1; + + return hcd->driver->find_raw_port_number(hcd, port1); +} + static int usb_hcd_request_irqs(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index b6f4bad3f756..255c14464bf2 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -15,6 +15,7 @@ #include <linux/kernel.h> #include <linux/acpi.h> #include <linux/pci.h> +#include <linux/usb/hcd.h> #include <acpi/acpi_bus.h> #include "usb.h" @@ -188,8 +189,13 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) * connected to. */ if (!udev->parent) { - *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev), + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + int raw_port_num; + + raw_port_num = usb_hcd_find_raw_port_number(hcd, port_num); + *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev), + raw_port_num); if (!*handle) return -ENODEV; } else { diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5a0c541daf89..c7525b1cad74 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -145,6 +145,7 @@ config USB_LPC32XX tristate "LPC32XX USB Peripheral Controller" depends on ARCH_LPC32XX select USB_ISP1301 + select USB_OTG_UTILS help This option selects the USB device controller in the LPC32xx SoC. diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index b476daf49f6f..010f686d8881 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1214,6 +1214,7 @@ itd_urb_transaction ( memset (itd, 0, sizeof *itd); itd->itd_dma = itd_dma; + itd->frame = 9999; /* an invalid value */ list_add (&itd->itd_list, &sched->td_list); } spin_unlock_irqrestore (&ehci->lock, flags); @@ -1915,6 +1916,7 @@ sitd_urb_transaction ( memset (sitd, 0, sizeof *sitd); sitd->sitd_dma = sitd_dma; + sitd->frame = 9999; /* an invalid value */ list_add (&sitd->sitd_list, &iso_sched->td_list); } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 35616ffbe3ae..6dc238c592bc 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1022,44 +1022,24 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, * is attached to (or the roothub port its ancestor hub is attached to). All we * know is the index of that port under either the USB 2.0 or the USB 3.0 * roothub, but that doesn't give us the real index into the HW port status - * registers. Scan through the xHCI roothub port array, looking for the Nth - * entry of the correct port speed. Return the port number of that entry. + * registers. Call xhci_find_raw_port_number() to get real index. */ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci, struct usb_device *udev) { struct usb_device *top_dev; - unsigned int num_similar_speed_ports; - unsigned int faked_port_num; - int i; + struct usb_hcd *hcd; + + if (udev->speed == USB_SPEED_SUPER) + hcd = xhci->shared_hcd; + else + hcd = xhci->main_hcd; for (top_dev = udev; top_dev->parent && top_dev->parent->parent; top_dev = top_dev->parent) /* Found device below root hub */; - faked_port_num = top_dev->portnum; - for (i = 0, num_similar_speed_ports = 0; - i < HCS_MAX_PORTS(xhci->hcs_params1); i++) { - u8 port_speed = xhci->port_array[i]; - - /* - * Skip ports that don't have known speeds, or have duplicate - * Extended Capabilities port speed entries. - */ - if (port_speed == 0 || port_speed == DUPLICATE_ENTRY) - continue; - /* - * USB 3.0 ports are always under a USB 3.0 hub. USB 2.0 and - * 1.1 ports are under the USB 2.0 hub. If the port speed - * matches the device speed, it's a similar speed port. - */ - if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER)) - num_similar_speed_ports++; - if (num_similar_speed_ports == faked_port_num) - /* Roothub ports are numbered from 1 to N */ - return i+1; - } - return 0; + return xhci_find_raw_port_number(hcd, top_dev->portnum); } /* Setup an xHCI virtual device for a Set Address command */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index af259e0ec172..1a30c380043c 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -313,6 +313,7 @@ static const struct hc_driver xhci_pci_hc_driver = { .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm, .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, + .find_raw_port_number = xhci_find_raw_port_number, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 882875465301..1969c001b3f9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1599,14 +1599,20 @@ static void handle_port_status(struct xhci_hcd *xhci, max_ports = HCS_MAX_PORTS(xhci->hcs_params1); if ((port_id <= 0) || (port_id > max_ports)) { xhci_warn(xhci, "Invalid port id %d\n", port_id); - bogus_port_status = true; - goto cleanup; + inc_deq(xhci, xhci->event_ring); + return; } /* Figure out which usb_hcd this port is attached to: * is it a USB 3.0 port or a USB 2.0/1.1 port? */ major_revision = xhci->port_array[port_id - 1]; + + /* Find the right roothub. */ + hcd = xhci_to_hcd(xhci); + if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) + hcd = xhci->shared_hcd; + if (major_revision == 0) { xhci_warn(xhci, "Event for port %u not in " "Extended Capabilities, ignoring.\n", @@ -1629,10 +1635,6 @@ static void handle_port_status(struct xhci_hcd *xhci, * into the index into the ports on the correct split roothub, and the * correct bus_state structure. */ - /* Find the right roothub. */ - hcd = xhci_to_hcd(xhci); - if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) - hcd = xhci->shared_hcd; bus_state = &xhci->bus_state[hcd_index(hcd)]; if (hcd->speed == HCD_USB3) port_array = xhci->usb3_ports; @@ -2027,8 +2029,8 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, if (event_trb != ep_ring->dequeue && event_trb != td->last_trb) td->urb->actual_length = - td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); + td->urb->transfer_buffer_length - + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); else td->urb->actual_length = 0; @@ -2060,7 +2062,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, /* Maybe the event was for the data stage? */ td->urb->actual_length = td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); xhci_dbg(xhci, "Waiting for status " "stage event\n"); return 0; @@ -2096,7 +2098,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* handle completion code */ switch (trb_comp_code) { case COMP_SUCCESS: - if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { frame->status = 0; break; } @@ -2141,7 +2143,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])); } len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - - TRB_LEN(le32_to_cpu(event->transfer_len)); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); if (trb_comp_code != COMP_STOP_INVAL) { frame->actual_length = len; @@ -2199,7 +2201,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, case COMP_SUCCESS: /* Double check that the HW transferred everything. */ if (event_trb != td->last_trb || - TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { xhci_warn(xhci, "WARN Successful completion " "on short TX\n"); if (td->urb->transfer_flags & URB_SHORT_NOT_OK) @@ -2227,18 +2229,18 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, "%d bytes untransferred\n", td->urb->ep->desc.bEndpointAddress, td->urb->transfer_buffer_length, - TRB_LEN(le32_to_cpu(event->transfer_len))); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); /* Fast path - was this the last TRB in the TD for this URB? */ if (event_trb == td->last_trb) { - if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { td->urb->actual_length = td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); if (td->urb->transfer_buffer_length < td->urb->actual_length) { xhci_warn(xhci, "HC gave bad length " "of %d bytes left\n", - TRB_LEN(le32_to_cpu(event->transfer_len))); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); td->urb->actual_length = 0; if (td->urb->transfer_flags & URB_SHORT_NOT_OK) *status = -EREMOTEIO; @@ -2280,7 +2282,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, if (trb_comp_code != COMP_STOP_INVAL) td->urb->actual_length += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - - TRB_LEN(le32_to_cpu(event->transfer_len)); + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); } return finish_td(xhci, td, event_trb, event, ep, status, false); @@ -2368,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, * transfer type */ case COMP_SUCCESS: - if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) break; if (xhci->quirks & XHCI_TRUST_TX_LENGTH) trb_comp_code = COMP_SHORT_TX; @@ -2461,14 +2463,21 @@ static int handle_tx_event(struct xhci_hcd *xhci, * TD list. */ if (list_empty(&ep_ring->td_list)) { - xhci_warn(xhci, "WARN Event TRB for slot %d ep %d " - "with no TDs queued?\n", - TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), - ep_index); - xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", - (le32_to_cpu(event->flags) & - TRB_TYPE_BITMASK)>>10); - xhci_print_trb_offsets(xhci, (union xhci_trb *) event); + /* + * A stopped endpoint may generate an extra completion + * event if the device was suspended. Don't print + * warnings. + */ + if (!(trb_comp_code == COMP_STOP || + trb_comp_code == COMP_STOP_INVAL)) { + xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", + TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), + ep_index); + xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", + (le32_to_cpu(event->flags) & + TRB_TYPE_BITMASK)>>10); + xhci_print_trb_offsets(xhci, (union xhci_trb *) event); + } if (ep->skip) { ep->skip = false; xhci_dbg(xhci, "td_list is empty while skip " diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 849470b18831..53b8f89a0b1c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3779,6 +3779,28 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) return 0; } +/* + * Transfer the port index into real index in the HW port status + * registers. Caculate offset between the port's PORTSC register + * and port status base. Divide the number of per port register + * to get the real index. The raw port number bases 1. + */ +int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + __le32 __iomem *base_addr = &xhci->op_regs->port_status_base; + __le32 __iomem *addr; + int raw_port; + + if (hcd->speed != HCD_USB3) + addr = xhci->usb2_ports[port1 - 1]; + else + addr = xhci->usb3_ports[port1 - 1]; + + raw_port = (addr - base_addr)/NUM_PORT_REGS + 1; + return raw_port; +} + #ifdef CONFIG_USB_SUSPEND /* BESL to HIRD Encoding array for USB2 LPM */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2c510e4a7d4c..63582719e0fb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -972,6 +972,10 @@ struct xhci_transfer_event { __le32 flags; }; +/* Transfer event TRB length bit mask */ +/* bits 0:23 */ +#define EVENT_TRB_LEN(p) ((p) & 0xffffff) + /** Transfer Event bit fields **/ #define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) @@ -1829,6 +1833,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); +int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1); #ifdef CONFIG_PM int xhci_bus_suspend(struct usb_hcd *hcd); diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 65217a590068..90549382eba5 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -38,6 +38,7 @@ config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET depends on I2C + select USB_OTG_UTILS help Say Y here to add support for the NXP ISP1301 USB transceiver driver. This chip is typically used as USB transceiver for USB host, gadget diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d4809d551473..9886180e45f1 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -640,6 +640,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, + { USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 9d359e189a64..e79861eeed4c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -584,6 +584,13 @@ #define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ /* + * Mitsubishi Electric Corp. (http://www.meau.com) + * Submitted by Konstantin Holoborodko + */ +#define MITSUBISHI_VID 0x06D3 +#define MITSUBISHI_FXUSB_PID 0x0284 /* USB/RS422 converters: FX-USB-AW/-BD */ + +/* * Definitions for B&B Electronics products. */ #define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 2e70efa08b77..5d9b178484fd 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -903,6 +903,7 @@ static int usb_serial_probe(struct usb_interface *interface, port->port.ops = &serial_port_ops; port->serial = serial; spin_lock_init(&port->lock); + init_waitqueue_head(&port->delta_msr_wait); /* Keep this for private driver use for the moment but should probably go away */ INIT_WORK(&port->work, usb_serial_port_work); diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c index 43fb11ee2e8d..2968b4934659 100644 --- a/drivers/vhost/tcm_vhost.c +++ b/drivers/vhost/tcm_vhost.c @@ -60,6 +60,15 @@ enum { VHOST_SCSI_VQ_IO = 2, }; +/* + * VIRTIO_RING_F_EVENT_IDX seems broken. Not sure the bug is in + * kernel but disabling it helps. + * TODO: debug and remove the workaround. + */ +enum { + VHOST_SCSI_FEATURES = VHOST_FEATURES & (~VIRTIO_RING_F_EVENT_IDX) +}; + #define VHOST_SCSI_MAX_TARGET 256 #define VHOST_SCSI_MAX_VQ 128 @@ -946,7 +955,7 @@ static void vhost_scsi_flush(struct vhost_scsi *vs) static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) { - if (features & ~VHOST_FEATURES) + if (features & ~VHOST_SCSI_FEATURES) return -EOPNOTSUPP; mutex_lock(&vs->dev.mutex); @@ -992,7 +1001,7 @@ static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl, return -EFAULT; return 0; case VHOST_GET_FEATURES: - features = VHOST_FEATURES; + features = VHOST_SCSI_FEATURES; if (copy_to_user(featurep, &features, sizeof features)) return -EFAULT; return 0; diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 025428e04c33..c1a2914447e1 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -34,6 +34,77 @@ #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ #define ATMEL_LCDC_FIFO_SIZE 512 /* words */ +struct atmel_lcdfb_config { + bool have_alt_pixclock; + bool have_hozval; + bool have_intensity_bit; +}; + +static struct atmel_lcdfb_config at91sam9261_config = { + .have_hozval = true, + .have_intensity_bit = true, +}; + +static struct atmel_lcdfb_config at91sam9263_config = { + .have_intensity_bit = true, +}; + +static struct atmel_lcdfb_config at91sam9g10_config = { + .have_hozval = true, +}; + +static struct atmel_lcdfb_config at91sam9g45_config = { + .have_alt_pixclock = true, +}; + +static struct atmel_lcdfb_config at91sam9g45es_config = { +}; + +static struct atmel_lcdfb_config at91sam9rl_config = { + .have_intensity_bit = true, +}; + +static struct atmel_lcdfb_config at32ap_config = { + .have_hozval = true, +}; + +static const struct platform_device_id atmel_lcdfb_devtypes[] = { + { + .name = "at91sam9261-lcdfb", + .driver_data = (unsigned long)&at91sam9261_config, + }, { + .name = "at91sam9263-lcdfb", + .driver_data = (unsigned long)&at91sam9263_config, + }, { + .name = "at91sam9g10-lcdfb", + .driver_data = (unsigned long)&at91sam9g10_config, + }, { + .name = "at91sam9g45-lcdfb", + .driver_data = (unsigned long)&at91sam9g45_config, + }, { + .name = "at91sam9g45es-lcdfb", + .driver_data = (unsigned long)&at91sam9g45es_config, + }, { + .name = "at91sam9rl-lcdfb", + .driver_data = (unsigned long)&at91sam9rl_config, + }, { + .name = "at32ap-lcdfb", + .driver_data = (unsigned long)&at32ap_config, + }, { + /* terminator */ + } +}; + +static struct atmel_lcdfb_config * +atmel_lcdfb_get_config(struct platform_device *pdev) +{ + unsigned long data; + + data = platform_get_device_id(pdev)->driver_data; + + return (struct atmel_lcdfb_config *)data; +} + #if defined(CONFIG_ARCH_AT91) #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ | FBINFO_PARTIAL_PAN_OK \ @@ -193,14 +264,16 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) +static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo, + unsigned long xres) { + unsigned long lcdcon2; unsigned long value; - if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10() - || cpu_is_at32ap7000())) + if (!sinfo->config->have_hozval) return xres; + lcdcon2 = lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2); value = xres; if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { /* STN display */ @@ -423,7 +496,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, break; case 16: /* Older SOCs use IBGR:555 rather than BGR:565. */ - if (sinfo->have_intensity_bit) + if (sinfo->config->have_intensity_bit) var->green.length = 5; else var->green.length = 6; @@ -531,7 +604,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info) /* Now, the LCDC core... */ /* Set pixel clock */ - if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) + if (sinfo->config->have_alt_pixclock) pix_factor = 1; clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; @@ -591,8 +664,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info) lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); /* Horizontal value (aka line size) */ - hozval_linesz = compute_hozval(info->var.xres, - lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); + hozval_linesz = compute_hozval(sinfo, info->var.xres); /* Display size */ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; @@ -684,7 +756,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, case FB_VISUAL_PSEUDOCOLOR: if (regno < 256) { - if (sinfo->have_intensity_bit) { + if (sinfo->config->have_intensity_bit) { /* old style I+BGR:555 */ val = ((red >> 11) & 0x001f); val |= ((green >> 6) & 0x03e0); @@ -821,15 +893,13 @@ static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo) { - if (sinfo->bus_clk) - clk_enable(sinfo->bus_clk); + clk_enable(sinfo->bus_clk); clk_enable(sinfo->lcdc_clk); } static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo) { - if (sinfo->bus_clk) - clk_disable(sinfo->bus_clk); + clk_disable(sinfo->bus_clk); clk_disable(sinfo->lcdc_clk); } @@ -874,10 +944,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) } sinfo->info = info; sinfo->pdev = pdev; - if (cpu_is_at91sam9261() || cpu_is_at91sam9263() || - cpu_is_at91sam9rl()) { - sinfo->have_intensity_bit = true; - } + sinfo->config = atmel_lcdfb_get_config(pdev); + if (!sinfo->config) + goto free_info; strcpy(info->fix.id, sinfo->pdev->name); info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; @@ -888,13 +957,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) info->fix = atmel_lcdfb_fix; /* Enable LCDC Clocks */ - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10() - || cpu_is_at32ap7000()) { - sinfo->bus_clk = clk_get(dev, "hck1"); - if (IS_ERR(sinfo->bus_clk)) { - ret = PTR_ERR(sinfo->bus_clk); - goto free_info; - } + sinfo->bus_clk = clk_get(dev, "hclk"); + if (IS_ERR(sinfo->bus_clk)) { + ret = PTR_ERR(sinfo->bus_clk); + goto free_info; } sinfo->lcdc_clk = clk_get(dev, "lcdc_clk"); if (IS_ERR(sinfo->lcdc_clk)) { @@ -1055,8 +1121,7 @@ stop_clk: atmel_lcdfb_stop_clock(sinfo); clk_put(sinfo->lcdc_clk); put_bus_clk: - if (sinfo->bus_clk) - clk_put(sinfo->bus_clk); + clk_put(sinfo->bus_clk); free_info: framebuffer_release(info); out: @@ -1081,8 +1146,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) unregister_framebuffer(info); atmel_lcdfb_stop_clock(sinfo); clk_put(sinfo->lcdc_clk); - if (sinfo->bus_clk) - clk_put(sinfo->bus_clk); + clk_put(sinfo->bus_clk); fb_dealloc_cmap(&info->cmap); free_irq(sinfo->irq_base, info); iounmap(sinfo->mmio); @@ -1151,7 +1215,7 @@ static struct platform_driver atmel_lcdfb_driver = { .remove = __exit_p(atmel_lcdfb_remove), .suspend = atmel_lcdfb_suspend, .resume = atmel_lcdfb_resume, - + .id_table = atmel_lcdfb_devtypes, .driver = { .name = "atmel_lcdfb", .owner = THIS_MODULE, diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index 755556ca5b2d..45169cbaba6e 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -169,6 +169,7 @@ struct mxsfb_info { unsigned dotclk_delay; const struct mxsfb_devdata *devdata; int mapped; + u32 sync; }; #define mxsfb_is_v3(host) (host->devdata->ipversion == 3) @@ -456,9 +457,9 @@ static int mxsfb_set_par(struct fb_info *fb_info) vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT) vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; - if (fb_info->var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT) + if (host->sync & MXSFB_SYNC_DATA_ENABLE_HIGH_ACT) vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; - if (fb_info->var.sync & FB_SYNC_DOTCLK_FAILING_ACT) + if (host->sync & MXSFB_SYNC_DOTCLK_FAILING_ACT) vdctrl0 |= VDCTRL0_DOTCLK_ACT_FAILING; writel(vdctrl0, host->base + LCDC_VDCTRL0); @@ -861,6 +862,8 @@ static int mxsfb_probe(struct platform_device *pdev) INIT_LIST_HEAD(&fb_info->modelist); + host->sync = pdata->sync; + ret = mxsfb_init_fbinfo(host); if (ret != 0) goto error_init_fb; diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index e31f5b33b501..d40612c31a98 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -32,6 +32,8 @@ #include <linux/omap-dma.h> +#include <mach/hardware.h> + #include "omapfb.h" #include "lcdc.h" diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 6b6643911d29..048c98381ef6 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -63,6 +63,9 @@ struct tpo_td043_device { u32 power_on_resume:1; }; +/* used to pass spi_device from SPI to DSS portion of the driver */ +static struct tpo_td043_device *g_tpo_td043; + static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) { struct spi_message m; @@ -403,7 +406,7 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev) static int tpo_td043_probe(struct omap_dss_device *dssdev) { - struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); + struct tpo_td043_device *tpo_td043 = g_tpo_td043; int nreset_gpio = dssdev->reset_gpio; int ret = 0; @@ -440,6 +443,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) if (ret) dev_warn(&dssdev->dev, "failed to create sysfs files\n"); + dev_set_drvdata(&dssdev->dev, tpo_td043); + return 0; fail_gpio_req: @@ -505,6 +510,9 @@ static int tpo_td043_spi_probe(struct spi_device *spi) return -ENODEV; } + if (g_tpo_td043 != NULL) + return -EBUSY; + spi->bits_per_word = 16; spi->mode = SPI_MODE_0; @@ -521,7 +529,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi) tpo_td043->spi = spi; tpo_td043->nreset_gpio = dssdev->reset_gpio; dev_set_drvdata(&spi->dev, tpo_td043); - dev_set_drvdata(&dssdev->dev, tpo_td043); + g_tpo_td043 = tpo_td043; omap_dss_register_driver(&tpo_td043_driver); @@ -534,6 +542,7 @@ static int tpo_td043_spi_remove(struct spi_device *spi) omap_dss_unregister_driver(&tpo_td043_driver); kfree(tpo_td043); + g_tpo_td043 = NULL; return 0; } diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index d7d66ef5cb58..7f791aeda4d2 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -202,12 +202,10 @@ static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = { static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { /* OMAP_DSS_CHANNEL_LCD */ - OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | - OMAP_DSS_OUTPUT_DSI1, + OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1, /* OMAP_DSS_CHANNEL_DIGIT */ - OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI | - OMAP_DSS_OUTPUT_DPI, + OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI, /* OMAP_DSS_CHANNEL_LCD2 */ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 5a32232cf7c1..67af155cf602 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -182,7 +182,7 @@ config XEN_PRIVCMD config XEN_STUB bool "Xen stub drivers" - depends on XEN && X86_64 + depends on XEN && X86_64 && BROKEN default n help Allow kernel to install stub drivers, to reserve space for Xen drivers, diff --git a/drivers/xen/events.c b/drivers/xen/events.c index d17aa41a9041..aa85881d17b2 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -403,11 +403,23 @@ static void unmask_evtchn(int port) if (unlikely((cpu != cpu_from_evtchn(port)))) do_hypercall = 1; - else + else { + /* + * Need to clear the mask before checking pending to + * avoid a race with an event becoming pending. + * + * EVTCHNOP_unmask will only trigger an upcall if the + * mask bit was set, so if a hypercall is needed + * remask the event. + */ + sync_clear_bit(port, BM(&s->evtchn_mask[0])); evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); - if (unlikely(evtchn_pending && xen_hvm_domain())) - do_hypercall = 1; + if (unlikely(evtchn_pending && xen_hvm_domain())) { + sync_set_bit(port, BM(&s->evtchn_mask[0])); + do_hypercall = 1; + } + } /* Slow path (hypercall) if this is a non-local port or if this is * an hvm domain and an event is pending (hvm domains don't have @@ -418,8 +430,6 @@ static void unmask_evtchn(int port) } else { struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); - sync_clear_bit(port, BM(&s->evtchn_mask[0])); - /* * The following is basically the equivalent of * 'hw_resend_irq'. Just like a real IO-APIC we 'lose diff --git a/drivers/xen/fallback.c b/drivers/xen/fallback.c index 0ef7c4d40f86..b04fb64c5a91 100644 --- a/drivers/xen/fallback.c +++ b/drivers/xen/fallback.c @@ -44,7 +44,7 @@ int xen_event_channel_op_compat(int cmd, void *arg) } EXPORT_SYMBOL_GPL(xen_event_channel_op_compat); -int HYPERVISOR_physdev_op_compat(int cmd, void *arg) +int xen_physdev_op_compat(int cmd, void *arg) { struct physdev_op op; int rc; @@ -78,3 +78,4 @@ int HYPERVISOR_physdev_op_compat(int cmd, void *arg) return rc; } +EXPORT_SYMBOL_GPL(xen_physdev_op_compat); diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index f3278a6603ca..90e34ac7e522 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -505,6 +505,9 @@ static int __init xen_acpi_processor_init(void) pr = per_cpu(processors, i); perf = per_cpu_ptr(acpi_perf_data, i); + if (!pr) + continue; + pr->performance = perf; rc = acpi_processor_get_performance_info(pr); if (rc) diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 9204126f1560..a2278ba7fb27 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -17,6 +17,7 @@ #include <xen/events.h> #include <asm/xen/pci.h> #include <asm/xen/hypervisor.h> +#include <xen/interface/physdev.h> #include "pciback.h" #include "conf_space.h" #include "conf_space_quirks.h" @@ -85,37 +86,52 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev) static void pcistub_device_release(struct kref *kref) { struct pcistub_device *psdev; + struct pci_dev *dev; struct xen_pcibk_dev_data *dev_data; psdev = container_of(kref, struct pcistub_device, kref); - dev_data = pci_get_drvdata(psdev->dev); + dev = psdev->dev; + dev_data = pci_get_drvdata(dev); - dev_dbg(&psdev->dev->dev, "pcistub_device_release\n"); + dev_dbg(&dev->dev, "pcistub_device_release\n"); - xen_unregister_device_domain_owner(psdev->dev); + xen_unregister_device_domain_owner(dev); /* Call the reset function which does not take lock as this * is called from "unbind" which takes a device_lock mutex. */ - __pci_reset_function_locked(psdev->dev); - if (pci_load_and_free_saved_state(psdev->dev, - &dev_data->pci_saved_state)) { - dev_dbg(&psdev->dev->dev, "Could not reload PCI state\n"); - } else - pci_restore_state(psdev->dev); + __pci_reset_function_locked(dev); + if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state)) + dev_dbg(&dev->dev, "Could not reload PCI state\n"); + else + pci_restore_state(dev); + + if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { + struct physdev_pci_device ppdev = { + .seg = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn + }; + int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, + &ppdev); + + if (err) + dev_warn(&dev->dev, "MSI-X release failed (%d)\n", + err); + } /* Disable the device */ - xen_pcibk_reset_device(psdev->dev); + xen_pcibk_reset_device(dev); kfree(dev_data); - pci_set_drvdata(psdev->dev, NULL); + pci_set_drvdata(dev, NULL); /* Clean-up the device */ - xen_pcibk_config_free_dyn_fields(psdev->dev); - xen_pcibk_config_free_dev(psdev->dev); + xen_pcibk_config_free_dyn_fields(dev); + xen_pcibk_config_free_dev(dev); - psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; - pci_dev_put(psdev->dev); + dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; + pci_dev_put(dev); kfree(psdev); } @@ -355,6 +371,19 @@ static int pcistub_init_device(struct pci_dev *dev) if (err) goto config_release; + if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { + struct physdev_pci_device ppdev = { + .seg = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn + }; + + err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); + if (err) + dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", + err); + } + /* We need the device active to save the state. */ dev_dbg(&dev->dev, "save state of device\n"); pci_save_state(dev); diff --git a/firmware/Makefile b/firmware/Makefile index cbb09ce9730a..5d8ee1319b5c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -82,7 +82,7 @@ fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \ fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \ qlogic/12160.bin fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin -fw-shipped-$(CONFIG_INFINIBAND_QIB) += qlogic/sd7220.fw +fw-shipped-$(CONFIG_INFINIBAND_QIB) += intel/sd7220.fw fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp fw-shipped-$(CONFIG_SND_MAESTRO3) += ess/maestro3_assp_kernel.fw \ ess/maestro3_assp_minisrc.fw diff --git a/firmware/qlogic/sd7220.fw.ihex b/firmware/intel/sd7220.fw.ihex index a33636319112..a33636319112 100644 --- a/firmware/qlogic/sd7220.fw.ihex +++ b/firmware/intel/sd7220.fw.ihex diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index ecd25a1b4e51..ca9d8f1a3bb6 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -651,6 +651,8 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, if (tree_mod_dont_log(fs_info, NULL)) return 0; + __tree_mod_log_free_eb(fs_info, old_root); + ret = tree_mod_alloc(fs_info, flags, &tm); if (ret < 0) goto out; @@ -736,7 +738,7 @@ tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq) static noinline void tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, struct extent_buffer *src, unsigned long dst_offset, - unsigned long src_offset, int nr_items) + unsigned long src_offset, int nr_items, int log_removal) { int ret; int i; @@ -750,10 +752,12 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, } for (i = 0; i < nr_items; i++) { - ret = tree_mod_log_insert_key_locked(fs_info, src, - i + src_offset, - MOD_LOG_KEY_REMOVE); - BUG_ON(ret < 0); + if (log_removal) { + ret = tree_mod_log_insert_key_locked(fs_info, src, + i + src_offset, + MOD_LOG_KEY_REMOVE); + BUG_ON(ret < 0); + } ret = tree_mod_log_insert_key_locked(fs_info, dst, i + dst_offset, MOD_LOG_KEY_ADD); @@ -927,7 +931,6 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ret = btrfs_dec_ref(trans, root, buf, 1, 1); BUG_ON(ret); /* -ENOMEM */ } - tree_mod_log_free_eb(root->fs_info, buf); clean_tree_block(trans, root, buf); *last_ref = 1; } @@ -1046,6 +1049,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, btrfs_set_node_ptr_generation(parent, parent_slot, trans->transid); btrfs_mark_buffer_dirty(parent); + tree_mod_log_free_eb(root->fs_info, buf); btrfs_free_tree_block(trans, root, buf, parent_start, last_ref); } @@ -1750,7 +1754,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, goto enospc; } - tree_mod_log_free_eb(root->fs_info, root->node); tree_mod_log_set_root_pointer(root, child); rcu_assign_pointer(root->node, child); @@ -2995,7 +2998,7 @@ static int push_node_left(struct btrfs_trans_handle *trans, push_items = min(src_nritems - 8, push_items); tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0, - push_items); + push_items, 1); copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(dst_nritems), btrfs_node_key_ptr_offset(0), @@ -3066,7 +3069,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans, sizeof(struct btrfs_key_ptr)); tree_mod_log_eb_copy(root->fs_info, dst, src, 0, - src_nritems - push_items, push_items); + src_nritems - push_items, push_items, 1); copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(src_nritems - push_items), @@ -3218,12 +3221,18 @@ static noinline int split_node(struct btrfs_trans_handle *trans, int mid; int ret; u32 c_nritems; + int tree_mod_log_removal = 1; c = path->nodes[level]; WARN_ON(btrfs_header_generation(c) != trans->transid); if (c == root->node) { /* trying to split the root, lets make a new one */ ret = insert_new_root(trans, root, path, level + 1); + /* + * removal of root nodes has been logged by + * tree_mod_log_set_root_pointer due to locking + */ + tree_mod_log_removal = 0; if (ret) return ret; } else { @@ -3261,7 +3270,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans, (unsigned long)btrfs_header_chunk_tree_uuid(split), BTRFS_UUID_SIZE); - tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid); + tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid, + tree_mod_log_removal); copy_extent_buffer(split, c, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(mid), diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7d84651e850b..6d19a0a554aa 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1291,6 +1291,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, 0, objectid, NULL, 0, 0, 0); if (IS_ERR(leaf)) { ret = PTR_ERR(leaf); + leaf = NULL; goto fail; } @@ -1334,11 +1335,16 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, btrfs_tree_unlock(leaf); + return root; + fail: - if (ret) - return ERR_PTR(ret); + if (leaf) { + btrfs_tree_unlock(leaf); + free_extent_buffer(leaf); + } + kfree(root); - return root; + return ERR_PTR(ret); } static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, @@ -3253,7 +3259,7 @@ void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) if (btrfs_root_refs(&root->root_item) == 0) synchronize_srcu(&fs_info->subvol_srcu); - if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { + if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { btrfs_free_log(NULL, root); btrfs_free_log_root_tree(NULL, fs_info); } diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9ac2eca681eb..3d551231caba 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -257,7 +257,8 @@ static int exclude_super_stripes(struct btrfs_root *root, cache->bytes_super += stripe_len; ret = add_excluded_extent(root, cache->key.objectid, stripe_len); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; } for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { @@ -265,13 +266,17 @@ static int exclude_super_stripes(struct btrfs_root *root, ret = btrfs_rmap_block(&root->fs_info->mapping_tree, cache->key.objectid, bytenr, 0, &logical, &nr, &stripe_len); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; while (nr--) { cache->bytes_super += stripe_len; ret = add_excluded_extent(root, logical[nr], stripe_len); - BUG_ON(ret); /* -ENOMEM */ + if (ret) { + kfree(logical); + return ret; + } } kfree(logical); @@ -4438,7 +4443,7 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info) spin_lock(&sinfo->lock); spin_lock(&block_rsv->lock); - block_rsv->size = num_bytes; + block_rsv->size = min_t(u64, num_bytes, 512 * 1024 * 1024); num_bytes = sinfo->bytes_used + sinfo->bytes_pinned + sinfo->bytes_reserved + sinfo->bytes_readonly + @@ -4793,14 +4798,49 @@ out_fail: * If the inodes csum_bytes is the same as the original * csum_bytes then we know we haven't raced with any free()ers * so we can just reduce our inodes csum bytes and carry on. - * Otherwise we have to do the normal free thing to account for - * the case that the free side didn't free up its reserve - * because of this outstanding reservation. */ - if (BTRFS_I(inode)->csum_bytes == csum_bytes) + if (BTRFS_I(inode)->csum_bytes == csum_bytes) { calc_csum_metadata_size(inode, num_bytes, 0); - else - to_free = calc_csum_metadata_size(inode, num_bytes, 0); + } else { + u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes; + u64 bytes; + + /* + * This is tricky, but first we need to figure out how much we + * free'd from any free-ers that occured during this + * reservation, so we reset ->csum_bytes to the csum_bytes + * before we dropped our lock, and then call the free for the + * number of bytes that were freed while we were trying our + * reservation. + */ + bytes = csum_bytes - BTRFS_I(inode)->csum_bytes; + BTRFS_I(inode)->csum_bytes = csum_bytes; + to_free = calc_csum_metadata_size(inode, bytes, 0); + + + /* + * Now we need to see how much we would have freed had we not + * been making this reservation and our ->csum_bytes were not + * artificially inflated. + */ + BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes; + bytes = csum_bytes - orig_csum_bytes; + bytes = calc_csum_metadata_size(inode, bytes, 0); + + /* + * Now reset ->csum_bytes to what it should be. If bytes is + * more than to_free then we would have free'd more space had we + * not had an artificially high ->csum_bytes, so we need to free + * the remainder. If bytes is the same or less then we don't + * need to do anything, the other free-ers did the correct + * thing. + */ + BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes; + if (bytes > to_free) + to_free = bytes - to_free; + else + to_free = 0; + } spin_unlock(&BTRFS_I(inode)->lock); if (dropped) to_free += btrfs_calc_trans_metadata_size(root, dropped); @@ -7947,7 +7987,17 @@ int btrfs_read_block_groups(struct btrfs_root *root) * info has super bytes accounted for, otherwise we'll think * we have more space than we actually do. */ - exclude_super_stripes(root, cache); + ret = exclude_super_stripes(root, cache); + if (ret) { + /* + * We may have excluded something, so call this just in + * case. + */ + free_excluded_extents(root, cache); + kfree(cache->free_space_ctl); + kfree(cache); + goto error; + } /* * check for two cases, either we are full, and therefore @@ -8089,7 +8139,17 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, cache->last_byte_to_unpin = (u64)-1; cache->cached = BTRFS_CACHE_FINISHED; - exclude_super_stripes(root, cache); + ret = exclude_super_stripes(root, cache); + if (ret) { + /* + * We may have excluded something, so call this just in + * case. + */ + free_excluded_extents(root, cache); + kfree(cache->free_space_ctl); + kfree(cache); + return ret; + } add_new_free_space(cache, root->fs_info, chunk_offset, chunk_offset + size); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index f173c5af6461..cdee391fc7bf 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1257,6 +1257,39 @@ int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end) GFP_NOFS); } +int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end) +{ + unsigned long index = start >> PAGE_CACHE_SHIFT; + unsigned long end_index = end >> PAGE_CACHE_SHIFT; + struct page *page; + + while (index <= end_index) { + page = find_get_page(inode->i_mapping, index); + BUG_ON(!page); /* Pages should be in the extent_io_tree */ + clear_page_dirty_for_io(page); + page_cache_release(page); + index++; + } + return 0; +} + +int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end) +{ + unsigned long index = start >> PAGE_CACHE_SHIFT; + unsigned long end_index = end >> PAGE_CACHE_SHIFT; + struct page *page; + + while (index <= end_index) { + page = find_get_page(inode->i_mapping, index); + BUG_ON(!page); /* Pages should be in the extent_io_tree */ + account_page_redirty(page); + __set_page_dirty_nobuffers(page); + page_cache_release(page); + index++; + } + return 0; +} + /* * helper function to set both pages and extents in the tree writeback */ diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 6068a1985560..258c92156857 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -325,6 +325,8 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, unsigned long *map_len); int extent_range_uptodate(struct extent_io_tree *tree, u64 start, u64 end); +int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end); +int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end); int extent_clear_unlock_delalloc(struct inode *inode, struct extent_io_tree *tree, u64 start, u64 end, struct page *locked_page, diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index ec160202be3e..c4628a201cb3 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -118,9 +118,11 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); csums_in_item /= csum_size; - if (csum_offset >= csums_in_item) { + if (csum_offset == csums_in_item) { ret = -EFBIG; goto fail; + } else if (csum_offset > csums_in_item) { + goto fail; } } item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); @@ -728,7 +730,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, return -ENOMEM; sector_sum = sums->sums; - trans->adding_csums = 1; again: next_offset = (u64)-1; found_next = 0; @@ -899,7 +900,6 @@ next_sector: goto again; } out: - trans->adding_csums = 0; btrfs_free_path(path); return ret; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 5b4ea5f55b8f..ade03e6f7bd2 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2142,6 +2142,7 @@ static long btrfs_fallocate(struct file *file, int mode, { struct inode *inode = file_inode(file); struct extent_state *cached_state = NULL; + struct btrfs_root *root = BTRFS_I(inode)->root; u64 cur_offset; u64 last_byte; u64 alloc_start; @@ -2169,6 +2170,11 @@ static long btrfs_fallocate(struct file *file, int mode, ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start); if (ret) return ret; + if (root->fs_info->quota_enabled) { + ret = btrfs_qgroup_reserve(root, alloc_end - alloc_start); + if (ret) + goto out_reserve_fail; + } /* * wait for ordered IO before we have any locks. We'll loop again @@ -2272,6 +2278,9 @@ static long btrfs_fallocate(struct file *file, int mode, &cached_state, GFP_NOFS); out: mutex_unlock(&inode->i_mutex); + if (root->fs_info->quota_enabled) + btrfs_qgroup_free(root, alloc_end - alloc_start); +out_reserve_fail: /* Let go of our reservation. */ btrfs_free_reserved_data_space(inode, alloc_end - alloc_start); return ret; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ca1b767d51f7..09c58a35b429 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -353,6 +353,7 @@ static noinline int compress_file_range(struct inode *inode, int i; int will_compress; int compress_type = root->fs_info->compress_type; + int redirty = 0; /* if this is a small write inside eof, kick off a defrag */ if ((end - start + 1) < 16 * 1024 && @@ -415,6 +416,17 @@ again: if (BTRFS_I(inode)->force_compress) compress_type = BTRFS_I(inode)->force_compress; + /* + * we need to call clear_page_dirty_for_io on each + * page in the range. Otherwise applications with the file + * mmap'd can wander in and change the page contents while + * we are compressing them. + * + * If the compression fails for any reason, we set the pages + * dirty again later on. + */ + extent_range_clear_dirty_for_io(inode, start, end); + redirty = 1; ret = btrfs_compress_pages(compress_type, inode->i_mapping, start, total_compressed, pages, @@ -554,6 +566,8 @@ cleanup_and_bail_uncompressed: __set_page_dirty_nobuffers(locked_page); /* unlocked later on in the async handlers */ } + if (redirty) + extent_range_redirty_for_io(inode, start, end); add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0, BTRFS_COMPRESS_NONE); *num_added += 1; @@ -1743,8 +1757,10 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, struct btrfs_ordered_sum *sum; list_for_each_entry(sum, list, list) { + trans->adding_csums = 1; btrfs_csum_file_blocks(trans, BTRFS_I(inode)->root->fs_info->csum_root, sum); + trans->adding_csums = 0; } return 0; } @@ -3679,11 +3695,9 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir, * 1 for the dir item * 1 for the dir index * 1 for the inode ref - * 1 for the inode ref in the tree log - * 2 for the dir entries in the log * 1 for the inode */ - trans = btrfs_start_transaction(root, 8); + trans = btrfs_start_transaction(root, 5); if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC) return trans; @@ -8127,7 +8141,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, * inodes. So 5 * 2 is 10, plus 1 for the new link, so 11 total items * should cover the worst case number of items we'll modify. */ - trans = btrfs_start_transaction(root, 20); + trans = btrfs_start_transaction(root, 11); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_notrans; diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index dc08d77b717e..005c45db699e 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -557,6 +557,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput) INIT_LIST_HEAD(&splice); INIT_LIST_HEAD(&works); + mutex_lock(&root->fs_info->ordered_operations_mutex); spin_lock(&root->fs_info->ordered_extent_lock); list_splice_init(&root->fs_info->ordered_extents, &splice); while (!list_empty(&splice)) { @@ -600,6 +601,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput) cond_resched(); } + mutex_unlock(&root->fs_info->ordered_operations_mutex); } /* diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 5471e47d6559..b44124dd2370 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1153,7 +1153,7 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, ret = btrfs_find_all_roots(trans, fs_info, node->bytenr, sgn > 0 ? node->seq - 1 : node->seq, &roots); if (ret < 0) - goto out; + return ret; spin_lock(&fs_info->qgroup_lock); quota_root = fs_info->quota_root; @@ -1275,7 +1275,6 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, ret = 0; unlock: spin_unlock(&fs_info->qgroup_lock); -out: ulist_free(roots); ulist_free(tmp); diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 53c3501fa4ca..85e072b956d5 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -542,7 +542,6 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) eb = path->nodes[0]; ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); item_size = btrfs_item_size_nr(eb, path->slots[0]); - btrfs_release_path(path); if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { do { @@ -558,7 +557,9 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) ret < 0 ? -1 : ref_level, ret < 0 ? -1 : ref_root); } while (ret != 1); + btrfs_release_path(path); } else { + btrfs_release_path(path); swarn.path = path; swarn.dev = dev; iterate_extent_inodes(fs_info, found_key.objectid, diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index f7a8b861058b..c85e7c6b4598 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -3945,12 +3945,10 @@ static int is_extent_unchanged(struct send_ctx *sctx, found_key.type != key.type) { key.offset += right_len; break; - } else { - if (found_key.offset != key.offset + right_len) { - /* Should really not happen */ - ret = -EIO; - goto out; - } + } + if (found_key.offset != key.offset + right_len) { + ret = 0; + goto out; } key = found_key; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5989a92236f7..2854c824ab64 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4935,7 +4935,18 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, em = lookup_extent_mapping(em_tree, chunk_start, 1); read_unlock(&em_tree->lock); - BUG_ON(!em || em->start != chunk_start); + if (!em) { + printk(KERN_ERR "btrfs: couldn't find em for chunk %Lu\n", + chunk_start); + return -EIO; + } + + if (em->start != chunk_start) { + printk(KERN_ERR "btrfs: bad chunk start, em=%Lu, wanted=%Lu\n", + em->start, chunk_start); + free_extent_map(em); + return -EIO; + } map = (struct map_lookup *)em->bdev; length = em->len; diff --git a/fs/dcache.c b/fs/dcache.c index fbfae008ba44..e8bc3420d63e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2542,7 +2542,6 @@ static int prepend_path(const struct path *path, bool slash = false; int error = 0; - br_read_lock(&vfsmount_lock); while (dentry != root->dentry || vfsmnt != root->mnt) { struct dentry * parent; @@ -2572,8 +2571,6 @@ static int prepend_path(const struct path *path, if (!error && !slash) error = prepend(buffer, buflen, "/", 1); -out: - br_read_unlock(&vfsmount_lock); return error; global_root: @@ -2590,7 +2587,7 @@ global_root: error = prepend(buffer, buflen, "/", 1); if (!error) error = is_mounted(vfsmnt) ? 1 : 2; - goto out; + return error; } /** @@ -2617,9 +2614,11 @@ char *__d_path(const struct path *path, int error; prepend(&res, &buflen, "\0", 1); + br_read_lock(&vfsmount_lock); write_seqlock(&rename_lock); error = prepend_path(path, root, &res, &buflen); write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); if (error < 0) return ERR_PTR(error); @@ -2636,9 +2635,11 @@ char *d_absolute_path(const struct path *path, int error; prepend(&res, &buflen, "\0", 1); + br_read_lock(&vfsmount_lock); write_seqlock(&rename_lock); error = prepend_path(path, &root, &res, &buflen); write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); if (error > 1) error = -EINVAL; @@ -2702,11 +2703,13 @@ char *d_path(const struct path *path, char *buf, int buflen) return path->dentry->d_op->d_dname(path->dentry, buf, buflen); get_fs_root(current->fs, &root); + br_read_lock(&vfsmount_lock); write_seqlock(&rename_lock); error = path_with_deleted(path, &root, &res, &buflen); + write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); if (error < 0) res = ERR_PTR(error); - write_sequnlock(&rename_lock); path_put(&root); return res; } @@ -2830,6 +2833,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) get_fs_root_and_pwd(current->fs, &root, &pwd); error = -ENOENT; + br_read_lock(&vfsmount_lock); write_seqlock(&rename_lock); if (!d_unlinked(pwd.dentry)) { unsigned long len; @@ -2839,6 +2843,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) prepend(&cwd, &buflen, "\0", 1); error = prepend_path(&pwd, &root, &cwd, &buflen); write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); if (error < 0) goto out; @@ -2859,6 +2864,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) } } else { write_sequnlock(&rename_lock); + br_read_unlock(&vfsmount_lock); } out: diff --git a/fs/internal.h b/fs/internal.h index 507141fceb99..4be78237d896 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -125,3 +125,8 @@ extern int invalidate_inodes(struct super_block *, bool); * dcache.c */ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); + +/* + * read_write.c + */ +extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); diff --git a/fs/namespace.c b/fs/namespace.c index 50ca17d3cb45..d581e45c0a9f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -798,6 +798,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, } mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; + /* Don't allow unprivileged users to change mount flags */ + if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) + mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; + atomic_inc(&sb->s_active); mnt->mnt.mnt_sb = sb; mnt->mnt.mnt_root = dget(root); @@ -1713,6 +1717,9 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) if (readonly_request == __mnt_is_readonly(mnt)) return 0; + if (mnt->mnt_flags & MNT_LOCK_READONLY) + return -EPERM; + if (readonly_request) error = mnt_make_readonly(real_mount(mnt)); else @@ -2339,7 +2346,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, /* First pass: copy the tree topology */ copy_flags = CL_COPY_ALL | CL_EXPIRE; if (user_ns != mnt_ns->user_ns) - copy_flags |= CL_SHARED_TO_SLAVE; + copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED; new = copy_tree(old, old->mnt.mnt_root, copy_flags); if (IS_ERR(new)) { up_write(&namespace_sem); @@ -2732,6 +2739,51 @@ bool our_mnt(struct vfsmount *mnt) return check_mnt(real_mount(mnt)); } +bool current_chrooted(void) +{ + /* Does the current process have a non-standard root */ + struct path ns_root; + struct path fs_root; + bool chrooted; + + /* Find the namespace root */ + ns_root.mnt = ¤t->nsproxy->mnt_ns->root->mnt; + ns_root.dentry = ns_root.mnt->mnt_root; + path_get(&ns_root); + while (d_mountpoint(ns_root.dentry) && follow_down_one(&ns_root)) + ; + + get_fs_root(current->fs, &fs_root); + + chrooted = !path_equal(&fs_root, &ns_root); + + path_put(&fs_root); + path_put(&ns_root); + + return chrooted; +} + +void update_mnt_policy(struct user_namespace *userns) +{ + struct mnt_namespace *ns = current->nsproxy->mnt_ns; + struct mount *mnt; + + down_read(&namespace_sem); + list_for_each_entry(mnt, &ns->list, mnt_list) { + switch (mnt->mnt.mnt_sb->s_magic) { + case SYSFS_MAGIC: + userns->may_mount_sysfs = true; + break; + case PROC_SUPER_MAGIC: + userns->may_mount_proc = true; + break; + } + if (userns->may_mount_sysfs && userns->may_mount_proc) + break; + } + up_read(&namespace_sem); +} + static void *mntns_get(struct task_struct *task) { struct mnt_namespace *ns = NULL; diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index 737d839bc17b..6fc7b5cae92b 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c @@ -55,7 +55,8 @@ static void dev_remove(struct net *net, dev_t dev) bl_pipe_msg.bl_wq = &nn->bl_wq; memset(msg, 0, sizeof(*msg)); - msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); + msg->len = sizeof(bl_msg) + bl_msg.totallen; + msg->data = kzalloc(msg->len, GFP_NOFS); if (!msg->data) goto out; @@ -66,7 +67,6 @@ static void dev_remove(struct net *net, dev_t dev) memcpy(msg->data, &bl_msg, sizeof(bl_msg)); dataptr = (uint8_t *) msg->data; memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request)); - msg->len = sizeof(bl_msg) + bl_msg.totallen; add_wait_queue(&nn->bl_wq, &wq); if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) { diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index dc0f98dfa717..c516da5873fd 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -726,9 +726,9 @@ out1: return ret; } -static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data) +static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen) { - return key_instantiate_and_link(key, data, strlen(data) + 1, + return key_instantiate_and_link(key, data, datalen, id_resolver_cache->thread_keyring, authkey); } @@ -738,6 +738,7 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, struct key *key, struct key *authkey) { char id_str[NFS_UINT_MAXLEN]; + size_t len; int ret = -ENOKEY; /* ret = -ENOKEY */ @@ -747,13 +748,15 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, case IDMAP_CONV_NAMETOID: if (strcmp(upcall->im_name, im->im_name) != 0) break; - sprintf(id_str, "%d", im->im_id); - ret = nfs_idmap_instantiate(key, authkey, id_str); + /* Note: here we store the NUL terminator too */ + len = sprintf(id_str, "%d", im->im_id) + 1; + ret = nfs_idmap_instantiate(key, authkey, id_str, len); break; case IDMAP_CONV_IDTONAME: if (upcall->im_id != im->im_id) break; - ret = nfs_idmap_instantiate(key, authkey, im->im_name); + len = strlen(im->im_name); + ret = nfs_idmap_instantiate(key, authkey, im->im_name, len); break; default: ret = -EINVAL; diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 49eeb044c109..4fb234d3aefb 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -129,7 +129,6 @@ static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo) { if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) return; - clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); pnfs_return_layout(inode); } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b2671cb0f901..26431cf62ddb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2632,7 +2632,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, int status; if (pnfs_ld_layoutret_on_setattr(inode)) - pnfs_return_layout(inode); + pnfs_commit_and_return_layout(inode); nfs_fattr_init(fattr); @@ -6416,22 +6416,8 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) static void nfs4_layoutcommit_release(void *calldata) { struct nfs4_layoutcommit_data *data = calldata; - struct pnfs_layout_segment *lseg, *tmp; - unsigned long *bitlock = &NFS_I(data->args.inode)->flags; pnfs_cleanup_layoutcommit(data); - /* Matched by references in pnfs_set_layoutcommit */ - list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) { - list_del_init(&lseg->pls_lc_list); - if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, - &lseg->pls_flags)) - pnfs_put_lseg(lseg); - } - - clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); - smp_mb__after_clear_bit(); - wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); - put_rpccred(data->cred); kfree(data); } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 48ac5aad6258..4bdffe0ba025 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -417,6 +417,16 @@ should_free_lseg(struct pnfs_layout_range *lseg_range, lo_seg_intersecting(lseg_range, recall_range); } +static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg, + struct list_head *tmp_list) +{ + if (!atomic_dec_and_test(&lseg->pls_refcount)) + return false; + pnfs_layout_remove_lseg(lseg->pls_layout, lseg); + list_add(&lseg->pls_list, tmp_list); + return true; +} + /* Returns 1 if lseg is removed from list, 0 otherwise */ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, struct list_head *tmp_list) @@ -430,11 +440,8 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, */ dprintk("%s: lseg %p ref %d\n", __func__, lseg, atomic_read(&lseg->pls_refcount)); - if (atomic_dec_and_test(&lseg->pls_refcount)) { - pnfs_layout_remove_lseg(lseg->pls_layout, lseg); - list_add(&lseg->pls_list, tmp_list); + if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list)) rv = 1; - } } return rv; } @@ -777,6 +784,21 @@ send_layoutget(struct pnfs_layout_hdr *lo, return lseg; } +static void pnfs_clear_layoutcommit(struct inode *inode, + struct list_head *head) +{ + struct nfs_inode *nfsi = NFS_I(inode); + struct pnfs_layout_segment *lseg, *tmp; + + if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) + return; + list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) { + if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) + continue; + pnfs_lseg_dec_and_remove_zero(lseg, head); + } +} + /* * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr * when the layout segment list is empty. @@ -808,6 +830,7 @@ _pnfs_return_layout(struct inode *ino) /* Reference matched in nfs4_layoutreturn_release */ pnfs_get_layout_hdr(lo); empty = list_empty(&lo->plh_segs); + pnfs_clear_layoutcommit(ino, &tmp_list); pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL); /* Don't send a LAYOUTRETURN if list was initially empty */ if (empty) { @@ -820,8 +843,6 @@ _pnfs_return_layout(struct inode *ino) spin_unlock(&ino->i_lock); pnfs_free_lseg_list(&tmp_list); - WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)); - lrp = kzalloc(sizeof(*lrp), GFP_KERNEL); if (unlikely(lrp == NULL)) { status = -ENOMEM; @@ -845,6 +866,33 @@ out: } EXPORT_SYMBOL_GPL(_pnfs_return_layout); +int +pnfs_commit_and_return_layout(struct inode *inode) +{ + struct pnfs_layout_hdr *lo; + int ret; + + spin_lock(&inode->i_lock); + lo = NFS_I(inode)->layout; + if (lo == NULL) { + spin_unlock(&inode->i_lock); + return 0; + } + pnfs_get_layout_hdr(lo); + /* Block new layoutgets and read/write to ds */ + lo->plh_block_lgets++; + spin_unlock(&inode->i_lock); + filemap_fdatawait(inode->i_mapping); + ret = pnfs_layoutcommit_inode(inode, true); + if (ret == 0) + ret = _pnfs_return_layout(inode); + spin_lock(&inode->i_lock); + lo->plh_block_lgets--; + spin_unlock(&inode->i_lock); + pnfs_put_layout_hdr(lo); + return ret; +} + bool pnfs_roc(struct inode *ino) { struct pnfs_layout_hdr *lo; @@ -1458,7 +1506,6 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) dprintk("pnfs write error = %d\n", hdr->pnfs_error); if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & PNFS_LAYOUTRET_ON_ERROR) { - clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); pnfs_return_layout(hdr->inode); } if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) @@ -1613,7 +1660,6 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) dprintk("pnfs read error = %d\n", hdr->pnfs_error); if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & PNFS_LAYOUTRET_ON_ERROR) { - clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); pnfs_return_layout(hdr->inode); } if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) @@ -1746,11 +1792,27 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp) list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { if (lseg->pls_range.iomode == IOMODE_RW && - test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) + test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) list_add(&lseg->pls_lc_list, listp); } } +static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp) +{ + struct pnfs_layout_segment *lseg, *tmp; + unsigned long *bitlock = &NFS_I(inode)->flags; + + /* Matched by references in pnfs_set_layoutcommit */ + list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) { + list_del_init(&lseg->pls_lc_list); + pnfs_put_lseg(lseg); + } + + clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); + smp_mb__after_clear_bit(); + wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); +} + void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) { pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode); @@ -1795,6 +1857,7 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data) if (nfss->pnfs_curr_ld->cleanup_layoutcommit) nfss->pnfs_curr_ld->cleanup_layoutcommit(data); + pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list); } /* diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 94ba80417748..f5f8a470a647 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -219,6 +219,7 @@ void pnfs_set_layoutcommit(struct nfs_write_data *wdata); void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data); int pnfs_layoutcommit_inode(struct inode *inode, bool sync); int _pnfs_return_layout(struct inode *); +int pnfs_commit_and_return_layout(struct inode *); void pnfs_ld_write_done(struct nfs_write_data *); void pnfs_ld_read_done(struct nfs_read_data *); struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, @@ -407,6 +408,11 @@ static inline int pnfs_return_layout(struct inode *ino) return 0; } +static inline int pnfs_commit_and_return_layout(struct inode *inode) +{ + return 0; +} + static inline bool pnfs_ld_layoutret_on_setattr(struct inode *inode) { diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 62c1ee128aeb..ca05f6dc3544 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -102,7 +102,8 @@ nfsd_reply_cache_free_locked(struct svc_cacherep *rp) { if (rp->c_type == RC_REPLBUFF) kfree(rp->c_replvec.iov_base); - hlist_del(&rp->c_hash); + if (!hlist_unhashed(&rp->c_hash)) + hlist_del(&rp->c_hash); list_del(&rp->c_lru); --num_drc_entries; kmem_cache_free(drc_slab, rp); @@ -118,6 +119,10 @@ nfsd_reply_cache_free(struct svc_cacherep *rp) int nfsd_reply_cache_init(void) { + INIT_LIST_HEAD(&lru_head); + max_drc_entries = nfsd_cache_size_limit(); + num_drc_entries = 0; + register_shrinker(&nfsd_reply_cache_shrinker); drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep), 0, 0, NULL); @@ -128,10 +133,6 @@ int nfsd_reply_cache_init(void) if (!cache_hash) goto out_nomem; - INIT_LIST_HEAD(&lru_head); - max_drc_entries = nfsd_cache_size_limit(); - num_drc_entries = 0; - return 0; out_nomem: printk(KERN_ERR "nfsd: failed to allocate reply cache\n"); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 2a7eb536de0b..2b2e2396a869 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1013,6 +1013,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, int host_err; int stable = *stablep; int use_wgather; + loff_t pos = offset; dentry = file->f_path.dentry; inode = dentry->d_inode; @@ -1025,7 +1026,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); - host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); + host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &pos); set_fs(oldfs); if (host_err < 0) goto out_nfserr; diff --git a/fs/pnode.c b/fs/pnode.c index 3e000a51ac0d..8b29d2164da6 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -9,6 +9,7 @@ #include <linux/mnt_namespace.h> #include <linux/mount.h> #include <linux/fs.h> +#include <linux/nsproxy.h> #include "internal.h" #include "pnode.h" @@ -220,6 +221,7 @@ static struct mount *get_source(struct mount *dest, int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, struct mount *source_mnt, struct list_head *tree_list) { + struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; struct mount *m, *child; int ret = 0; struct mount *prev_dest_mnt = dest_mnt; @@ -237,6 +239,10 @@ int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); + /* Notice when we are propagating across user namespaces */ + if (m->mnt_ns->user_ns != user_ns) + type |= CL_UNPRIVILEGED; + child = copy_tree(source, source->mnt.mnt_root, type); if (IS_ERR(child)) { ret = PTR_ERR(child); diff --git a/fs/pnode.h b/fs/pnode.h index 19b853a3445c..a0493d5ebfbf 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -23,6 +23,7 @@ #define CL_MAKE_SHARED 0x08 #define CL_PRIVATE 0x10 #define CL_SHARED_TO_SLAVE 0x20 +#define CL_UNPRIVILEGED 0x40 static inline void set_mnt_shared(struct mount *mnt) { diff --git a/fs/proc/root.c b/fs/proc/root.c index c6e9fac26bac..9c7fab1d23f0 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -16,6 +16,7 @@ #include <linux/sched.h> #include <linux/module.h> #include <linux/bitops.h> +#include <linux/user_namespace.h> #include <linux/mount.h> #include <linux/pid_namespace.h> #include <linux/parser.h> @@ -108,6 +109,9 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, } else { ns = task_active_pid_ns(current); options = data; + + if (!current_user_ns()->may_mount_proc) + return ERR_PTR(-EPERM); } sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); diff --git a/fs/read_write.c b/fs/read_write.c index a698eff457fb..e6ddc8dceb96 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -17,6 +17,7 @@ #include <linux/splice.h> #include <linux/compat.h> #include "read_write.h" +#include "internal.h" #include <asm/uaccess.h> #include <asm/unistd.h> @@ -417,6 +418,33 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof EXPORT_SYMBOL(do_sync_write); +ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) +{ + mm_segment_t old_fs; + const char __user *p; + ssize_t ret; + + if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write)) + return -EINVAL; + + old_fs = get_fs(); + set_fs(get_ds()); + p = (__force const char __user *)buf; + if (count > MAX_RW_COUNT) + count = MAX_RW_COUNT; + if (file->f_op->write) + ret = file->f_op->write(file, p, count, pos); + else + ret = do_sync_write(file, p, count, pos); + set_fs(old_fs); + if (ret > 0) { + fsnotify_modify(file); + add_wchar(current, ret); + } + inc_syscw(current); + return ret; +} + ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { ssize_t ret; diff --git a/fs/splice.c b/fs/splice.c index 718bd0056384..29e394e49ddd 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -31,6 +31,7 @@ #include <linux/security.h> #include <linux/gfp.h> #include <linux/socket.h> +#include "internal.h" /* * Attempt to steal a page from a pipe buffer. This should perhaps go into @@ -1048,9 +1049,10 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, { int ret; void *data; + loff_t tmp = sd->pos; data = buf->ops->map(pipe, buf, 0); - ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos); + ret = __kernel_write(sd->u.file, data + buf->offset, sd->len, &tmp); buf->ops->unmap(pipe, buf, data); return ret; diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 2fbdff6be25c..e14512678c9b 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1020,6 +1020,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) ino = parent_sd->s_ino; if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; + else + return 0; } if (filp->f_pos == 1) { if (parent_sd->s_parent) @@ -1028,6 +1030,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) ino = parent_sd->s_ino; if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; + else + return 0; } mutex_lock(&sysfs_mutex); for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos); @@ -1058,10 +1062,21 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) return 0; } +static loff_t sysfs_dir_llseek(struct file *file, loff_t offset, int whence) +{ + struct inode *inode = file_inode(file); + loff_t ret; + + mutex_lock(&inode->i_mutex); + ret = generic_file_llseek(file, offset, whence); + mutex_unlock(&inode->i_mutex); + + return ret; +} const struct file_operations sysfs_dir_operations = { .read = generic_read_dir, .readdir = sysfs_readdir, .release = sysfs_dir_release, - .llseek = generic_file_llseek, + .llseek = sysfs_dir_llseek, }; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8d924b5ec733..afd83273e6ce 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/magic.h> #include <linux/slab.h> +#include <linux/user_namespace.h> #include "sysfs.h" @@ -111,6 +112,9 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, struct super_block *sb; int error; + if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs) + return ERR_PTR(-EPERM); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 9c7f5807824b..dd7adff76e81 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -152,7 +152,7 @@ struct clk { }, \ .reg = _reg, \ .shift = _shift, \ - .width = _width, \ + .mask = BIT(_width) - 1, \ .flags = _mux_flags, \ .lock = _lock, \ }; \ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 7f197d7addb0..1f0352802794 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -45,6 +45,14 @@ struct clk_hw; * undo any work done in the @prepare callback. Called with * prepare_lock held. * + * @is_prepared: Queries the hardware to determine if the clock is prepared. + * This function is allowed to sleep. Optional, if this op is not + * set then the prepare count will be used. + * + * @unprepare_unused: Unprepare the clock atomically. Only called from + * clk_disable_unused for prepare clocks with special needs. + * Called with prepare mutex held. This function may sleep. + * * @enable: Enable the clock atomically. This must not return until the * clock is generating a valid clock signal, usable by consumer * devices. Called with enable_lock held. This function must not @@ -108,6 +116,8 @@ struct clk_hw; struct clk_ops { int (*prepare)(struct clk_hw *hw); void (*unprepare)(struct clk_hw *hw); + int (*is_prepared)(struct clk_hw *hw); + void (*unprepare_unused)(struct clk_hw *hw); int (*enable)(struct clk_hw *hw); void (*disable)(struct clk_hw *hw); int (*is_enabled)(struct clk_hw *hw); @@ -287,8 +297,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name, struct clk_mux { struct clk_hw hw; void __iomem *reg; + u32 *table; + u32 mask; u8 shift; - u8 width; u8 flags; spinlock_t *lock; }; @@ -297,11 +308,17 @@ struct clk_mux { #define CLK_MUX_INDEX_BIT BIT(1) extern const struct clk_ops clk_mux_ops; + struct clk *clk_register_mux(struct device *dev, const char *name, const char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock); +struct clk *clk_register_mux_table(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned long flags, + void __iomem *reg, u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table, spinlock_t *lock); + /** * struct clk_fixed_factor - fixed multiplier and divider clock * @@ -325,6 +342,37 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned int mult, unsigned int div); +/*** + * struct clk_composite - aggregate clock of mux, divider and gate clocks + * + * @hw: handle between common and hardware-specific interfaces + * @mux_hw: handle between composite and hardware-specifix mux clock + * @div_hw: handle between composite and hardware-specifix divider clock + * @gate_hw: handle between composite and hardware-specifix gate clock + * @mux_ops: clock ops for mux + * @div_ops: clock ops for divider + * @gate_ops: clock ops for gate + */ +struct clk_composite { + struct clk_hw hw; + struct clk_ops ops; + + struct clk_hw *mux_hw; + struct clk_hw *div_hw; + struct clk_hw *gate_hw; + + const struct clk_ops *mux_ops; + const struct clk_ops *div_ops; + const struct clk_ops *gate_ops; +}; + +struct clk *clk_register_composite(struct device *dev, const char *name, + const char **parent_names, int num_parents, + struct clk_hw *mux_hw, const struct clk_ops *mux_ops, + struct clk_hw *div_hw, const struct clk_ops *div_ops, + struct clk_hw *gate_hw, const struct clk_ops *gate_ops, + unsigned long flags); + /** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock @@ -351,6 +399,7 @@ unsigned int __clk_get_enable_count(struct clk *clk); unsigned int __clk_get_prepare_count(struct clk *clk); unsigned long __clk_get_rate(struct clk *clk); unsigned long __clk_get_flags(struct clk *clk); +bool __clk_is_prepared(struct clk *clk); bool __clk_is_enabled(struct clk *clk); struct clk *__clk_lookup(const char *name); diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h new file mode 100644 index 000000000000..e074fdd5a236 --- /dev/null +++ b/include/linux/clk/sunxi.h @@ -0,0 +1,22 @@ +/* + * Copyright 2012 Maxime Ripard + * + * Maxime Ripard <maxime.ripard@free-electrons.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. + */ + +#ifndef __LINUX_CLK_SUNXI_H_ +#define __LINUX_CLK_SUNXI_H_ + +void __init sunxi_init_clocks(void); + +#endif diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 404d6f940872..642789baec74 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -123,5 +123,6 @@ static inline void tegra_cpu_clock_resume(void) void tegra_periph_reset_deassert(struct clk *c); void tegra_periph_reset_assert(struct clk *c); void tegra_clocks_init(void); +void tegra_clocks_apply_init_table(void); #endif /* __LINUX_CLK_TEGRA_H_ */ diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 27cfda427dd9..192d6d1771ee 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -332,15 +332,23 @@ extern int clocksource_mmio_init(void __iomem *, const char *, extern int clocksource_i8253_init(void); +struct device_node; +typedef void(*clocksource_of_init_fn)(struct device_node *); #ifdef CONFIG_CLKSRC_OF extern void clocksource_of_init(void); #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ static const struct of_device_id __clksrc_of_table_##name \ __used __section(__clksrc_of_table) \ - = { .compatible = compat, .data = fn }; + = { .compatible = compat, \ + .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn } #else -#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) +static inline void clocksource_of_init(void) {} +#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ + static const struct of_device_id __clksrc_of_table_##name \ + __attribute__((unused)) \ + = { .compatible = compat, \ + .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn } #endif #endif /* _LINUX_CLOCKSOURCE_H */ diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index a975de1ff59f..3bd46f766751 100644 --- a/include/linux/debug_locks.h +++ b/include/linux/debug_locks.h @@ -51,7 +51,7 @@ struct task_struct; extern void debug_show_all_locks(void); extern void debug_show_held_locks(struct task_struct *task); extern void debug_check_no_locks_freed(const void *from, unsigned long len); -extern void debug_check_no_locks_held(void); +extern void debug_check_no_locks_held(struct task_struct *task); #else static inline void debug_show_all_locks(void) { @@ -67,7 +67,7 @@ debug_check_no_locks_freed(const void *from, unsigned long len) } static inline void -debug_check_no_locks_held(void) +debug_check_no_locks_held(struct task_struct *task) { } #endif diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 043a5cf8b5ba..e70df40d84f6 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -3,7 +3,6 @@ #ifndef FREEZER_H_INCLUDED #define FREEZER_H_INCLUDED -#include <linux/debug_locks.h> #include <linux/sched.h> #include <linux/wait.h> #include <linux/atomic.h> @@ -49,8 +48,6 @@ extern void thaw_kernel_threads(void); static inline bool try_to_freeze(void) { - if (!(current->flags & PF_NOFREEZE)) - debug_check_no_locks_held(); might_sleep(); if (likely(!freezing(current))) return false; diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index 729eded4b24f..2b93a9a5a1e6 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h @@ -50,4 +50,6 @@ static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root, spin_unlock(&fs->lock); } +extern bool current_chrooted(void); + #endif /* _LINUX_FS_STRUCT_H */ diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h index 5b18ecde69b5..1aa4f13cdfa6 100644 --- a/include/linux/mfd/max77693-private.h +++ b/include/linux/mfd/max77693-private.h @@ -106,6 +106,29 @@ enum max77693_muic_reg { MAX77693_MUIC_REG_END, }; +/* MAX77693 INTMASK1~2 Register */ +#define INTMASK1_ADC1K_SHIFT 3 +#define INTMASK1_ADCERR_SHIFT 2 +#define INTMASK1_ADCLOW_SHIFT 1 +#define INTMASK1_ADC_SHIFT 0 +#define INTMASK1_ADC1K_MASK (1 << INTMASK1_ADC1K_SHIFT) +#define INTMASK1_ADCERR_MASK (1 << INTMASK1_ADCERR_SHIFT) +#define INTMASK1_ADCLOW_MASK (1 << INTMASK1_ADCLOW_SHIFT) +#define INTMASK1_ADC_MASK (1 << INTMASK1_ADC_SHIFT) + +#define INTMASK2_VIDRM_SHIFT 5 +#define INTMASK2_VBVOLT_SHIFT 4 +#define INTMASK2_DXOVP_SHIFT 3 +#define INTMASK2_DCDTMR_SHIFT 2 +#define INTMASK2_CHGDETRUN_SHIFT 1 +#define INTMASK2_CHGTYP_SHIFT 0 +#define INTMASK2_VIDRM_MASK (1 << INTMASK2_VIDRM_SHIFT) +#define INTMASK2_VBVOLT_MASK (1 << INTMASK2_VBVOLT_SHIFT) +#define INTMASK2_DXOVP_MASK (1 << INTMASK2_DXOVP_SHIFT) +#define INTMASK2_DCDTMR_MASK (1 << INTMASK2_DCDTMR_SHIFT) +#define INTMASK2_CHGDETRUN_MASK (1 << INTMASK2_CHGDETRUN_SHIFT) +#define INTMASK2_CHGTYP_MASK (1 << INTMASK2_CHGTYP_SHIFT) + /* MAX77693 MUIC - STATUS1~3 Register */ #define STATUS1_ADC_SHIFT (0) #define STATUS1_ADCLOW_SHIFT (5) diff --git a/include/linux/mm.h b/include/linux/mm.h index 7acc9dc73c9f..e19ff30ad0a2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -87,7 +87,6 @@ extern unsigned int kobjsize(const void *objp); #define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */ #define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */ -#define VM_POPULATE 0x00001000 #define VM_LOCKED 0x00002000 #define VM_IO 0x00004000 /* Memory mapped I/O or similar */ diff --git a/include/linux/mman.h b/include/linux/mman.h index 61c7a87e5d2b..9aa863da287f 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -79,8 +79,6 @@ calc_vm_flag_bits(unsigned long flags) { return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | _calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) | - ((flags & MAP_LOCKED) ? (VM_LOCKED | VM_POPULATE) : 0) | - (((flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE) ? - VM_POPULATE : 0); + _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ); } #endif /* _LINUX_MMAN_H */ diff --git a/include/linux/mount.h b/include/linux/mount.h index d7029f4a191a..73005f9957ea 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -47,6 +47,8 @@ struct mnt_namespace; #define MNT_INTERNAL 0x4000 +#define MNT_LOCK_READONLY 0x400000 + struct vfsmount { struct dentry *mnt_root; /* root of the mounted tree */ struct super_block *mnt_sb; /* pointer to superblock */ diff --git a/include/linux/mxsfb.h b/include/linux/mxsfb.h index f14943d55315..f80af8674342 100644 --- a/include/linux/mxsfb.h +++ b/include/linux/mxsfb.h @@ -24,8 +24,8 @@ #define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */ #define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */ -#define FB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6) -#define FB_SYNC_DOTCLK_FAILING_ACT (1 << 7) /* failing/negtive edge sampling */ +#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6) +#define MXSFB_SYNC_DOTCLK_FAILING_ACT (1 << 7) /* failing/negtive edge sampling */ struct mxsfb_platform_data { struct fb_videomode *mode_list; @@ -44,6 +44,9 @@ struct mxsfb_platform_data { * allocated. If specified,fb_size must also be specified. * fb_phys must be unused by Linux. */ + u32 sync; /* sync mask, contains MXSFB specifics not + * carried in fb_info->var.sync + */ }; #endif /* __LINUX_MXSFB_H */ diff --git a/include/linux/of.h b/include/linux/of.h index a0f129284948..c0747a44eaff 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -235,6 +235,9 @@ extern struct device_node *of_find_node_with_property( extern struct property *of_find_property(const struct device_node *np, const char *name, int *lenp); +extern int of_property_read_u32_index(const struct device_node *np, + const char *propname, + u32 index, u32 *out_value); extern int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz); extern int of_property_read_u16_array(const struct device_node *np, @@ -394,6 +397,12 @@ static inline struct device_node *of_find_compatible_node( return NULL; } +static inline int of_property_read_u32_index(const struct device_node *np, + const char *propname, u32 index, u32 *out_value) +{ + return -ENOSYS; +} + static inline int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz) { diff --git a/include/linux/platform_data/irq-renesas-intc-irqpin.h b/include/linux/platform_data/irq-renesas-intc-irqpin.h new file mode 100644 index 000000000000..e4cb911066a6 --- /dev/null +++ b/include/linux/platform_data/irq-renesas-intc-irqpin.h @@ -0,0 +1,29 @@ +/* + * Renesas INTC External IRQ Pin Driver + * + * Copyright (C) 2013 Magnus Damm + * + * 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 + * + * 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 + */ + +#ifndef __IRQ_RENESAS_INTC_IRQPIN_H__ +#define __IRQ_RENESAS_INTC_IRQPIN_H__ + +struct renesas_intc_irqpin_config { + unsigned int sense_bitfield_width; + unsigned int irq_base; + bool control_parent; +}; + +#endif /* __IRQ_RENESAS_INTC_IRQPIN_H__ */ diff --git a/include/linux/platform_data/irq-renesas-irqc.h b/include/linux/platform_data/irq-renesas-irqc.h new file mode 100644 index 000000000000..3ae17b3e00ed --- /dev/null +++ b/include/linux/platform_data/irq-renesas-irqc.h @@ -0,0 +1,27 @@ +/* + * Renesas IRQC Driver + * + * Copyright (C) 2013 Magnus Damm + * + * 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 + * + * 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 + */ + +#ifndef __IRQ_RENESAS_IRQC_H__ +#define __IRQ_RENESAS_IRQC_H__ + +struct renesas_irqc_config { + unsigned int irq_base; +}; + +#endif /* __IRQ_RENESAS_IRQC_H__ */ diff --git a/include/linux/thermal.h b/include/linux/thermal.h index f0bd7f90a90d..e3c0ae9bb1fa 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -44,7 +44,7 @@ /* Adding event notification support elements */ #define THERMAL_GENL_FAMILY_NAME "thermal_event" #define THERMAL_GENL_VERSION 0x01 -#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group" +#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_grp" /* Default Thermal Governor */ #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE) diff --git a/include/linux/udp.h b/include/linux/udp.h index 9d81de123c90..42278bbf7a88 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -68,6 +68,7 @@ struct udp_sock { * For encapsulation sockets. */ int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); + void (*encap_destroy)(struct sock *sk); }; static inline struct udp_sock *udp_sk(const struct sock *sk) diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 0a78df5f6cfd..59694b5e5e90 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -357,6 +357,7 @@ struct hc_driver { */ int (*disable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state state); + int (*find_raw_port_number)(struct usb_hcd *, int); }; extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); @@ -396,6 +397,7 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags); extern void usb_remove_hcd(struct usb_hcd *hcd); +extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1); struct platform_device; extern void usb_hcd_platform_shutdown(struct platform_device *dev); diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h index 28884c717411..148d35171aac 100644 --- a/include/linux/usb/nop-usb-xceiv.h +++ b/include/linux/usb/nop-usb-xceiv.h @@ -5,6 +5,11 @@ struct nop_usb_xceiv_platform_data { enum usb_phy_type type; + unsigned long clk_rate; + + /* if set fails with -EPROBE_DEFER if can't get regulator */ + unsigned int needs_vcc:1; + unsigned int needs_reset:1; }; #if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 4ce009324933..b6b215f13b45 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -26,6 +26,8 @@ struct user_namespace { kuid_t owner; kgid_t group; unsigned int proc_inum; + bool may_mount_sysfs; + bool may_mount_proc; }; extern struct user_namespace init_user_ns; @@ -82,4 +84,6 @@ static inline void put_user_ns(struct user_namespace *ns) #endif +void update_mnt_policy(struct user_namespace *userns); + #endif /* _LINUX_USER_H */ diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h index 80461c1ae9ef..bb8271d487b7 100644 --- a/include/net/flow_keys.h +++ b/include/net/flow_keys.h @@ -9,6 +9,7 @@ struct flow_keys { __be32 ports; __be16 port16[2]; }; + u16 thoff; u8 ip_proto; }; diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 68c69d54d392..fce8e6b66d55 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -976,6 +976,7 @@ struct netns_ipvs { int sysctl_sync_retries; int sysctl_nat_icmp_send; int sysctl_pmtu_disc; + int sysctl_backup_only; /* ip_vs_lblc */ int sysctl_lblc_expiration; @@ -1067,6 +1068,12 @@ static inline int sysctl_pmtu_disc(struct netns_ipvs *ipvs) return ipvs->sysctl_pmtu_disc; } +static inline int sysctl_backup_only(struct netns_ipvs *ipvs) +{ + return ipvs->sync_state & IP_VS_STATE_BACKUP && + ipvs->sysctl_backup_only; +} + #else static inline int sysctl_sync_threshold(struct netns_ipvs *ipvs) @@ -1114,6 +1121,11 @@ static inline int sysctl_pmtu_disc(struct netns_ipvs *ipvs) return 1; } +static inline int sysctl_backup_only(struct netns_ipvs *ipvs) +{ + return 0; +} + #endif /* diff --git a/include/net/ipip.h b/include/net/ipip.h index fd19625ff99d..982141c15200 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -77,15 +77,11 @@ static inline void tunnel_ip_select_ident(struct sk_buff *skb, { struct iphdr *iph = ip_hdr(skb); - if (iph->frag_off & htons(IP_DF)) - iph->id = 0; - else { - /* Use inner packet iph-id if possible. */ - if (skb->protocol == htons(ETH_P_IP) && old_iph->id) - iph->id = old_iph->id; - else - __ip_select_ident(iph, dst, - (skb_shinfo(skb)->gso_segs ?: 1) - 1); - } + /* Use inner packet iph-id if possible. */ + if (skb->protocol == htons(ETH_P_IP) && old_iph->id) + iph->id = old_iph->id; + else + __ip_select_ident(iph, dst, + (skb_shinfo(skb)->gso_segs ?: 1) - 1); } #endif diff --git a/include/uapi/linux/packet_diag.h b/include/uapi/linux/packet_diag.h index 93f5fa94a431..afafd703ad92 100644 --- a/include/uapi/linux/packet_diag.h +++ b/include/uapi/linux/packet_diag.h @@ -33,9 +33,11 @@ enum { PACKET_DIAG_TX_RING, PACKET_DIAG_FANOUT, - PACKET_DIAG_MAX, + __PACKET_DIAG_MAX, }; +#define PACKET_DIAG_MAX (__PACKET_DIAG_MAX - 1) + struct packet_diag_info { __u32 pdi_index; __u32 pdi_version; diff --git a/include/uapi/linux/unix_diag.h b/include/uapi/linux/unix_diag.h index b8a24941db21..b9e2a6a7446f 100644 --- a/include/uapi/linux/unix_diag.h +++ b/include/uapi/linux/unix_diag.h @@ -39,9 +39,11 @@ enum { UNIX_DIAG_MEMINFO, UNIX_DIAG_SHUTDOWN, - UNIX_DIAG_MAX, + __UNIX_DIAG_MAX, }; +#define UNIX_DIAG_MAX (__UNIX_DIAG_MAX - 1) + struct unix_diag_vfs { __u32 udiag_vfs_ino; __u32 udiag_vfs_dev; diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h index 8deb22672ada..0f5a2fc69af9 100644 --- a/include/video/atmel_lcdc.h +++ b/include/video/atmel_lcdc.h @@ -31,6 +31,7 @@ #define ATMEL_LCDC_WIRING_BGR 0 #define ATMEL_LCDC_WIRING_RGB 1 +struct atmel_lcdfb_config; /* LCD Controller info data structure, stored in device platform_data */ struct atmel_lcdfb_info { @@ -61,7 +62,8 @@ struct atmel_lcdfb_info { void (*atmel_lcdfb_power_control)(int on); struct fb_monspecs *default_monspecs; u32 pseudo_palette[16]; - bool have_intensity_bit; + + struct atmel_lcdfb_config *config; }; #define ATMEL_LCDC_DMABADDR1 0x00 diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h index 01c3d62436ef..ffd4652de91c 100644 --- a/include/xen/interface/io/blkif.h +++ b/include/xen/interface/io/blkif.h @@ -138,11 +138,21 @@ struct blkif_request_discard { uint8_t _pad3; } __attribute__((__packed__)); +struct blkif_request_other { + uint8_t _pad1; + blkif_vdev_t _pad2; /* only for read/write requests */ +#ifdef CONFIG_X86_64 + uint32_t _pad3; /* offsetof(blkif_req..,u.other.id)==8*/ +#endif + uint64_t id; /* private guest value, echoed in resp */ +} __attribute__((__packed__)); + struct blkif_request { uint8_t operation; /* BLKIF_OP_??? */ union { struct blkif_request_rw rw; struct blkif_request_discard discard; + struct blkif_request_other other; } u; } __attribute__((__packed__)); diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h index 1844d31f4552..7000bb1f6e96 100644 --- a/include/xen/interface/physdev.h +++ b/include/xen/interface/physdev.h @@ -251,6 +251,12 @@ struct physdev_pci_device_add { #define PHYSDEVOP_pci_device_remove 26 #define PHYSDEVOP_restore_msi_ext 27 +/* + * Dom0 should use these two to announce MMIO resources assigned to + * MSI-X capable devices won't (prepare) or may (release) change. + */ +#define PHYSDEVOP_prepare_msix 30 +#define PHYSDEVOP_release_msix 31 struct physdev_pci_device { /* IN */ uint16_t seg; diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 3953fda2e8bd..e4e47f647446 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -330,8 +330,16 @@ static struct dentry *mqueue_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - if (!(flags & MS_KERNMOUNT)) - data = current->nsproxy->ipc_ns; + if (!(flags & MS_KERNMOUNT)) { + struct ipc_namespace *ns = current->nsproxy->ipc_ns; + /* Don't allow mounting unless the caller has CAP_SYS_ADMIN + * over the ipc namespace. + */ + if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + + data = ns; + } return mount_ns(fs_type, flags, data, mqueue_fill_super); } diff --git a/kernel/exit.c b/kernel/exit.c index 51e485ca9935..60bc027c61c3 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -835,7 +835,7 @@ void do_exit(long code) /* * Make sure we are holding no locks: */ - debug_check_no_locks_held(); + debug_check_no_locks_held(tsk); /* * We can do this unlocked here. The futex code uses this flag * just to verify whether the pi state cleanup has been done diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 259db207b5d9..8a0efac4f99d 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -4088,7 +4088,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len) } EXPORT_SYMBOL_GPL(debug_check_no_locks_freed); -static void print_held_locks_bug(void) +static void print_held_locks_bug(struct task_struct *curr) { if (!debug_locks_off()) return; @@ -4097,21 +4097,22 @@ static void print_held_locks_bug(void) printk("\n"); printk("=====================================\n"); - printk("[ BUG: %s/%d still has locks held! ]\n", - current->comm, task_pid_nr(current)); + printk("[ BUG: lock held at task exit time! ]\n"); print_kernel_ident(); printk("-------------------------------------\n"); - lockdep_print_held_locks(current); + printk("%s/%d is exiting with locks still held!\n", + curr->comm, task_pid_nr(curr)); + lockdep_print_held_locks(curr); + printk("\nstack backtrace:\n"); dump_stack(); } -void debug_check_no_locks_held(void) +void debug_check_no_locks_held(struct task_struct *task) { - if (unlikely(current->lockdep_depth > 0)) - print_held_locks_bug(); + if (unlikely(task->lockdep_depth > 0)) + print_held_locks_bug(task); } -EXPORT_SYMBOL_GPL(debug_check_no_locks_held); void debug_show_all_locks(void) { diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index c1c3dc1c6023..bea15bdf82b0 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -181,6 +181,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) int nr; int rc; struct task_struct *task, *me = current; + int init_pids = thread_group_leader(me) ? 1 : 2; /* Don't allow any more processes into the pid namespace */ disable_pid_allocation(pid_ns); @@ -230,7 +231,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) */ for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); - if (pid_ns->nr_hashed == 1) + if (pid_ns->nr_hashed == init_pids) break; schedule(); } diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 2fb8cb88df8d..7f32fe0e52cd 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -67,7 +67,8 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc) */ int tick_check_broadcast_device(struct clock_event_device *dev) { - if ((tick_broadcast_device.evtdev && + if ((dev->features & CLOCK_EVT_FEAT_DUMMY) || + (tick_broadcast_device.evtdev && tick_broadcast_device.evtdev->rating >= dev->rating) || (dev->features & CLOCK_EVT_FEAT_C3STOP)) return 0; diff --git a/kernel/user.c b/kernel/user.c index e81978e8c03b..8e635a18ab52 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -51,6 +51,8 @@ struct user_namespace init_user_ns = { .owner = GLOBAL_ROOT_UID, .group = GLOBAL_ROOT_GID, .proc_inum = PROC_USER_INIT_INO, + .may_mount_sysfs = true, + .may_mount_proc = true, }; EXPORT_SYMBOL_GPL(init_user_ns); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index b14f4d342043..a54f26f82eb2 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -61,6 +61,15 @@ int create_user_ns(struct cred *new) kgid_t group = new->egid; int ret; + /* + * Verify that we can not violate the policy of which files + * may be accessed that is specified by the root directory, + * by verifing that the root directory is at the root of the + * mount namespace which allows all files to be accessed. + */ + if (current_chrooted()) + return -EPERM; + /* The creator needs a mapping in the parent user namespace * or else we won't be able to reasonably tell userspace who * created a user_namespace. @@ -87,6 +96,8 @@ int create_user_ns(struct cred *new) set_cred_user_ns(new, ns); + update_mnt_policy(ns); + return 0; } diff --git a/mm/fremap.c b/mm/fremap.c index 4723ac8d2fc2..87da3590c61e 100644 --- a/mm/fremap.c +++ b/mm/fremap.c @@ -204,10 +204,8 @@ get_write_lock: unsigned long addr; struct file *file = get_file(vma->vm_file); - vm_flags = vma->vm_flags; - if (!(flags & MAP_NONBLOCK)) - vm_flags |= VM_POPULATE; - addr = mmap_region(file, start, size, vm_flags, pgoff); + addr = mmap_region(file, start, size, + vma->vm_flags, pgoff); fput(file); if (IS_ERR_VALUE(addr)) { err = addr; @@ -226,12 +224,6 @@ get_write_lock: mutex_unlock(&mapping->i_mmap_mutex); } - if (!(flags & MAP_NONBLOCK) && !(vma->vm_flags & VM_POPULATE)) { - if (!has_write_lock) - goto get_write_lock; - vma->vm_flags |= VM_POPULATE; - } - if (vma->vm_flags & VM_LOCKED) { /* * drop PG_Mlocked flag for over-mapped range diff --git a/mm/mlock.c b/mm/mlock.c index 1c5e33fce639..79b7cf7d1bca 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -358,7 +358,7 @@ static int do_mlock(unsigned long start, size_t len, int on) newflags = vma->vm_flags & ~VM_LOCKED; if (on) - newflags |= VM_LOCKED | VM_POPULATE; + newflags |= VM_LOCKED; tmp = vma->vm_end; if (tmp > end) @@ -418,8 +418,7 @@ int __mm_populate(unsigned long start, unsigned long len, int ignore_errors) * range with the first VMA. Also, skip undesirable VMA types. */ nend = min(end, vma->vm_end); - if ((vma->vm_flags & (VM_IO | VM_PFNMAP | VM_POPULATE)) != - VM_POPULATE) + if (vma->vm_flags & (VM_IO | VM_PFNMAP)) continue; if (nstart < vma->vm_start) nstart = vma->vm_start; @@ -492,9 +491,9 @@ static int do_mlockall(int flags) struct vm_area_struct * vma, * prev = NULL; if (flags & MCL_FUTURE) - current->mm->def_flags |= VM_LOCKED | VM_POPULATE; + current->mm->def_flags |= VM_LOCKED; else - current->mm->def_flags &= ~(VM_LOCKED | VM_POPULATE); + current->mm->def_flags &= ~VM_LOCKED; if (flags == MCL_FUTURE) goto out; @@ -503,7 +502,7 @@ static int do_mlockall(int flags) newflags = vma->vm_flags & ~VM_LOCKED; if (flags & MCL_CURRENT) - newflags |= VM_LOCKED | VM_POPULATE; + newflags |= VM_LOCKED; /* Ignore errors */ mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags); diff --git a/mm/mmap.c b/mm/mmap.c index 2664a47cec93..6466699b16cb 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1306,7 +1306,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, } addr = mmap_region(file, addr, len, vm_flags, pgoff); - if (!IS_ERR_VALUE(addr) && (vm_flags & VM_POPULATE)) + if (!IS_ERR_VALUE(addr) && + ((vm_flags & VM_LOCKED) || + (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE)) *populate = len; return addr; } diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index a18714469bf7..85addcd9372b 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -86,13 +86,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) grp = &vlan_info->grp; - /* Take it out of our own structures, but be sure to interlock with - * HW accelerating devices or SW vlan input packet processing if - * VLAN is not 0 (leave it there for 802.1p). - */ - if (vlan_id) - vlan_vid_del(real_dev, vlan_id); - grp->nr_vlan_devs--; if (vlan->flags & VLAN_FLAG_MVRP) @@ -114,6 +107,13 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) vlan_gvrp_uninit_applicant(real_dev); } + /* Take it out of our own structures, but be sure to interlock with + * HW accelerating devices or SW vlan input packet processing if + * VLAN is not 0 (leave it there for 802.1p). + */ + if (vlan_id) + vlan_vid_del(real_dev, vlan_id); + /* Get rid of the vlan's reference to real_dev */ dev_put(real_dev); } diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 79d87d8d4f51..fad0302bdb32 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -359,6 +359,7 @@ static void __sco_sock_close(struct sock *sk) sco_chan_del(sk, ECONNRESET); break; + case BT_CONNECT2: case BT_CONNECT: case BT_DISCONN: sco_chan_del(sk, ECONNRESET); diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b0812c91c0f0..bab338e6270d 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -423,7 +423,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, return 0; br_warn(br, "adding interface %s with same address " "as a received packet\n", - source->dev->name); + source ? source->dev->name : br->dev->name); fdb_delete(br, fdb); } diff --git a/net/core/dev.c b/net/core/dev.c index d540ced1f6c6..b13e5c766c11 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1545,7 +1545,6 @@ void net_enable_timestamp(void) return; } #endif - WARN_ON(in_interrupt()); static_key_slow_inc(&netstamp_needed); } EXPORT_SYMBOL(net_enable_timestamp); diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 9d4c7201400d..e187bf06d673 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -140,6 +140,8 @@ ipv6: flow->ports = *ports; } + flow->thoff = (u16) nhoff; + return true; } EXPORT_SYMBOL(skb_flow_dissect); diff --git a/net/core/scm.c b/net/core/scm.c index 905dcc6ad1e3..2dc6cdaaae8a 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -24,6 +24,7 @@ #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/security.h> +#include <linux/pid_namespace.h> #include <linux/pid.h> #include <linux/nsproxy.h> #include <linux/slab.h> @@ -52,7 +53,8 @@ static __inline__ int scm_check_creds(struct ucred *creds) if (!uid_valid(uid) || !gid_valid(gid)) return -EINVAL; - if ((creds->pid == task_tgid_vnr(current) || nsown_capable(CAP_SYS_ADMIN)) && + if ((creds->pid == task_tgid_vnr(current) || + ns_capable(current->nsproxy->pid_ns->user_ns, CAP_SYS_ADMIN)) && ((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) || uid_eq(uid, cred->suid)) || nsown_capable(CAP_SETUID)) && ((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) || diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 68f6a94f7661..c929d9c1c4b6 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1333,8 +1333,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, iph->frag_off |= htons(IP_MF); offset += (skb->len - skb->mac_len - iph->ihl * 4); } else { - if (!(iph->frag_off & htons(IP_DF))) - iph->id = htons(id++); + iph->id = htons(id++); } iph->tot_len = htons(skb->len - skb->mac_len); iph->check = 0; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 98cbc6877019..bf6c5cf31aed 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1522,7 +1522,8 @@ static int __init ip_auto_config(void) } for (i++; i < CONF_NAMESERVERS_MAX; i++) if (ic_nameservers[i] != NONE) - pr_cont(", nameserver%u=%pI4\n", i, &ic_nameservers[i]); + pr_cont(", nameserver%u=%pI4", i, &ic_nameservers[i]); + pr_cont("\n"); #endif /* !SILENT */ return 0; diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index ce2d43e1f09f..0d755c50994b 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -36,19 +36,6 @@ config NF_CONNTRACK_PROC_COMPAT If unsure, say Y. -config IP_NF_QUEUE - tristate "IP Userspace queueing via NETLINK (OBSOLETE)" - depends on NETFILTER_ADVANCED - help - Netfilter has the ability to queue packets to user space: the - netlink device can be used to access them using this driver. - - This option enables the old IPv4-only "ip_queue" implementation - which has been obsoleted by the new "nfnetlink_queue" code (see - CONFIG_NETFILTER_NETLINK_QUEUE). - - To compile it as a module, choose M here. If unsure, say N. - config IP_NF_IPTABLES tristate "IP tables support (required for filtering/masq/NAT)" default m if NETFILTER_ADVANCED=n diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0d9bdacce99f..3bd55bad230a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2059,11 +2059,8 @@ void tcp_enter_loss(struct sock *sk, int how) if (tcp_is_reno(tp)) tcp_reset_reno_sack(tp); - if (!how) { - /* Push undo marker, if it was plain RTO and nothing - * was retransmitted. */ - tp->undo_marker = tp->snd_una; - } else { + tp->undo_marker = tp->snd_una; + if (how) { tp->sacked_out = 0; tp->fackets_out = 0; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 817fbb396bc8..5d0b4387cba6 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1809,8 +1809,11 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) goto send_now; } - /* Ok, it looks like it is advisable to defer. */ - tp->tso_deferred = 1 | (jiffies << 1); + /* Ok, it looks like it is advisable to defer. + * Do not rearm the timer if already set to not break TCP ACK clocking. + */ + if (!tp->tso_deferred) + tp->tso_deferred = 1 | (jiffies << 1); return true; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 265c42cf963c..0a073a263720 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1762,9 +1762,16 @@ int udp_rcv(struct sk_buff *skb) void udp_destroy_sock(struct sock *sk) { + struct udp_sock *up = udp_sk(sk); bool slow = lock_sock_fast(sk); udp_flush_pending_frames(sk); unlock_sock_fast(sk, slow); + if (static_key_false(&udp_encap_needed) && up->encap_type) { + void (*encap_destroy)(struct sock *sk); + encap_destroy = ACCESS_ONCE(up->encap_destroy); + if (encap_destroy) + encap_destroy(sk); + } } /* diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f2c7e615f902..26512250e095 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4784,26 +4784,20 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev) static int __net_init addrconf_init_net(struct net *net) { - int err; + int err = -ENOMEM; struct ipv6_devconf *all, *dflt; - err = -ENOMEM; - all = &ipv6_devconf; - dflt = &ipv6_devconf_dflt; + all = kmemdup(&ipv6_devconf, sizeof(ipv6_devconf), GFP_KERNEL); + if (all == NULL) + goto err_alloc_all; - if (!net_eq(net, &init_net)) { - all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL); - if (all == NULL) - goto err_alloc_all; + dflt = kmemdup(&ipv6_devconf_dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); + if (dflt == NULL) + goto err_alloc_dflt; - dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); - if (dflt == NULL) - goto err_alloc_dflt; - } else { - /* these will be inherited by all namespaces */ - dflt->autoconf = ipv6_defaults.autoconf; - dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; - } + /* these will be inherited by all namespaces */ + dflt->autoconf = ipv6_defaults.autoconf; + dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; net->ipv6.devconf_all = all; net->ipv6.devconf_dflt = dflt; diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c index 83acc1405a18..33608c610276 100644 --- a/net/ipv6/netfilter/ip6t_NPT.c +++ b/net/ipv6/netfilter/ip6t_NPT.c @@ -114,6 +114,7 @@ ip6t_dnpt_tg(struct sk_buff *skb, const struct xt_action_param *par) static struct xt_target ip6t_npt_target_reg[] __read_mostly = { { .name = "SNPT", + .table = "mangle", .target = ip6t_snpt_tg, .targetsize = sizeof(struct ip6t_npt_tginfo), .checkentry = ip6t_npt_checkentry, @@ -124,6 +125,7 @@ static struct xt_target ip6t_npt_target_reg[] __read_mostly = { }, { .name = "DNPT", + .table = "mangle", .target = ip6t_dnpt_tg, .targetsize = sizeof(struct ip6t_npt_tginfo), .checkentry = ip6t_npt_checkentry, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 599e1ba6d1ce..d8e5e852fc7a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1285,10 +1285,18 @@ do_confirm: void udpv6_destroy_sock(struct sock *sk) { + struct udp_sock *up = udp_sk(sk); lock_sock(sk); udp_v6_flush_pending_frames(sk); release_sock(sk); + if (static_key_false(&udpv6_encap_needed) && up->encap_type) { + void (*encap_destroy)(struct sock *sk); + encap_destroy = ACCESS_ONCE(up->encap_destroy); + if (encap_destroy) + encap_destroy(sk); + } + inet6_destroy_sock(sk); } diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index d07e3a626446..d28e7f014cc6 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -2583,8 +2583,10 @@ bed: NULL, NULL, NULL); /* Check if the we got some results */ - if (!self->cachedaddr) - return -EAGAIN; /* Didn't find any devices */ + if (!self->cachedaddr) { + err = -EAGAIN; /* Didn't find any devices */ + goto out; + } daddr = self->cachedaddr; /* Cleanup */ self->cachedaddr = 0; diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index d36875f3427e..8aecf5df6656 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -114,7 +114,6 @@ struct l2tp_net { static void l2tp_session_set_header_len(struct l2tp_session *session, int version); static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); -static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); static inline struct l2tp_net *l2tp_pernet(struct net *net) { @@ -192,6 +191,7 @@ struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) } else { /* Socket is owned by kernelspace */ sk = tunnel->sock; + sock_hold(sk); } out: @@ -210,6 +210,7 @@ void l2tp_tunnel_sock_put(struct sock *sk) } sock_put(sk); } + sock_put(sk); } EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_put); @@ -373,10 +374,8 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk struct sk_buff *skbp; struct sk_buff *tmp; u32 ns = L2TP_SKB_CB(skb)->ns; - struct l2tp_stats *sstats; spin_lock_bh(&session->reorder_q.lock); - sstats = &session->stats; skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { if (L2TP_SKB_CB(skbp)->ns > ns) { __skb_queue_before(&session->reorder_q, skbp, skb); @@ -384,9 +383,7 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n", session->name, ns, L2TP_SKB_CB(skbp)->ns, skb_queue_len(&session->reorder_q)); - u64_stats_update_begin(&sstats->syncp); - sstats->rx_oos_packets++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_oos_packets); goto out; } } @@ -403,23 +400,16 @@ static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff * { struct l2tp_tunnel *tunnel = session->tunnel; int length = L2TP_SKB_CB(skb)->length; - struct l2tp_stats *tstats, *sstats; /* We're about to requeue the skb, so return resources * to its current owner (a socket receive buffer). */ skb_orphan(skb); - tstats = &tunnel->stats; - u64_stats_update_begin(&tstats->syncp); - sstats = &session->stats; - u64_stats_update_begin(&sstats->syncp); - tstats->rx_packets++; - tstats->rx_bytes += length; - sstats->rx_packets++; - sstats->rx_bytes += length; - u64_stats_update_end(&tstats->syncp); - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&tunnel->stats.rx_packets); + atomic_long_add(length, &tunnel->stats.rx_bytes); + atomic_long_inc(&session->stats.rx_packets); + atomic_long_add(length, &session->stats.rx_bytes); if (L2TP_SKB_CB(skb)->has_seq) { /* Bump our Nr */ @@ -450,7 +440,6 @@ static void l2tp_recv_dequeue(struct l2tp_session *session) { struct sk_buff *skb; struct sk_buff *tmp; - struct l2tp_stats *sstats; /* If the pkt at the head of the queue has the nr that we * expect to send up next, dequeue it and any other @@ -458,13 +447,10 @@ static void l2tp_recv_dequeue(struct l2tp_session *session) */ start: spin_lock_bh(&session->reorder_q.lock); - sstats = &session->stats; skb_queue_walk_safe(&session->reorder_q, skb, tmp) { if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) { - u64_stats_update_begin(&sstats->syncp); - sstats->rx_seq_discards++; - sstats->rx_errors++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_seq_discards); + atomic_long_inc(&session->stats.rx_errors); l2tp_dbg(session, L2TP_MSG_SEQ, "%s: oos pkt %u len %d discarded (too old), waiting for %u, reorder_q_len=%d\n", session->name, L2TP_SKB_CB(skb)->ns, @@ -623,7 +609,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, struct l2tp_tunnel *tunnel = session->tunnel; int offset; u32 ns, nr; - struct l2tp_stats *sstats = &session->stats; /* The ref count is increased since we now hold a pointer to * the session. Take care to decrement the refcnt when exiting @@ -640,9 +625,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, "%s: cookie mismatch (%u/%u). Discarding.\n", tunnel->name, tunnel->tunnel_id, session->session_id); - u64_stats_update_begin(&sstats->syncp); - sstats->rx_cookie_discards++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_cookie_discards); goto discard; } ptr += session->peer_cookie_len; @@ -711,9 +694,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, l2tp_warn(session, L2TP_MSG_SEQ, "%s: recv data has no seq numbers when required. Discarding.\n", session->name); - u64_stats_update_begin(&sstats->syncp); - sstats->rx_seq_discards++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_seq_discards); goto discard; } @@ -732,9 +713,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, l2tp_warn(session, L2TP_MSG_SEQ, "%s: recv data has no seq numbers when required. Discarding.\n", session->name); - u64_stats_update_begin(&sstats->syncp); - sstats->rx_seq_discards++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_seq_discards); goto discard; } } @@ -788,9 +767,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, * packets */ if (L2TP_SKB_CB(skb)->ns != session->nr) { - u64_stats_update_begin(&sstats->syncp); - sstats->rx_seq_discards++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_seq_discards); l2tp_dbg(session, L2TP_MSG_SEQ, "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n", session->name, L2TP_SKB_CB(skb)->ns, @@ -816,9 +793,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, return; discard: - u64_stats_update_begin(&sstats->syncp); - sstats->rx_errors++; - u64_stats_update_end(&sstats->syncp); + atomic_long_inc(&session->stats.rx_errors); kfree_skb(skb); if (session->deref) @@ -828,6 +803,23 @@ discard: } EXPORT_SYMBOL(l2tp_recv_common); +/* Drop skbs from the session's reorder_q + */ +int l2tp_session_queue_purge(struct l2tp_session *session) +{ + struct sk_buff *skb = NULL; + BUG_ON(!session); + BUG_ON(session->magic != L2TP_SESSION_MAGIC); + while ((skb = skb_dequeue(&session->reorder_q))) { + atomic_long_inc(&session->stats.rx_errors); + kfree_skb(skb); + if (session->deref) + (*session->deref)(session); + } + return 0; +} +EXPORT_SYMBOL_GPL(l2tp_session_queue_purge); + /* Internal UDP receive frame. Do the real work of receiving an L2TP data frame * here. The skb is not on a list when we get here. * Returns 0 if the packet was a data packet and was successfully passed on. @@ -843,7 +835,6 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, u32 tunnel_id, session_id; u16 version; int length; - struct l2tp_stats *tstats; if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb)) goto discard_bad_csum; @@ -932,10 +923,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, discard_bad_csum: LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name); UDP_INC_STATS_USER(tunnel->l2tp_net, UDP_MIB_INERRORS, 0); - tstats = &tunnel->stats; - u64_stats_update_begin(&tstats->syncp); - tstats->rx_errors++; - u64_stats_update_end(&tstats->syncp); + atomic_long_inc(&tunnel->stats.rx_errors); kfree_skb(skb); return 0; @@ -1062,7 +1050,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, struct l2tp_tunnel *tunnel = session->tunnel; unsigned int len = skb->len; int error; - struct l2tp_stats *tstats, *sstats; /* Debug */ if (session->send_seq) @@ -1091,21 +1078,15 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, error = ip_queue_xmit(skb, fl); /* Update stats */ - tstats = &tunnel->stats; - u64_stats_update_begin(&tstats->syncp); - sstats = &session->stats; - u64_stats_update_begin(&sstats->syncp); if (error >= 0) { - tstats->tx_packets++; - tstats->tx_bytes += len; - sstats->tx_packets++; - sstats->tx_bytes += len; + atomic_long_inc(&tunnel->stats.tx_packets); + atomic_long_add(len, &tunnel->stats.tx_bytes); + atomic_long_inc(&session->stats.tx_packets); + atomic_long_add(len, &session->stats.tx_bytes); } else { - tstats->tx_errors++; - sstats->tx_errors++; + atomic_long_inc(&tunnel->stats.tx_errors); + atomic_long_inc(&session->stats.tx_errors); } - u64_stats_update_end(&tstats->syncp); - u64_stats_update_end(&sstats->syncp); return 0; } @@ -1282,6 +1263,7 @@ static void l2tp_tunnel_destruct(struct sock *sk) /* No longer an encapsulation socket. See net/ipv4/udp.c */ (udp_sk(sk))->encap_type = 0; (udp_sk(sk))->encap_rcv = NULL; + (udp_sk(sk))->encap_destroy = NULL; break; case L2TP_ENCAPTYPE_IP: break; @@ -1311,7 +1293,7 @@ end: /* When the tunnel is closed, all the attached sessions need to go too. */ -static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) +void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) { int hash; struct hlist_node *walk; @@ -1334,25 +1316,13 @@ again: hlist_del_init(&session->hlist); - /* Since we should hold the sock lock while - * doing any unbinding, we need to release the - * lock we're holding before taking that lock. - * Hold a reference to the sock so it doesn't - * disappear as we're jumping between locks. - */ if (session->ref != NULL) (*session->ref)(session); write_unlock_bh(&tunnel->hlist_lock); - if (tunnel->version != L2TP_HDR_VER_2) { - struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); - - spin_lock_bh(&pn->l2tp_session_hlist_lock); - hlist_del_init_rcu(&session->global_hlist); - spin_unlock_bh(&pn->l2tp_session_hlist_lock); - synchronize_rcu(); - } + __l2tp_session_unhash(session); + l2tp_session_queue_purge(session); if (session->session_close != NULL) (*session->session_close)(session); @@ -1360,6 +1330,8 @@ again: if (session->deref != NULL) (*session->deref)(session); + l2tp_session_dec_refcount(session); + write_lock_bh(&tunnel->hlist_lock); /* Now restart from the beginning of this hash @@ -1372,6 +1344,17 @@ again: } write_unlock_bh(&tunnel->hlist_lock); } +EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall); + +/* Tunnel socket destroy hook for UDP encapsulation */ +static void l2tp_udp_encap_destroy(struct sock *sk) +{ + struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); + if (tunnel) { + l2tp_tunnel_closeall(tunnel); + sock_put(sk); + } +} /* Really kill the tunnel. * Come here only when all sessions have been cleared from the tunnel. @@ -1397,19 +1380,21 @@ static void l2tp_tunnel_del_work(struct work_struct *work) return; sock = sk->sk_socket; - BUG_ON(!sock); - /* If the tunnel socket was created directly by the kernel, use the - * sk_* API to release the socket now. Otherwise go through the - * inet_* layer to shut the socket down, and let userspace close it. + /* If the tunnel socket was created by userspace, then go through the + * inet layer to shut the socket down, and let userspace close it. + * Otherwise, if we created the socket directly within the kernel, use + * the sk API to release it here. * In either case the tunnel resources are freed in the socket * destructor when the tunnel socket goes away. */ - if (sock->file == NULL) { - kernel_sock_shutdown(sock, SHUT_RDWR); - sk_release_kernel(sk); + if (tunnel->fd >= 0) { + if (sock) + inet_shutdown(sock, 2); } else { - inet_shutdown(sock, 2); + if (sock) + kernel_sock_shutdown(sock, SHUT_RDWR); + sk_release_kernel(sk); } l2tp_tunnel_sock_put(sk); @@ -1668,6 +1653,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; + udp_sk(sk)->encap_destroy = l2tp_udp_encap_destroy; #if IS_ENABLED(CONFIG_IPV6) if (sk->sk_family == PF_INET6) udpv6_encap_enable(); @@ -1723,6 +1709,7 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create); */ int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) { + l2tp_tunnel_closeall(tunnel); return (false == queue_work(l2tp_wq, &tunnel->del_work)); } EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); @@ -1731,62 +1718,71 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); */ void l2tp_session_free(struct l2tp_session *session) { - struct l2tp_tunnel *tunnel; + struct l2tp_tunnel *tunnel = session->tunnel; BUG_ON(atomic_read(&session->ref_count) != 0); - tunnel = session->tunnel; - if (tunnel != NULL) { + if (tunnel) { BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); + if (session->session_id != 0) + atomic_dec(&l2tp_session_count); + sock_put(tunnel->sock); + session->tunnel = NULL; + l2tp_tunnel_dec_refcount(tunnel); + } + + kfree(session); - /* Delete the session from the hash */ + return; +} +EXPORT_SYMBOL_GPL(l2tp_session_free); + +/* Remove an l2tp session from l2tp_core's hash lists. + * Provides a tidyup interface for pseudowire code which can't just route all + * shutdown via. l2tp_session_delete and a pseudowire-specific session_close + * callback. + */ +void __l2tp_session_unhash(struct l2tp_session *session) +{ + struct l2tp_tunnel *tunnel = session->tunnel; + + /* Remove the session from core hashes */ + if (tunnel) { + /* Remove from the per-tunnel hash */ write_lock_bh(&tunnel->hlist_lock); hlist_del_init(&session->hlist); write_unlock_bh(&tunnel->hlist_lock); - /* Unlink from the global hash if not L2TPv2 */ + /* For L2TPv3 we have a per-net hash: remove from there, too */ if (tunnel->version != L2TP_HDR_VER_2) { struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); - spin_lock_bh(&pn->l2tp_session_hlist_lock); hlist_del_init_rcu(&session->global_hlist); spin_unlock_bh(&pn->l2tp_session_hlist_lock); synchronize_rcu(); } - - if (session->session_id != 0) - atomic_dec(&l2tp_session_count); - - sock_put(tunnel->sock); - - /* This will delete the tunnel context if this - * is the last session on the tunnel. - */ - session->tunnel = NULL; - l2tp_tunnel_dec_refcount(tunnel); } - - kfree(session); - - return; } -EXPORT_SYMBOL_GPL(l2tp_session_free); +EXPORT_SYMBOL_GPL(__l2tp_session_unhash); /* This function is used by the netlink SESSION_DELETE command and by pseudowire modules. */ int l2tp_session_delete(struct l2tp_session *session) { + if (session->ref) + (*session->ref)(session); + __l2tp_session_unhash(session); + l2tp_session_queue_purge(session); if (session->session_close != NULL) (*session->session_close)(session); - + if (session->deref) + (*session->ref)(session); l2tp_session_dec_refcount(session); - return 0; } EXPORT_SYMBOL_GPL(l2tp_session_delete); - /* We come here whenever a session's send_seq, cookie_len or * l2specific_len parameters are set. */ diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 8eb8f1d47f3a..485a490fd990 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -36,16 +36,15 @@ enum { struct sk_buff; struct l2tp_stats { - u64 tx_packets; - u64 tx_bytes; - u64 tx_errors; - u64 rx_packets; - u64 rx_bytes; - u64 rx_seq_discards; - u64 rx_oos_packets; - u64 rx_errors; - u64 rx_cookie_discards; - struct u64_stats_sync syncp; + atomic_long_t tx_packets; + atomic_long_t tx_bytes; + atomic_long_t tx_errors; + atomic_long_t rx_packets; + atomic_long_t rx_bytes; + atomic_long_t rx_seq_discards; + atomic_long_t rx_oos_packets; + atomic_long_t rx_errors; + atomic_long_t rx_cookie_discards; }; struct l2tp_tunnel; @@ -240,11 +239,14 @@ extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp); +extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); +extern void __l2tp_session_unhash(struct l2tp_session *session); extern int l2tp_session_delete(struct l2tp_session *session); extern void l2tp_session_free(struct l2tp_session *session); extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); +extern int l2tp_session_queue_purge(struct l2tp_session *session); extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len); diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index c3813bc84552..072d7202e182 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c @@ -146,14 +146,14 @@ static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v) tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0, atomic_read(&tunnel->ref_count)); - seq_printf(m, " %08x rx %llu/%llu/%llu rx %llu/%llu/%llu\n", + seq_printf(m, " %08x rx %ld/%ld/%ld rx %ld/%ld/%ld\n", tunnel->debug, - (unsigned long long)tunnel->stats.tx_packets, - (unsigned long long)tunnel->stats.tx_bytes, - (unsigned long long)tunnel->stats.tx_errors, - (unsigned long long)tunnel->stats.rx_packets, - (unsigned long long)tunnel->stats.rx_bytes, - (unsigned long long)tunnel->stats.rx_errors); + atomic_long_read(&tunnel->stats.tx_packets), + atomic_long_read(&tunnel->stats.tx_bytes), + atomic_long_read(&tunnel->stats.tx_errors), + atomic_long_read(&tunnel->stats.rx_packets), + atomic_long_read(&tunnel->stats.rx_bytes), + atomic_long_read(&tunnel->stats.rx_errors)); if (tunnel->show != NULL) tunnel->show(m, tunnel); @@ -203,14 +203,14 @@ static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v) seq_printf(m, "\n"); } - seq_printf(m, " %hu/%hu tx %llu/%llu/%llu rx %llu/%llu/%llu\n", + seq_printf(m, " %hu/%hu tx %ld/%ld/%ld rx %ld/%ld/%ld\n", session->nr, session->ns, - (unsigned long long)session->stats.tx_packets, - (unsigned long long)session->stats.tx_bytes, - (unsigned long long)session->stats.tx_errors, - (unsigned long long)session->stats.rx_packets, - (unsigned long long)session->stats.rx_bytes, - (unsigned long long)session->stats.rx_errors); + atomic_long_read(&session->stats.tx_packets), + atomic_long_read(&session->stats.tx_bytes), + atomic_long_read(&session->stats.tx_errors), + atomic_long_read(&session->stats.rx_packets), + atomic_long_read(&session->stats.rx_bytes), + atomic_long_read(&session->stats.rx_errors)); if (session->show != NULL) session->show(m, session); diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 7f41b7051269..571db8dd2292 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -228,10 +228,16 @@ static void l2tp_ip_close(struct sock *sk, long timeout) static void l2tp_ip_destroy_sock(struct sock *sk) { struct sk_buff *skb; + struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) kfree_skb(skb); + if (tunnel) { + l2tp_tunnel_closeall(tunnel); + sock_put(sk); + } + sk_refcnt_debug_dec(sk); } diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 41f2f8126ebc..c74f5a91ff6a 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -241,10 +241,17 @@ static void l2tp_ip6_close(struct sock *sk, long timeout) static void l2tp_ip6_destroy_sock(struct sock *sk) { + struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); + lock_sock(sk); ip6_flush_pending_frames(sk); release_sock(sk); + if (tunnel) { + l2tp_tunnel_closeall(tunnel); + sock_put(sk); + } + inet6_destroy_sock(sk); } diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index c1bab22db85e..0825ff26e113 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -246,8 +246,6 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla #if IS_ENABLED(CONFIG_IPV6) struct ipv6_pinfo *np = NULL; #endif - struct l2tp_stats stats; - unsigned int start; hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, L2TP_CMD_TUNNEL_GET); @@ -265,28 +263,22 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla if (nest == NULL) goto nla_put_failure; - do { - start = u64_stats_fetch_begin(&tunnel->stats.syncp); - stats.tx_packets = tunnel->stats.tx_packets; - stats.tx_bytes = tunnel->stats.tx_bytes; - stats.tx_errors = tunnel->stats.tx_errors; - stats.rx_packets = tunnel->stats.rx_packets; - stats.rx_bytes = tunnel->stats.rx_bytes; - stats.rx_errors = tunnel->stats.rx_errors; - stats.rx_seq_discards = tunnel->stats.rx_seq_discards; - stats.rx_oos_packets = tunnel->stats.rx_oos_packets; - } while (u64_stats_fetch_retry(&tunnel->stats.syncp, start)); - - if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, stats.tx_packets) || - nla_put_u64(skb, L2TP_ATTR_TX_BYTES, stats.tx_bytes) || - nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, stats.tx_errors) || - nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, stats.rx_packets) || - nla_put_u64(skb, L2TP_ATTR_RX_BYTES, stats.rx_bytes) || + if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, + atomic_long_read(&tunnel->stats.tx_packets)) || + nla_put_u64(skb, L2TP_ATTR_TX_BYTES, + atomic_long_read(&tunnel->stats.tx_bytes)) || + nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, + atomic_long_read(&tunnel->stats.tx_errors)) || + nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, + atomic_long_read(&tunnel->stats.rx_packets)) || + nla_put_u64(skb, L2TP_ATTR_RX_BYTES, + atomic_long_read(&tunnel->stats.rx_bytes)) || nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, - stats.rx_seq_discards) || + atomic_long_read(&tunnel->stats.rx_seq_discards)) || nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS, - stats.rx_oos_packets) || - nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, stats.rx_errors)) + atomic_long_read(&tunnel->stats.rx_oos_packets)) || + nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, + atomic_long_read(&tunnel->stats.rx_errors))) goto nla_put_failure; nla_nest_end(skb, nest); @@ -612,8 +604,6 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl struct nlattr *nest; struct l2tp_tunnel *tunnel = session->tunnel; struct sock *sk = NULL; - struct l2tp_stats stats; - unsigned int start; sk = tunnel->sock; @@ -656,28 +646,22 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl if (nest == NULL) goto nla_put_failure; - do { - start = u64_stats_fetch_begin(&session->stats.syncp); - stats.tx_packets = session->stats.tx_packets; - stats.tx_bytes = session->stats.tx_bytes; - stats.tx_errors = session->stats.tx_errors; - stats.rx_packets = session->stats.rx_packets; - stats.rx_bytes = session->stats.rx_bytes; - stats.rx_errors = session->stats.rx_errors; - stats.rx_seq_discards = session->stats.rx_seq_discards; - stats.rx_oos_packets = session->stats.rx_oos_packets; - } while (u64_stats_fetch_retry(&session->stats.syncp, start)); - - if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, stats.tx_packets) || - nla_put_u64(skb, L2TP_ATTR_TX_BYTES, stats.tx_bytes) || - nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, stats.tx_errors) || - nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, stats.rx_packets) || - nla_put_u64(skb, L2TP_ATTR_RX_BYTES, stats.rx_bytes) || + if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, + atomic_long_read(&session->stats.tx_packets)) || + nla_put_u64(skb, L2TP_ATTR_TX_BYTES, + atomic_long_read(&session->stats.tx_bytes)) || + nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, + atomic_long_read(&session->stats.tx_errors)) || + nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, + atomic_long_read(&session->stats.rx_packets)) || + nla_put_u64(skb, L2TP_ATTR_RX_BYTES, + atomic_long_read(&session->stats.rx_bytes)) || nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, - stats.rx_seq_discards) || + atomic_long_read(&session->stats.rx_seq_discards)) || nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS, - stats.rx_oos_packets) || - nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, stats.rx_errors)) + atomic_long_read(&session->stats.rx_oos_packets)) || + nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, + atomic_long_read(&session->stats.rx_errors))) goto nla_put_failure; nla_nest_end(skb, nest); diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 6a53371dba1f..637a341c1e2d 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -97,6 +97,7 @@ #include <net/ip.h> #include <net/udp.h> #include <net/xfrm.h> +#include <net/inet_common.h> #include <asm/byteorder.h> #include <linux/atomic.h> @@ -259,7 +260,7 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int session->name); /* Not bound. Nothing we can do, so discard. */ - session->stats.rx_errors++; + atomic_long_inc(&session->stats.rx_errors); kfree_skb(skb); } @@ -447,34 +448,16 @@ static void pppol2tp_session_close(struct l2tp_session *session) { struct pppol2tp_session *ps = l2tp_session_priv(session); struct sock *sk = ps->sock; - struct sk_buff *skb; + struct socket *sock = sk->sk_socket; BUG_ON(session->magic != L2TP_SESSION_MAGIC); - if (session->session_id == 0) - goto out; - - if (sk != NULL) { - lock_sock(sk); - - if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { - pppox_unbind_sock(sk); - sk->sk_state = PPPOX_DEAD; - sk->sk_state_change(sk); - } - - /* Purge any queued data */ - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); - while ((skb = skb_dequeue(&session->reorder_q))) { - kfree_skb(skb); - sock_put(sk); - } - release_sock(sk); + if (sock) { + inet_shutdown(sock, 2); + /* Don't let the session go away before our socket does */ + l2tp_session_inc_refcount(session); } - -out: return; } @@ -483,19 +466,12 @@ out: */ static void pppol2tp_session_destruct(struct sock *sk) { - struct l2tp_session *session; - - if (sk->sk_user_data != NULL) { - session = sk->sk_user_data; - if (session == NULL) - goto out; - + struct l2tp_session *session = sk->sk_user_data; + if (session) { sk->sk_user_data = NULL; BUG_ON(session->magic != L2TP_SESSION_MAGIC); l2tp_session_dec_refcount(session); } - -out: return; } @@ -525,16 +501,13 @@ static int pppol2tp_release(struct socket *sock) session = pppol2tp_sock_to_session(sk); /* Purge any queued data */ - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); if (session != NULL) { - struct sk_buff *skb; - while ((skb = skb_dequeue(&session->reorder_q))) { - kfree_skb(skb); - sock_put(sk); - } + __l2tp_session_unhash(session); + l2tp_session_queue_purge(session); sock_put(sk); } + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); release_sock(sk); @@ -880,18 +853,6 @@ out: return error; } -/* Called when deleting sessions via the netlink interface. - */ -static int pppol2tp_session_delete(struct l2tp_session *session) -{ - struct pppol2tp_session *ps = l2tp_session_priv(session); - - if (ps->sock == NULL) - l2tp_session_dec_refcount(session); - - return 0; -} - #endif /* CONFIG_L2TP_V3 */ /* getname() support. @@ -1025,14 +986,14 @@ end: static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest, struct l2tp_stats *stats) { - dest->tx_packets = stats->tx_packets; - dest->tx_bytes = stats->tx_bytes; - dest->tx_errors = stats->tx_errors; - dest->rx_packets = stats->rx_packets; - dest->rx_bytes = stats->rx_bytes; - dest->rx_seq_discards = stats->rx_seq_discards; - dest->rx_oos_packets = stats->rx_oos_packets; - dest->rx_errors = stats->rx_errors; + dest->tx_packets = atomic_long_read(&stats->tx_packets); + dest->tx_bytes = atomic_long_read(&stats->tx_bytes); + dest->tx_errors = atomic_long_read(&stats->tx_errors); + dest->rx_packets = atomic_long_read(&stats->rx_packets); + dest->rx_bytes = atomic_long_read(&stats->rx_bytes); + dest->rx_seq_discards = atomic_long_read(&stats->rx_seq_discards); + dest->rx_oos_packets = atomic_long_read(&stats->rx_oos_packets); + dest->rx_errors = atomic_long_read(&stats->rx_errors); } /* Session ioctl helper. @@ -1666,14 +1627,14 @@ static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v) tunnel->name, (tunnel == tunnel->sock->sk_user_data) ? 'Y' : 'N', atomic_read(&tunnel->ref_count) - 1); - seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n", + seq_printf(m, " %08x %ld/%ld/%ld %ld/%ld/%ld\n", tunnel->debug, - (unsigned long long)tunnel->stats.tx_packets, - (unsigned long long)tunnel->stats.tx_bytes, - (unsigned long long)tunnel->stats.tx_errors, - (unsigned long long)tunnel->stats.rx_packets, - (unsigned long long)tunnel->stats.rx_bytes, - (unsigned long long)tunnel->stats.rx_errors); + atomic_long_read(&tunnel->stats.tx_packets), + atomic_long_read(&tunnel->stats.tx_bytes), + atomic_long_read(&tunnel->stats.tx_errors), + atomic_long_read(&tunnel->stats.rx_packets), + atomic_long_read(&tunnel->stats.rx_bytes), + atomic_long_read(&tunnel->stats.rx_errors)); } static void pppol2tp_seq_session_show(struct seq_file *m, void *v) @@ -1708,14 +1669,14 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v) session->lns_mode ? "LNS" : "LAC", session->debug, jiffies_to_msecs(session->reorder_timeout)); - seq_printf(m, " %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n", + seq_printf(m, " %hu/%hu %ld/%ld/%ld %ld/%ld/%ld\n", session->nr, session->ns, - (unsigned long long)session->stats.tx_packets, - (unsigned long long)session->stats.tx_bytes, - (unsigned long long)session->stats.tx_errors, - (unsigned long long)session->stats.rx_packets, - (unsigned long long)session->stats.rx_bytes, - (unsigned long long)session->stats.rx_errors); + atomic_long_read(&session->stats.tx_packets), + atomic_long_read(&session->stats.tx_bytes), + atomic_long_read(&session->stats.tx_errors), + atomic_long_read(&session->stats.rx_packets), + atomic_long_read(&session->stats.rx_bytes), + atomic_long_read(&session->stats.rx_errors)); if (po) seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan)); @@ -1839,7 +1800,7 @@ static const struct pppox_proto pppol2tp_proto = { static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = { .session_create = pppol2tp_session_create, - .session_delete = pppol2tp_session_delete, + .session_delete = l2tp_session_delete, }; #endif /* CONFIG_L2TP_V3 */ diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 47edf5a40a59..61f49d241712 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1394,10 +1394,8 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) skb_reset_network_header(skb); IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n", &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, mtu); - rcu_read_lock(); ipv4_update_pmtu(skb, dev_net(skb->dev), mtu, 0, 0, 0, 0); - rcu_read_unlock(); /* Client uses PMTUD? */ if (!(cih->frag_off & htons(IP_DF))) goto ignore_ipip; @@ -1577,7 +1575,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) } /* ipvs enabled in this netns ? */ net = skb_net(skb); - if (!net_ipvs(net)->enable) + ipvs = net_ipvs(net); + if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable)) return NF_ACCEPT; ip_vs_fill_iph_skb(af, skb, &iph); @@ -1654,7 +1653,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) } IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet"); - ipvs = net_ipvs(net); /* Check the server status */ if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) { /* the destination server is not available */ @@ -1815,13 +1813,15 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb, { int r; struct net *net; + struct netns_ipvs *ipvs; if (ip_hdr(skb)->protocol != IPPROTO_ICMP) return NF_ACCEPT; /* ipvs enabled in this netns ? */ net = skb_net(skb); - if (!net_ipvs(net)->enable) + ipvs = net_ipvs(net); + if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable)) return NF_ACCEPT; return ip_vs_in_icmp(skb, &r, hooknum); @@ -1835,6 +1835,7 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, { int r; struct net *net; + struct netns_ipvs *ipvs; struct ip_vs_iphdr iphdr; ip_vs_fill_iph_skb(AF_INET6, skb, &iphdr); @@ -1843,7 +1844,8 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, /* ipvs enabled in this netns ? */ net = skb_net(skb); - if (!net_ipvs(net)->enable) + ipvs = net_ipvs(net); + if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable)) return NF_ACCEPT; return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c68198bf9128..9e2d1cccd1eb 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1808,6 +1808,12 @@ static struct ctl_table vs_vars[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "backup_only", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, #ifdef CONFIG_IP_VS_DEBUG { .procname = "debug_level", @@ -3741,6 +3747,7 @@ static int __net_init ip_vs_control_net_init_sysctl(struct net *net) tbl[idx++].data = &ipvs->sysctl_nat_icmp_send; ipvs->sysctl_pmtu_disc = 1; tbl[idx++].data = &ipvs->sysctl_pmtu_disc; + tbl[idx++].data = &ipvs->sysctl_backup_only; ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl); diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index ae8ec6f27688..cd1d7298f7ba 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c @@ -906,7 +906,7 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, sctp_chunkhdr_t _sctpch, *sch; unsigned char chunk_type; int event, next_state; - int ihl; + int ihl, cofs; #ifdef CONFIG_IP_VS_IPV6 ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr); @@ -914,8 +914,8 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, ihl = ip_hdrlen(skb); #endif - sch = skb_header_pointer(skb, ihl + sizeof(sctp_sctphdr_t), - sizeof(_sctpch), &_sctpch); + cofs = ihl + sizeof(sctp_sctphdr_t); + sch = skb_header_pointer(skb, cofs, sizeof(_sctpch), &_sctpch); if (sch == NULL) return; @@ -933,10 +933,12 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, */ if ((sch->type == SCTP_CID_COOKIE_ECHO) || (sch->type == SCTP_CID_COOKIE_ACK)) { - sch = skb_header_pointer(skb, (ihl + sizeof(sctp_sctphdr_t) + - sch->length), sizeof(_sctpch), &_sctpch); - if (sch) { - if (sch->type == SCTP_CID_ABORT) + int clen = ntohs(sch->length); + + if (clen >= sizeof(sctp_chunkhdr_t)) { + sch = skb_header_pointer(skb, cofs + ALIGN(clen, 4), + sizeof(_sctpch), &_sctpch); + if (sch && sch->type == SCTP_CID_ABORT) chunk_type = sch->type; } } diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 432f95780003..ba65b2041eb4 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -969,6 +969,10 @@ static int __init nf_conntrack_proto_dccp_init(void) { int ret; + ret = register_pernet_subsys(&dccp_net_ops); + if (ret < 0) + goto out_pernet; + ret = nf_ct_l4proto_register(&dccp_proto4); if (ret < 0) goto out_dccp4; @@ -977,16 +981,12 @@ static int __init nf_conntrack_proto_dccp_init(void) if (ret < 0) goto out_dccp6; - ret = register_pernet_subsys(&dccp_net_ops); - if (ret < 0) - goto out_pernet; - return 0; -out_pernet: - nf_ct_l4proto_unregister(&dccp_proto6); out_dccp6: nf_ct_l4proto_unregister(&dccp_proto4); out_dccp4: + unregister_pernet_subsys(&dccp_net_ops); +out_pernet: return ret; } diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index bd7d01d9c7e7..155ce9f8a0db 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -420,18 +420,18 @@ static int __init nf_ct_proto_gre_init(void) { int ret; - ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre4); - if (ret < 0) - goto out_gre4; - ret = register_pernet_subsys(&proto_gre_net_ops); if (ret < 0) goto out_pernet; + ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre4); + if (ret < 0) + goto out_gre4; + return 0; -out_pernet: - nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4); out_gre4: + unregister_pernet_subsys(&proto_gre_net_ops); +out_pernet: return ret; } diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 480f616d5936..ec83536def9a 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -888,6 +888,10 @@ static int __init nf_conntrack_proto_sctp_init(void) { int ret; + ret = register_pernet_subsys(&sctp_net_ops); + if (ret < 0) + goto out_pernet; + ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_sctp4); if (ret < 0) goto out_sctp4; @@ -896,16 +900,12 @@ static int __init nf_conntrack_proto_sctp_init(void) if (ret < 0) goto out_sctp6; - ret = register_pernet_subsys(&sctp_net_ops); - if (ret < 0) - goto out_pernet; - return 0; -out_pernet: - nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp6); out_sctp6: nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp4); out_sctp4: + unregister_pernet_subsys(&sctp_net_ops); +out_pernet: return ret; } diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 157489581c31..ca969f6273f7 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -371,6 +371,10 @@ static int __init nf_conntrack_proto_udplite_init(void) { int ret; + ret = register_pernet_subsys(&udplite_net_ops); + if (ret < 0) + goto out_pernet; + ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite4); if (ret < 0) goto out_udplite4; @@ -379,16 +383,12 @@ static int __init nf_conntrack_proto_udplite_init(void) if (ret < 0) goto out_udplite6; - ret = register_pernet_subsys(&udplite_net_ops); - if (ret < 0) - goto out_pernet; - return 0; -out_pernet: - nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite6); out_udplite6: nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4); out_udplite4: + unregister_pernet_subsys(&udplite_net_ops); +out_pernet: return ret; } diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 858fd52c1040..1cb48540f86a 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -112,7 +112,7 @@ instance_create(u_int16_t queue_num, int portid) inst->queue_num = queue_num; inst->peer_portid = portid; inst->queue_maxlen = NFQNL_QMAX_DEFAULT; - inst->copy_range = 0xfffff; + inst->copy_range = 0xffff; inst->copy_mode = NFQNL_COPY_NONE; spin_lock_init(&inst->lock); INIT_LIST_HEAD(&inst->queue_list); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index f2aabb6f4105..5a55be3f17a5 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -142,6 +142,7 @@ int genl_register_mc_group(struct genl_family *family, int err = 0; BUG_ON(grp->name[0] == '\0'); + BUG_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL); genl_lock(); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index fb20f25ddec9..f8529fc8e542 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -180,6 +180,8 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); task->tk_waitqueue = queue; queue->qlen++; + /* barrier matches the read in rpc_wake_up_task_queue_locked() */ + smp_wmb(); rpc_set_queued(task); dprintk("RPC: %5u added to queue %p \"%s\"\n", @@ -430,8 +432,11 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task */ static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task) { - if (RPC_IS_QUEUED(task) && task->tk_waitqueue == queue) - __rpc_do_wake_up_task(queue, task); + if (RPC_IS_QUEUED(task)) { + smp_rmb(); + if (task->tk_waitqueue == queue) + __rpc_do_wake_up_task(queue, task); + } } /* diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 51be64f163ec..971282b6f6a3 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -382,7 +382,7 @@ static void unix_sock_destructor(struct sock *sk) #endif } -static int unix_release_sock(struct sock *sk, int embrion) +static void unix_release_sock(struct sock *sk, int embrion) { struct unix_sock *u = unix_sk(sk); struct path path; @@ -451,8 +451,6 @@ static int unix_release_sock(struct sock *sk, int embrion) if (unix_tot_inflight) unix_gc(); /* Garbage collect fds */ - - return 0; } static void init_peercred(struct sock *sk) @@ -699,9 +697,10 @@ static int unix_release(struct socket *sock) if (!sk) return 0; + unix_release_sock(sk, 0); sock->sk = NULL; - return unix_release_sock(sk, 0); + return 0; } static int unix_autobind(struct socket *sock) @@ -1413,8 +1412,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, if (UNIXCB(skb).cred) return; if (test_bit(SOCK_PASSCRED, &sock->flags) || - !other->sk_socket || - test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) { + (other->sk_socket && + test_bit(SOCK_PASSCRED, &other->sk_socket->flags))) { UNIXCB(skb).pid = get_pid(task_tgid(current)); UNIXCB(skb).cred = get_current_cred(); } diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 23414b93771f..13c88fbcf037 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -347,10 +347,8 @@ int yama_ptrace_traceme(struct task_struct *parent) /* Only disallow PTRACE_TRACEME on more aggressive settings. */ switch (ptrace_scope) { case YAMA_SCOPE_CAPABILITY: - rcu_read_lock(); - if (!ns_capable(__task_cred(parent)->user_ns, CAP_SYS_PTRACE)) + if (!has_ns_capability(parent, current_user_ns(), CAP_SYS_PTRACE)) rc = -EPERM; - rcu_read_unlock(); break; case YAMA_SCOPE_NO_ATTACH: rc = -EPERM; |