diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2012-03-04 16:00:27 -0500 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2012-03-04 16:03:30 -0500 |
| commit | 7cb7f82611dddb4b471d42d0fad645dd0dc3f360 (patch) | |
| tree | 61cb56ea1a885c96e6cb78fcd12e6abddd77e27c | |
| parent | 7169ff4a0942adf524f25713eaed30599d438926 (diff) | |
| parent | e77a6b313fdfe4faa8f9a8edf919c7eb8d095fb5 (diff) | |
Merge tag 'tegra-soc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra into tegra/soc-drivers
Tegra SoC driver support.
Some device tree conversions, some new drivers. and a fix for an issue
introduced in Grant Likely's irq_domain conversion in his tree. Because
of that, this branch depends on his branch to build (but not to merge):
git://git.secretlab.ca/git/linux-2.6.git irqdomain/next
* tag 'tegra-soc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra: (34 commits)
ARM: tegra: uncompress.h: Don't depend on kernel headers
gpio: tegra: Fix build issue due to irq_domain rework.
ARM: tegra: Remove duplicate PMU interrupt inversion code
ARM: tegra: Add a simple PMC driver
ARM: tegra: dma: not required to move requestor when stopping.
ARM: tegra: Fix EMC pdata initialization from registers
gpio: tegra: Parameterize the number of banks
gpio: tegra: Dynamically allocate IRQ base, and support DT
ARM: tegra: Remove use of TEGRA_GPIO_TO_IRQ
ARM: tegra: Pass uncompress.h UART selection to DEBUG_LL
ARM: tegra: uncompress.h: Choose a UART at runtime
ARM: tegra: uncompress.h: Store UART address in a variable
ARM: tegra: Introduce define DEBUG_UART_SHIFT
ARM: tegra: Support Tegra30 in decompressor UART setup
ARM: tegra: Pause DMA when reading transfer count
ARM: tegra: emc: device tree support
ARM: tegra: emc: convert tegra2_emc to a platform driver
ARM: tegra: fuse: add bct strapping reading
ARM: tegra: fuse: add functions to access chip revision
ARM: tegra: fuse: use apbio dma for register access
...
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
32 files changed, 1467 insertions, 193 deletions
diff --git a/Documentation/devicetree/bindings/arm/tegra/emc.txt b/Documentation/devicetree/bindings/arm/tegra/emc.txt new file mode 100644 index 000000000000..09335f8eee00 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra/emc.txt | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | Embedded Memory Controller | ||
| 2 | |||
| 3 | Properties: | ||
| 4 | - name : Should be emc | ||
| 5 | - #address-cells : Should be 1 | ||
| 6 | - #size-cells : Should be 0 | ||
| 7 | - compatible : Should contain "nvidia,tegra20-emc". | ||
| 8 | - reg : Offset and length of the register set for the device | ||
| 9 | - nvidia,use-ram-code : If present, the sub-nodes will be addressed | ||
| 10 | and chosen using the ramcode board selector. If omitted, only one | ||
| 11 | set of tables can be present and said tables will be used | ||
| 12 | irrespective of ram-code configuration. | ||
| 13 | |||
| 14 | Child device nodes describe the memory settings for different configurations and clock rates. | ||
| 15 | |||
| 16 | Example: | ||
| 17 | |||
| 18 | emc@7000f400 { | ||
| 19 | #address-cells = < 1 >; | ||
| 20 | #size-cells = < 0 >; | ||
| 21 | compatible = "nvidia,tegra20-emc"; | ||
| 22 | reg = <0x7000f4000 0x200>; | ||
| 23 | } | ||
| 24 | |||
| 25 | |||
| 26 | Embedded Memory Controller ram-code table | ||
| 27 | |||
| 28 | If the emc node has the nvidia,use-ram-code property present, then the | ||
| 29 | next level of nodes below the emc table are used to specify which settings | ||
| 30 | apply for which ram-code settings. | ||
| 31 | |||
| 32 | If the emc node lacks the nvidia,use-ram-code property, this level is omitted | ||
| 33 | and the tables are stored directly under the emc node (see below). | ||
| 34 | |||
| 35 | Properties: | ||
| 36 | |||
| 37 | - name : Should be emc-tables | ||
| 38 | - nvidia,ram-code : the binary representation of the ram-code board strappings | ||
| 39 | for which this node (and children) are valid. | ||
| 40 | |||
| 41 | |||
| 42 | |||
| 43 | Embedded Memory Controller configuration table | ||
| 44 | |||
| 45 | This is a table containing the EMC register settings for the various | ||
| 46 | operating speeds of the memory controller. They are always located as | ||
| 47 | subnodes of the emc controller node. | ||
| 48 | |||
| 49 | There are two ways of specifying which tables to use: | ||
| 50 | |||
| 51 | * The simplest is if there is just one set of tables in the device tree, | ||
| 52 | and they will always be used (based on which frequency is used). | ||
| 53 | This is the preferred method, especially when firmware can fill in | ||
| 54 | this information based on the specific system information and just | ||
| 55 | pass it on to the kernel. | ||
| 56 | |||
| 57 | * The slightly more complex one is when more than one memory configuration | ||
| 58 | might exist on the system. The Tegra20 platform handles this during | ||
| 59 | early boot by selecting one out of possible 4 memory settings based | ||
| 60 | on a 2-pin "ram code" bootstrap setting on the board. The values of | ||
| 61 | these strappings can be read through a register in the SoC, and thus | ||
| 62 | used to select which tables to use. | ||
| 63 | |||
| 64 | Properties: | ||
| 65 | - name : Should be emc-table | ||
| 66 | - compatible : Should contain "nvidia,tegra20-emc-table". | ||
| 67 | - reg : either an opaque enumerator to tell different tables apart, or | ||
| 68 | the valid frequency for which the table should be used (in kHz). | ||
| 69 | - clock-frequency : the clock frequency for the EMC at which this | ||
| 70 | table should be used (in kHz). | ||
| 71 | - nvidia,emc-registers : a 46 word array of EMC registers to be programmed | ||
| 72 | for operation at the 'clock-frequency' setting. | ||
| 73 | The order and contents of the registers are: | ||
| 74 | RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT, | ||
| 75 | WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR, | ||
| 76 | PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW, | ||
| 77 | TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE, | ||
| 78 | ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE, | ||
| 79 | ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0, | ||
| 80 | CFG_CLKTRIM_1, CFG_CLKTRIM_2 | ||
| 81 | |||
| 82 | emc-table@166000 { | ||
| 83 | reg = <166000>; | ||
| 84 | compatible = "nvidia,tegra20-emc-table"; | ||
| 85 | clock-frequency = < 166000 >; | ||
| 86 | nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
| 87 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
| 88 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
| 89 | 0 0 0 0 >; | ||
| 90 | }; | ||
| 91 | |||
| 92 | emc-table@333000 { | ||
| 93 | reg = <333000>; | ||
| 94 | compatible = "nvidia,tegra20-emc-table"; | ||
| 95 | clock-frequency = < 333000 >; | ||
| 96 | nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
| 97 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
| 98 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
| 99 | 0 0 0 0 >; | ||
| 100 | }; | ||
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt new file mode 100644 index 000000000000..b5846e21cc2e --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | NVIDIA Tegra Power Management Controller (PMC) | ||
| 2 | |||
| 3 | Properties: | ||
| 4 | - name : Should be pmc | ||
| 5 | - compatible : Should contain "nvidia,tegra<chip>-pmc". | ||
| 6 | - reg : Offset and length of the register set for the device | ||
| 7 | - nvidia,invert-interrupt : If present, inverts the PMU interrupt signal. | ||
| 8 | The PMU is an external Power Management Unit, whose interrupt output | ||
| 9 | signal is fed into the PMC. This signal is optionally inverted, and then | ||
| 10 | fed into the ARM GIC. The PMC is not involved in the detection or | ||
| 11 | handling of this interrupt signal, merely its inversion. | ||
| 12 | |||
| 13 | Example: | ||
| 14 | |||
| 15 | pmc@7000f400 { | ||
| 16 | compatible = "nvidia,tegra20-pmc"; | ||
| 17 | reg = <0x7000e400 0x400>; | ||
| 18 | nvidia,invert-interrupt; | ||
| 19 | }; | ||
diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt new file mode 100644 index 000000000000..90fa7da525b8 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | * NVIDIA Tegra APB DMA controller | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "nvidia,<chip>-apbdma" | ||
| 5 | - reg: Should contain DMA registers location and length. This shuld include | ||
| 6 | all of the per-channel registers. | ||
| 7 | - interrupts: Should contain all of the per-channel DMA interrupts. | ||
| 8 | |||
| 9 | Examples: | ||
| 10 | |||
| 11 | apbdma: dma@6000a000 { | ||
| 12 | compatible = "nvidia,tegra20-apbdma"; | ||
| 13 | reg = <0x6000a000 0x1200>; | ||
| 14 | interrupts = < 0 136 0x04 | ||
| 15 | 0 137 0x04 | ||
| 16 | 0 138 0x04 | ||
| 17 | 0 139 0x04 | ||
| 18 | 0 140 0x04 | ||
| 19 | 0 141 0x04 | ||
| 20 | 0 142 0x04 | ||
| 21 | 0 143 0x04 | ||
| 22 | 0 144 0x04 | ||
| 23 | 0 145 0x04 | ||
| 24 | 0 146 0x04 | ||
| 25 | 0 147 0x04 | ||
| 26 | 0 148 0x04 | ||
| 27 | 0 149 0x04 | ||
| 28 | 0 150 0x04 | ||
| 29 | 0 151 0x04 >; | ||
| 30 | }; | ||
diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt index eb4b530d64e1..023c9526e5f8 100644 --- a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt +++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt | |||
| @@ -1,8 +1,40 @@ | |||
| 1 | NVIDIA Tegra 2 GPIO controller | 1 | NVIDIA Tegra GPIO controller |
| 2 | 2 | ||
| 3 | Required properties: | 3 | Required properties: |
| 4 | - compatible : "nvidia,tegra20-gpio" | 4 | - compatible : "nvidia,tegra<chip>-gpio" |
| 5 | - reg : Physical base address and length of the controller's registers. | ||
| 6 | - interrupts : The interrupt outputs from the controller. For Tegra20, | ||
| 7 | there should be 7 interrupts specified, and for Tegra30, there should | ||
| 8 | be 8 interrupts specified. | ||
| 5 | - #gpio-cells : Should be two. The first cell is the pin number and the | 9 | - #gpio-cells : Should be two. The first cell is the pin number and the |
| 6 | second cell is used to specify optional parameters: | 10 | second cell is used to specify optional parameters: |
| 7 | - bit 0 specifies polarity (0 for normal, 1 for inverted) | 11 | - bit 0 specifies polarity (0 for normal, 1 for inverted) |
| 8 | - gpio-controller : Marks the device node as a GPIO controller. | 12 | - gpio-controller : Marks the device node as a GPIO controller. |
| 13 | - #interrupt-cells : Should be 2. | ||
| 14 | The first cell is the GPIO number. | ||
| 15 | The second cell is used to specify flags: | ||
| 16 | bits[3:0] trigger type and level flags: | ||
| 17 | 1 = low-to-high edge triggered. | ||
| 18 | 2 = high-to-low edge triggered. | ||
| 19 | 4 = active high level-sensitive. | ||
| 20 | 8 = active low level-sensitive. | ||
| 21 | Valid combinations are 1, 2, 3, 4, 8. | ||
| 22 | - interrupt-controller : Marks the device node as an interrupt controller. | ||
| 23 | |||
| 24 | Example: | ||
| 25 | |||
| 26 | gpio: gpio@6000d000 { | ||
| 27 | compatible = "nvidia,tegra20-gpio"; | ||
| 28 | reg = < 0x6000d000 0x1000 >; | ||
| 29 | interrupts = < 0 32 0x04 | ||
| 30 | 0 33 0x04 | ||
| 31 | 0 34 0x04 | ||
| 32 | 0 35 0x04 | ||
| 33 | 0 55 0x04 | ||
| 34 | 0 87 0x04 | ||
| 35 | 0 89 0x04 >; | ||
| 36 | #gpio-cells = <2>; | ||
| 37 | gpio-controller; | ||
| 38 | #interrupt-cells = <2>; | ||
| 39 | interrupt-controller; | ||
| 40 | }; | ||
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts index 80afa1b70b80..6e8447dc0202 100644 --- a/arch/arm/boot/dts/tegra-harmony.dts +++ b/arch/arm/boot/dts/tegra-harmony.dts | |||
| @@ -10,19 +10,25 @@ | |||
| 10 | reg = < 0x00000000 0x40000000 >; | 10 | reg = < 0x00000000 0x40000000 >; |
| 11 | }; | 11 | }; |
| 12 | 12 | ||
| 13 | pmc@7000f400 { | ||
| 14 | nvidia,invert-interrupt; | ||
| 15 | }; | ||
| 16 | |||
| 13 | i2c@7000c000 { | 17 | i2c@7000c000 { |
| 14 | clock-frequency = <400000>; | 18 | clock-frequency = <400000>; |
| 15 | 19 | ||
| 16 | codec: wm8903@1a { | 20 | wm8903: wm8903@1a { |
| 17 | compatible = "wlf,wm8903"; | 21 | compatible = "wlf,wm8903"; |
| 18 | reg = <0x1a>; | 22 | reg = <0x1a>; |
| 19 | interrupts = < 347 >; | 23 | interrupt-parent = <&gpio>; |
| 24 | interrupts = < 187 0x04 >; | ||
| 20 | 25 | ||
| 21 | gpio-controller; | 26 | gpio-controller; |
| 22 | #gpio-cells = <2>; | 27 | #gpio-cells = <2>; |
| 23 | 28 | ||
| 24 | /* 0x8000 = Not configured */ | 29 | micdet-cfg = <0>; |
| 25 | gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >; | 30 | micdet-delay = <100>; |
| 31 | gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; | ||
| 26 | }; | 32 | }; |
| 27 | }; | 33 | }; |
| 28 | 34 | ||
| @@ -38,13 +44,32 @@ | |||
| 38 | clock-frequency = <400000>; | 44 | clock-frequency = <400000>; |
| 39 | }; | 45 | }; |
| 40 | 46 | ||
| 41 | sound { | 47 | i2s@70002a00 { |
| 42 | compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903"; | 48 | status = "disable"; |
| 49 | }; | ||
| 43 | 50 | ||
| 44 | spkr-en-gpios = <&codec 2 0>; | 51 | sound { |
| 45 | hp-det-gpios = <&gpio 178 0>; | 52 | compatible = "nvidia,tegra-audio-wm8903-harmony", |
| 46 | int-mic-en-gpios = <&gpio 184 0>; | 53 | "nvidia,tegra-audio-wm8903"; |
| 47 | ext-mic-en-gpios = <&gpio 185 0>; | 54 | nvidia,model = "NVIDIA Tegra Harmony"; |
| 55 | |||
| 56 | nvidia,audio-routing = | ||
| 57 | "Headphone Jack", "HPOUTR", | ||
| 58 | "Headphone Jack", "HPOUTL", | ||
| 59 | "Int Spk", "ROP", | ||
| 60 | "Int Spk", "RON", | ||
| 61 | "Int Spk", "LOP", | ||
| 62 | "Int Spk", "LON", | ||
| 63 | "Mic Jack", "MICBIAS", | ||
| 64 | "IN1L", "Mic Jack"; | ||
| 65 | |||
| 66 | nvidia,i2s-controller = <&tegra_i2s1>; | ||
| 67 | nvidia,audio-codec = <&wm8903>; | ||
| 68 | |||
| 69 | nvidia,spkr-en-gpios = <&wm8903 2 0>; | ||
| 70 | nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ | ||
| 71 | nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ | ||
| 72 | nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ | ||
| 48 | }; | 73 | }; |
| 49 | 74 | ||
| 50 | serial@70006000 { | 75 | serial@70006000 { |
diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts index 825d2957da0b..e4b552b46fe2 100644 --- a/arch/arm/boot/dts/tegra-paz00.dts +++ b/arch/arm/boot/dts/tegra-paz00.dts | |||
| @@ -12,6 +12,13 @@ | |||
| 12 | 12 | ||
| 13 | i2c@7000c000 { | 13 | i2c@7000c000 { |
| 14 | clock-frequency = <400000>; | 14 | clock-frequency = <400000>; |
| 15 | |||
| 16 | alc5632: alc5632@1e { | ||
| 17 | compatible = "realtek,alc5632"; | ||
| 18 | reg = <0x1e>; | ||
| 19 | gpio-controller; | ||
| 20 | #gpio-cells = <2>; | ||
| 21 | }; | ||
| 15 | }; | 22 | }; |
| 16 | 23 | ||
| 17 | i2c@7000c400 { | 24 | i2c@7000c400 { |
| @@ -37,6 +44,29 @@ | |||
| 37 | clock-frequency = <400000>; | 44 | clock-frequency = <400000>; |
| 38 | }; | 45 | }; |
| 39 | 46 | ||
| 47 | i2s@70002a00 { | ||
| 48 | status = "disable"; | ||
| 49 | }; | ||
| 50 | |||
| 51 | sound { | ||
| 52 | compatible = "nvidia,tegra-audio-alc5632-paz00", | ||
| 53 | "nvidia,tegra-audio-alc5632"; | ||
| 54 | |||
| 55 | nvidia,model = "Compal PAZ00"; | ||
| 56 | |||
| 57 | nvidia,audio-routing = | ||
| 58 | "Int Spk", "SPKOUT", | ||
| 59 | "Int Spk", "SPKOUTN", | ||
| 60 | "Headset Mic", "MICBIAS1", | ||
| 61 | "MIC1", "Headset Mic", | ||
| 62 | "Headset Stereophone", "HPR", | ||
| 63 | "Headset Stereophone", "HPL"; | ||
| 64 | |||
| 65 | nvidia,audio-codec = <&alc5632>; | ||
| 66 | nvidia,i2s-controller = <&tegra_i2s1>; | ||
| 67 | nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ | ||
| 68 | }; | ||
| 69 | |||
| 40 | serial@70006000 { | 70 | serial@70006000 { |
| 41 | clock-frequency = <216000000>; | 71 | clock-frequency = <216000000>; |
| 42 | }; | 72 | }; |
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts index b55a02e34ba7..876d5c92ce36 100644 --- a/arch/arm/boot/dts/tegra-seaboard.dts +++ b/arch/arm/boot/dts/tegra-seaboard.dts | |||
| @@ -13,6 +13,20 @@ | |||
| 13 | 13 | ||
| 14 | i2c@7000c000 { | 14 | i2c@7000c000 { |
| 15 | clock-frequency = <400000>; | 15 | clock-frequency = <400000>; |
| 16 | |||
| 17 | wm8903: wm8903@1a { | ||
| 18 | compatible = "wlf,wm8903"; | ||
| 19 | reg = <0x1a>; | ||
| 20 | interrupt-parent = <&gpio>; | ||
| 21 | interrupts = < 187 0x04 >; | ||
| 22 | |||
| 23 | gpio-controller; | ||
| 24 | #gpio-cells = <2>; | ||
| 25 | |||
| 26 | micdet-cfg = <0>; | ||
| 27 | micdet-delay = <100>; | ||
| 28 | gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; | ||
| 29 | }; | ||
| 16 | }; | 30 | }; |
| 17 | 31 | ||
| 18 | i2c@7000c400 { | 32 | i2c@7000c400 { |
| @@ -32,6 +46,32 @@ | |||
| 32 | }; | 46 | }; |
| 33 | }; | 47 | }; |
| 34 | 48 | ||
| 49 | i2s@70002a00 { | ||
| 50 | status = "disable"; | ||
| 51 | }; | ||
| 52 | |||
| 53 | sound { | ||
| 54 | compatible = "nvidia,tegra-audio-wm8903-seaboard", | ||
| 55 | "nvidia,tegra-audio-wm8903"; | ||
| 56 | nvidia,model = "NVIDIA Tegra Seaboard"; | ||
| 57 | |||
| 58 | nvidia,audio-routing = | ||
| 59 | "Headphone Jack", "HPOUTR", | ||
| 60 | "Headphone Jack", "HPOUTL", | ||
| 61 | "Int Spk", "ROP", | ||
| 62 | "Int Spk", "RON", | ||
| 63 | "Int Spk", "LOP", | ||
| 64 | "Int Spk", "LON", | ||
| 65 | "Mic Jack", "MICBIAS", | ||
| 66 | "IN1R", "Mic Jack"; | ||
| 67 | |||
| 68 | nvidia,i2s-controller = <&tegra_i2s1>; | ||
| 69 | nvidia,audio-codec = <&wm8903>; | ||
| 70 | |||
| 71 | nvidia,spkr-en-gpios = <&wm8903 2 0>; | ||
| 72 | nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */ | ||
| 73 | }; | ||
| 74 | |||
| 35 | serial@70006000 { | 75 | serial@70006000 { |
| 36 | status = "disable"; | 76 | status = "disable"; |
| 37 | }; | 77 | }; |
| @@ -93,4 +133,42 @@ | |||
| 93 | gpio-key,wakeup; | 133 | gpio-key,wakeup; |
| 94 | }; | 134 | }; |
| 95 | }; | 135 | }; |
| 136 | |||
| 137 | emc@7000f400 { | ||
| 138 | emc-table@190000 { | ||
| 139 | reg = < 190000 >; | ||
| 140 | compatible = "nvidia,tegra20-emc-table"; | ||
| 141 | clock-frequency = < 190000 >; | ||
| 142 | nvidia,emc-registers = < 0x0000000c 0x00000026 | ||
| 143 | 0x00000009 0x00000003 0x00000004 0x00000004 | ||
| 144 | 0x00000002 0x0000000c 0x00000003 0x00000003 | ||
| 145 | 0x00000002 0x00000001 0x00000004 0x00000005 | ||
| 146 | 0x00000004 0x00000009 0x0000000d 0x0000059f | ||
| 147 | 0x00000000 0x00000003 0x00000003 0x00000003 | ||
| 148 | 0x00000003 0x00000001 0x0000000b 0x000000c8 | ||
| 149 | 0x00000003 0x00000007 0x00000004 0x0000000f | ||
| 150 | 0x00000002 0x00000000 0x00000000 0x00000002 | ||
| 151 | 0x00000000 0x00000000 0x00000083 0xa06204ae | ||
| 152 | 0x007dc010 0x00000000 0x00000000 0x00000000 | ||
| 153 | 0x00000000 0x00000000 0x00000000 0x00000000 >; | ||
| 154 | }; | ||
| 155 | |||
| 156 | emc-table@380000 { | ||
| 157 | reg = < 380000 >; | ||
| 158 | compatible = "nvidia,tegra20-emc-table"; | ||
| 159 | clock-frequency = < 380000 >; | ||
| 160 | nvidia,emc-registers = < 0x00000017 0x0000004b | ||
| 161 | 0x00000012 0x00000006 0x00000004 0x00000005 | ||
| 162 | 0x00000003 0x0000000c 0x00000006 0x00000006 | ||
| 163 | 0x00000003 0x00000001 0x00000004 0x00000005 | ||
| 164 | 0x00000004 0x00000009 0x0000000d 0x00000b5f | ||
| 165 | 0x00000000 0x00000003 0x00000003 0x00000006 | ||
| 166 | 0x00000006 0x00000001 0x00000011 0x000000c8 | ||
| 167 | 0x00000003 0x0000000e 0x00000007 0x0000000f | ||
| 168 | 0x00000002 0x00000000 0x00000000 0x00000002 | ||
| 169 | 0x00000000 0x00000000 0x00000083 0xe044048b | ||
| 170 | 0x007d8010 0x00000000 0x00000000 0x00000000 | ||
| 171 | 0x00000000 0x00000000 0x00000000 0x00000000 >; | ||
| 172 | }; | ||
| 173 | }; | ||
| 96 | }; | 174 | }; |
diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts index 3b3ee7db99f3..252476867b54 100644 --- a/arch/arm/boot/dts/tegra-trimslice.dts +++ b/arch/arm/boot/dts/tegra-trimslice.dts | |||
| @@ -26,6 +26,18 @@ | |||
| 26 | status = "disable"; | 26 | status = "disable"; |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | i2s@70002800 { | ||
| 30 | status = "disable"; | ||
| 31 | }; | ||
| 32 | |||
| 33 | i2s@70002a00 { | ||
| 34 | status = "disable"; | ||
| 35 | }; | ||
| 36 | |||
| 37 | das@70000c00 { | ||
| 38 | status = "disable"; | ||
| 39 | }; | ||
| 40 | |||
| 29 | serial@70006000 { | 41 | serial@70006000 { |
| 30 | clock-frequency = < 216000000 >; | 42 | clock-frequency = < 216000000 >; |
| 31 | }; | 43 | }; |
diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts index c7d3b87f29df..2dcff8728e90 100644 --- a/arch/arm/boot/dts/tegra-ventana.dts +++ b/arch/arm/boot/dts/tegra-ventana.dts | |||
| @@ -12,6 +12,20 @@ | |||
| 12 | 12 | ||
| 13 | i2c@7000c000 { | 13 | i2c@7000c000 { |
| 14 | clock-frequency = <400000>; | 14 | clock-frequency = <400000>; |
| 15 | |||
| 16 | wm8903: wm8903@1a { | ||
| 17 | compatible = "wlf,wm8903"; | ||
| 18 | reg = <0x1a>; | ||
| 19 | interrupt-parent = <&gpio>; | ||
| 20 | interrupts = < 187 0x04 >; | ||
| 21 | |||
| 22 | gpio-controller; | ||
| 23 | #gpio-cells = <2>; | ||
| 24 | |||
| 25 | micdet-cfg = <0>; | ||
| 26 | micdet-delay = <100>; | ||
| 27 | gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; | ||
| 28 | }; | ||
| 15 | }; | 29 | }; |
| 16 | 30 | ||
| 17 | i2c@7000c400 { | 31 | i2c@7000c400 { |
| @@ -26,6 +40,34 @@ | |||
| 26 | clock-frequency = <400000>; | 40 | clock-frequency = <400000>; |
| 27 | }; | 41 | }; |
| 28 | 42 | ||
| 43 | i2s@70002a00 { | ||
| 44 | status = "disable"; | ||
| 45 | }; | ||
| 46 | |||
| 47 | sound { | ||
| 48 | compatible = "nvidia,tegra-audio-wm8903-ventana", | ||
| 49 | "nvidia,tegra-audio-wm8903"; | ||
| 50 | nvidia,model = "NVIDIA Tegra Ventana"; | ||
| 51 | |||
| 52 | nvidia,audio-routing = | ||
| 53 | "Headphone Jack", "HPOUTR", | ||
| 54 | "Headphone Jack", "HPOUTL", | ||
| 55 | "Int Spk", "ROP", | ||
| 56 | "Int Spk", "RON", | ||
| 57 | "Int Spk", "LOP", | ||
| 58 | "Int Spk", "LON", | ||
| 59 | "Mic Jack", "MICBIAS", | ||
| 60 | "IN1L", "Mic Jack"; | ||
| 61 | |||
| 62 | nvidia,i2s-controller = <&tegra_i2s1>; | ||
| 63 | nvidia,audio-codec = <&wm8903>; | ||
| 64 | |||
| 65 | nvidia,spkr-en-gpios = <&wm8903 2 0>; | ||
| 66 | nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ | ||
| 67 | nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ | ||
| 68 | nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ | ||
| 69 | }; | ||
| 70 | |||
| 29 | serial@70006000 { | 71 | serial@70006000 { |
| 30 | status = "disable"; | 72 | status = "disable"; |
| 31 | }; | 73 | }; |
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 3da7afd45322..ec1f0101c79c 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi | |||
| @@ -4,6 +4,11 @@ | |||
| 4 | compatible = "nvidia,tegra20"; | 4 | compatible = "nvidia,tegra20"; |
| 5 | interrupt-parent = <&intc>; | 5 | interrupt-parent = <&intc>; |
| 6 | 6 | ||
| 7 | pmc@7000f400 { | ||
| 8 | compatible = "nvidia,tegra20-pmc"; | ||
| 9 | reg = <0x7000e400 0x400>; | ||
| 10 | }; | ||
| 11 | |||
| 7 | intc: interrupt-controller@50041000 { | 12 | intc: interrupt-controller@50041000 { |
| 8 | compatible = "arm,cortex-a9-gic"; | 13 | compatible = "arm,cortex-a9-gic"; |
| 9 | interrupt-controller; | 14 | interrupt-controller; |
| @@ -12,6 +17,27 @@ | |||
| 12 | < 0x50040100 0x0100 >; | 17 | < 0x50040100 0x0100 >; |
| 13 | }; | 18 | }; |
| 14 | 19 | ||
| 20 | apbdma: dma@6000a000 { | ||
| 21 | compatible = "nvidia,tegra20-apbdma"; | ||
| 22 | reg = <0x6000a000 0x1200>; | ||
| 23 | interrupts = < 0 104 0x04 | ||
| 24 | 0 105 0x04 | ||
| 25 | 0 106 0x04 | ||
| 26 | 0 107 0x04 | ||
| 27 | 0 108 0x04 | ||
| 28 | 0 109 0x04 | ||
| 29 | 0 110 0x04 | ||
| 30 | 0 111 0x04 | ||
| 31 | 0 112 0x04 | ||
| 32 | 0 113 0x04 | ||
| 33 | 0 114 0x04 | ||
| 34 | 0 115 0x04 | ||
| 35 | 0 116 0x04 | ||
| 36 | 0 117 0x04 | ||
| 37 | 0 118 0x04 | ||
| 38 | 0 119 0x04 >; | ||
| 39 | }; | ||
| 40 | |||
| 15 | i2c@7000c000 { | 41 | i2c@7000c000 { |
| 16 | #address-cells = <1>; | 42 | #address-cells = <1>; |
| 17 | #size-cells = <0>; | 43 | #size-cells = <0>; |
| @@ -44,18 +70,18 @@ | |||
| 44 | interrupts = < 0 53 0x04 >; | 70 | interrupts = < 0 53 0x04 >; |
| 45 | }; | 71 | }; |
| 46 | 72 | ||
| 47 | i2s@70002800 { | 73 | tegra_i2s1: i2s@70002800 { |
| 48 | compatible = "nvidia,tegra20-i2s"; | 74 | compatible = "nvidia,tegra20-i2s"; |
| 49 | reg = <0x70002800 0x200>; | 75 | reg = <0x70002800 0x200>; |
| 50 | interrupts = < 0 13 0x04 >; | 76 | interrupts = < 0 13 0x04 >; |
| 51 | dma-channel = < 2 >; | 77 | nvidia,dma-request-selector = < &apbdma 2 >; |
| 52 | }; | 78 | }; |
| 53 | 79 | ||
| 54 | i2s@70002a00 { | 80 | tegra_i2s2: i2s@70002a00 { |
| 55 | compatible = "nvidia,tegra20-i2s"; | 81 | compatible = "nvidia,tegra20-i2s"; |
| 56 | reg = <0x70002a00 0x200>; | 82 | reg = <0x70002a00 0x200>; |
| 57 | interrupts = < 0 3 0x04 >; | 83 | interrupts = < 0 3 0x04 >; |
| 58 | dma-channel = < 1 >; | 84 | nvidia,dma-request-selector = < &apbdma 1 >; |
| 59 | }; | 85 | }; |
| 60 | 86 | ||
| 61 | das@70000c00 { | 87 | das@70000c00 { |
| @@ -75,6 +101,8 @@ | |||
| 75 | 0 89 0x04 >; | 101 | 0 89 0x04 >; |
| 76 | #gpio-cells = <2>; | 102 | #gpio-cells = <2>; |
| 77 | gpio-controller; | 103 | gpio-controller; |
| 104 | #interrupt-cells = <2>; | ||
| 105 | interrupt-controller; | ||
| 78 | }; | 106 | }; |
| 79 | 107 | ||
| 80 | pinmux: pinmux@70000000 { | 108 | pinmux: pinmux@70000000 { |
| @@ -120,6 +148,13 @@ | |||
| 120 | interrupts = < 0 91 0x04 >; | 148 | interrupts = < 0 91 0x04 >; |
| 121 | }; | 149 | }; |
| 122 | 150 | ||
| 151 | emc@7000f400 { | ||
| 152 | #address-cells = <1>; | ||
| 153 | #size-cells = <0>; | ||
| 154 | compatible = "nvidia,tegra20-emc"; | ||
| 155 | reg = <0x7000f400 0x200>; | ||
| 156 | }; | ||
| 157 | |||
| 123 | sdhci@c8000000 { | 158 | sdhci@c8000000 { |
| 124 | compatible = "nvidia,tegra20-sdhci"; | 159 | compatible = "nvidia,tegra20-sdhci"; |
| 125 | reg = <0xc8000000 0x200>; | 160 | reg = <0xc8000000 0x200>; |
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index ee7db9892e02..ac4b75cb26c0 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi | |||
| @@ -4,6 +4,11 @@ | |||
| 4 | compatible = "nvidia,tegra30"; | 4 | compatible = "nvidia,tegra30"; |
| 5 | interrupt-parent = <&intc>; | 5 | interrupt-parent = <&intc>; |
| 6 | 6 | ||
| 7 | pmc@7000f400 { | ||
| 8 | compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc"; | ||
| 9 | reg = <0x7000e400 0x400>; | ||
| 10 | }; | ||
| 11 | |||
| 7 | intc: interrupt-controller@50041000 { | 12 | intc: interrupt-controller@50041000 { |
| 8 | compatible = "arm,cortex-a9-gic"; | 13 | compatible = "arm,cortex-a9-gic"; |
| 9 | interrupt-controller; | 14 | interrupt-controller; |
| @@ -12,6 +17,43 @@ | |||
| 12 | < 0x50040100 0x0100 >; | 17 | < 0x50040100 0x0100 >; |
| 13 | }; | 18 | }; |
| 14 | 19 | ||
| 20 | apbdma: dma@6000a000 { | ||
| 21 | compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; | ||
| 22 | reg = <0x6000a000 0x1400>; | ||
| 23 | interrupts = < 0 104 0x04 | ||
| 24 | 0 105 0x04 | ||
| 25 | 0 106 0x04 | ||
| 26 | 0 107 0x04 | ||
| 27 | 0 108 0x04 | ||
| 28 | 0 109 0x04 | ||
| 29 | 0 110 0x04 | ||
| 30 | 0 111 0x04 | ||
| 31 | 0 112 0x04 | ||
| 32 | 0 113 0x04 | ||
| 33 | 0 114 0x04 | ||
| 34 | 0 115 0x04 | ||
| 35 | 0 116 0x04 | ||
| 36 | 0 117 0x04 | ||
| 37 | 0 118 0x04 | ||
| 38 | 0 119 0x04 | ||
| 39 | 0 128 0x04 | ||
| 40 | 0 129 0x04 | ||
| 41 | 0 130 0x04 | ||
| 42 | 0 131 0x04 | ||
| 43 | 0 132 0x04 | ||
| 44 | 0 133 0x04 | ||
| 45 | 0 134 0x04 | ||
| 46 | 0 135 0x04 | ||
| 47 | 0 136 0x04 | ||
| 48 | 0 137 0x04 | ||
| 49 | 0 138 0x04 | ||
| 50 | 0 139 0x04 | ||
| 51 | 0 140 0x04 | ||
| 52 | 0 141 0x04 | ||
| 53 | 0 142 0x04 | ||
| 54 | 0 143 0x04 >; | ||
| 55 | }; | ||
| 56 | |||
| 15 | i2c@7000c000 { | 57 | i2c@7000c000 { |
| 16 | #address-cells = <1>; | 58 | #address-cells = <1>; |
| 17 | #size-cells = <0>; | 59 | #size-cells = <0>; |
| @@ -55,9 +97,18 @@ | |||
| 55 | gpio: gpio@6000d000 { | 97 | gpio: gpio@6000d000 { |
| 56 | compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio"; | 98 | compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio"; |
| 57 | reg = < 0x6000d000 0x1000 >; | 99 | reg = < 0x6000d000 0x1000 >; |
| 58 | interrupts = < 0 32 0x04 0 33 0x04 0 34 0x04 0 35 0x04 0 55 0x04 0 87 0x04 0 89 0x04 >; | 100 | interrupts = < 0 32 0x04 |
| 101 | 0 33 0x04 | ||
| 102 | 0 34 0x04 | ||
| 103 | 0 35 0x04 | ||
| 104 | 0 55 0x04 | ||
| 105 | 0 87 0x04 | ||
| 106 | 0 89 0x04 | ||
| 107 | 0 125 0x04 >; | ||
| 59 | #gpio-cells = <2>; | 108 | #gpio-cells = <2>; |
| 60 | gpio-controller; | 109 | gpio-controller; |
| 110 | #interrupt-cells = <2>; | ||
| 111 | interrupt-controller; | ||
| 61 | }; | 112 | }; |
| 62 | 113 | ||
| 63 | serial@70006000 { | 114 | serial@70006000 { |
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index e120ff54f663..e0b7a4d32599 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile | |||
| @@ -7,6 +7,7 @@ obj-y += clock.o | |||
| 7 | obj-y += timer.o | 7 | obj-y += timer.o |
| 8 | obj-y += pinmux.o | 8 | obj-y += pinmux.o |
| 9 | obj-y += fuse.o | 9 | obj-y += fuse.o |
| 10 | obj-y += pmc.o | ||
| 10 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o | 11 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o |
| 11 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o | 12 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o |
| 12 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o | 13 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o |
| @@ -15,7 +16,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pinmux-tegra30-tables.o | |||
| 15 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o | 16 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o |
| 16 | obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o | 17 | obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o |
| 17 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 18 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
| 18 | obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o | 19 | obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o apbio.o |
| 19 | obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o | 20 | obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o |
| 20 | obj-$(CONFIG_TEGRA_PCI) += pcie.o | 21 | obj-$(CONFIG_TEGRA_PCI) += pcie.o |
| 21 | obj-$(CONFIG_USB_SUPPORT) += usb_phy.o | 22 | obj-$(CONFIG_USB_SUPPORT) += usb_phy.o |
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c new file mode 100644 index 000000000000..e75451e517bd --- /dev/null +++ b/arch/arm/mach-tegra/apbio.c | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 NVIDIA Corporation. | ||
| 3 | * Copyright (C) 2010 Google, Inc. | ||
| 4 | * | ||
| 5 | * This software is licensed under the terms of the GNU General Public | ||
| 6 | * License version 2, as published by the Free Software Foundation, and | ||
| 7 | * may be copied, distributed, and modified under those terms. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/dma-mapping.h> | ||
| 19 | #include <linux/spinlock.h> | ||
| 20 | #include <linux/completion.h> | ||
| 21 | #include <linux/sched.h> | ||
| 22 | #include <linux/mutex.h> | ||
| 23 | |||
| 24 | #include <mach/dma.h> | ||
| 25 | #include <mach/iomap.h> | ||
| 26 | |||
| 27 | #include "apbio.h" | ||
| 28 | |||
| 29 | static DEFINE_MUTEX(tegra_apb_dma_lock); | ||
| 30 | |||
| 31 | static struct tegra_dma_channel *tegra_apb_dma; | ||
| 32 | static u32 *tegra_apb_bb; | ||
| 33 | static dma_addr_t tegra_apb_bb_phys; | ||
| 34 | static DECLARE_COMPLETION(tegra_apb_wait); | ||
| 35 | |||
| 36 | bool tegra_apb_init(void) | ||
| 37 | { | ||
| 38 | struct tegra_dma_channel *ch; | ||
| 39 | |||
| 40 | mutex_lock(&tegra_apb_dma_lock); | ||
| 41 | |||
| 42 | /* Check to see if we raced to setup */ | ||
| 43 | if (tegra_apb_dma) | ||
| 44 | goto out; | ||
| 45 | |||
| 46 | ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT | | ||
| 47 | TEGRA_DMA_SHARED); | ||
| 48 | |||
| 49 | if (!ch) | ||
| 50 | goto out_fail; | ||
| 51 | |||
| 52 | tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32), | ||
| 53 | &tegra_apb_bb_phys, GFP_KERNEL); | ||
| 54 | if (!tegra_apb_bb) { | ||
| 55 | pr_err("%s: can not allocate bounce buffer\n", __func__); | ||
| 56 | tegra_dma_free_channel(ch); | ||
| 57 | goto out_fail; | ||
| 58 | } | ||
| 59 | |||
| 60 | tegra_apb_dma = ch; | ||
| 61 | out: | ||
| 62 | mutex_unlock(&tegra_apb_dma_lock); | ||
| 63 | return true; | ||
| 64 | |||
| 65 | out_fail: | ||
| 66 | mutex_unlock(&tegra_apb_dma_lock); | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | |||
| 70 | static void apb_dma_complete(struct tegra_dma_req *req) | ||
| 71 | { | ||
| 72 | complete(&tegra_apb_wait); | ||
| 73 | } | ||
| 74 | |||
| 75 | u32 tegra_apb_readl(unsigned long offset) | ||
| 76 | { | ||
| 77 | struct tegra_dma_req req; | ||
| 78 | int ret; | ||
| 79 | |||
| 80 | if (!tegra_apb_dma && !tegra_apb_init()) | ||
| 81 | return readl(IO_TO_VIRT(offset)); | ||
| 82 | |||
| 83 | mutex_lock(&tegra_apb_dma_lock); | ||
| 84 | req.complete = apb_dma_complete; | ||
| 85 | req.to_memory = 1; | ||
| 86 | req.dest_addr = tegra_apb_bb_phys; | ||
| 87 | req.dest_bus_width = 32; | ||
| 88 | req.dest_wrap = 1; | ||
| 89 | req.source_addr = offset; | ||
| 90 | req.source_bus_width = 32; | ||
| 91 | req.source_wrap = 4; | ||
| 92 | req.req_sel = TEGRA_DMA_REQ_SEL_CNTR; | ||
| 93 | req.size = 4; | ||
| 94 | |||
| 95 | INIT_COMPLETION(tegra_apb_wait); | ||
| 96 | |||
| 97 | tegra_dma_enqueue_req(tegra_apb_dma, &req); | ||
| 98 | |||
| 99 | ret = wait_for_completion_timeout(&tegra_apb_wait, | ||
| 100 | msecs_to_jiffies(50)); | ||
| 101 | |||
| 102 | if (WARN(ret == 0, "apb read dma timed out")) { | ||
| 103 | tegra_dma_dequeue_req(tegra_apb_dma, &req); | ||
| 104 | *(u32 *)tegra_apb_bb = 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | mutex_unlock(&tegra_apb_dma_lock); | ||
| 108 | return *((u32 *)tegra_apb_bb); | ||
| 109 | } | ||
| 110 | |||
| 111 | void tegra_apb_writel(u32 value, unsigned long offset) | ||
| 112 | { | ||
| 113 | struct tegra_dma_req req; | ||
| 114 | int ret; | ||
| 115 | |||
| 116 | if (!tegra_apb_dma && !tegra_apb_init()) { | ||
| 117 | writel(value, IO_TO_VIRT(offset)); | ||
| 118 | return; | ||
| 119 | } | ||
| 120 | |||
| 121 | mutex_lock(&tegra_apb_dma_lock); | ||
| 122 | *((u32 *)tegra_apb_bb) = value; | ||
| 123 | req.complete = apb_dma_complete; | ||
| 124 | req.to_memory = 0; | ||
| 125 | req.dest_addr = offset; | ||
| 126 | req.dest_wrap = 4; | ||
| 127 | req.dest_bus_width = 32; | ||
| 128 | req.source_addr = tegra_apb_bb_phys; | ||
| 129 | req.source_bus_width = 32; | ||
| 130 | req.source_wrap = 1; | ||
| 131 | req.req_sel = TEGRA_DMA_REQ_SEL_CNTR; | ||
| 132 | req.size = 4; | ||
| 133 | |||
| 134 | INIT_COMPLETION(tegra_apb_wait); | ||
| 135 | |||
| 136 | tegra_dma_enqueue_req(tegra_apb_dma, &req); | ||
| 137 | |||
| 138 | ret = wait_for_completion_timeout(&tegra_apb_wait, | ||
| 139 | msecs_to_jiffies(50)); | ||
| 140 | |||
| 141 | if (WARN(ret == 0, "apb write dma timed out")) | ||
| 142 | tegra_dma_dequeue_req(tegra_apb_dma, &req); | ||
| 143 | |||
| 144 | mutex_unlock(&tegra_apb_dma_lock); | ||
| 145 | } | ||
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h new file mode 100644 index 000000000000..8b49e8c89a64 --- /dev/null +++ b/arch/arm/mach-tegra/apbio.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 NVIDIA Corporation. | ||
| 3 | * Copyright (C) 2010 Google, Inc. | ||
| 4 | * | ||
| 5 | * This software is licensed under the terms of the GNU General Public | ||
| 6 | * License version 2, as published by the Free Software Foundation, and | ||
| 7 | * may be copied, distributed, and modified under those terms. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef __MACH_TEGRA_APBIO_H | ||
| 17 | #define __MACH_TEGRA_APBIO_H | ||
| 18 | |||
| 19 | #ifdef CONFIG_TEGRA_SYSTEM_DMA | ||
| 20 | |||
| 21 | u32 tegra_apb_readl(unsigned long offset); | ||
| 22 | void tegra_apb_writel(u32 value, unsigned long offset); | ||
| 23 | |||
| 24 | #else | ||
| 25 | #include <asm/io.h> | ||
| 26 | #include <mach/io.h> | ||
| 27 | |||
| 28 | static inline u32 tegra_apb_readl(unsigned long offset) | ||
| 29 | { | ||
| 30 | return readl(IO_TO_VIRT(offset)); | ||
| 31 | } | ||
| 32 | |||
| 33 | static inline void tegra_apb_writel(u32 value, unsigned long offset) | ||
| 34 | { | ||
| 35 | writel(value, IO_TO_VIRT(offset)); | ||
| 36 | } | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #endif | ||
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c index 21d1285731b3..976edfb05912 100644 --- a/arch/arm/mach-tegra/board-harmony-power.c +++ b/arch/arm/mach-tegra/board-harmony-power.c | |||
| @@ -18,18 +18,13 @@ | |||
| 18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/gpio.h> | 20 | #include <linux/gpio.h> |
| 21 | #include <linux/io.h> | ||
| 22 | #include <linux/regulator/machine.h> | 21 | #include <linux/regulator/machine.h> |
| 23 | #include <linux/mfd/tps6586x.h> | 22 | #include <linux/mfd/tps6586x.h> |
| 24 | 23 | ||
| 25 | #include <mach/iomap.h> | ||
| 26 | #include <mach/irqs.h> | 24 | #include <mach/irqs.h> |
| 27 | 25 | ||
| 28 | #include "board-harmony.h" | 26 | #include "board-harmony.h" |
| 29 | 27 | ||
| 30 | #define PMC_CTRL 0x0 | ||
| 31 | #define PMC_CTRL_INTR_LOW (1 << 17) | ||
| 32 | |||
| 33 | static struct regulator_consumer_supply tps658621_ldo0_supply[] = { | 28 | static struct regulator_consumer_supply tps658621_ldo0_supply[] = { |
| 34 | REGULATOR_SUPPLY("pex_clk", NULL), | 29 | REGULATOR_SUPPLY("pex_clk", NULL), |
| 35 | }; | 30 | }; |
| @@ -114,16 +109,6 @@ static struct i2c_board_info __initdata harmony_regulators[] = { | |||
| 114 | 109 | ||
| 115 | int __init harmony_regulator_init(void) | 110 | int __init harmony_regulator_init(void) |
| 116 | { | 111 | { |
| 117 | void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); | ||
| 118 | u32 pmc_ctrl; | ||
| 119 | |||
| 120 | /* | ||
| 121 | * Configure the power management controller to trigger PMU | ||
| 122 | * interrupts when low | ||
| 123 | */ | ||
| 124 | pmc_ctrl = readl(pmc + PMC_CTRL); | ||
| 125 | writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL); | ||
| 126 | |||
| 127 | i2c_register_board_info(3, harmony_regulators, 1); | 112 | i2c_register_board_info(3, harmony_regulators, 1); |
| 128 | 113 | ||
| 129 | return 0; | 114 | return 0; |
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c index 789bdc9e8f91..c00aadb01e09 100644 --- a/arch/arm/mach-tegra/board-harmony.c +++ b/arch/arm/mach-tegra/board-harmony.c | |||
| @@ -101,7 +101,6 @@ static struct wm8903_platform_data harmony_wm8903_pdata = { | |||
| 101 | static struct i2c_board_info __initdata wm8903_board_info = { | 101 | static struct i2c_board_info __initdata wm8903_board_info = { |
| 102 | I2C_BOARD_INFO("wm8903", 0x1a), | 102 | I2C_BOARD_INFO("wm8903", 0x1a), |
| 103 | .platform_data = &harmony_wm8903_pdata, | 103 | .platform_data = &harmony_wm8903_pdata, |
| 104 | .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ), | ||
| 105 | }; | 104 | }; |
| 106 | 105 | ||
| 107 | static void __init harmony_i2c_init(void) | 106 | static void __init harmony_i2c_init(void) |
| @@ -111,6 +110,7 @@ static void __init harmony_i2c_init(void) | |||
| 111 | platform_device_register(&tegra_i2c_device3); | 110 | platform_device_register(&tegra_i2c_device3); |
| 112 | platform_device_register(&tegra_i2c_device4); | 111 | platform_device_register(&tegra_i2c_device4); |
| 113 | 112 | ||
| 113 | wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ); | ||
| 114 | i2c_register_board_info(0, &wm8903_board_info, 1); | 114 | i2c_register_board_info(0, &wm8903_board_info, 1); |
| 115 | } | 115 | } |
| 116 | 116 | ||
diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c index ebac65f52510..d669847f0485 100644 --- a/arch/arm/mach-tegra/board-seaboard.c +++ b/arch/arm/mach-tegra/board-seaboard.c | |||
| @@ -159,7 +159,6 @@ static struct platform_device *seaboard_devices[] __initdata = { | |||
| 159 | 159 | ||
| 160 | static struct i2c_board_info __initdata isl29018_device = { | 160 | static struct i2c_board_info __initdata isl29018_device = { |
| 161 | I2C_BOARD_INFO("isl29018", 0x44), | 161 | I2C_BOARD_INFO("isl29018", 0x44), |
| 162 | .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ), | ||
| 163 | }; | 162 | }; |
| 164 | 163 | ||
| 165 | static struct i2c_board_info __initdata adt7461_device = { | 164 | static struct i2c_board_info __initdata adt7461_device = { |
| @@ -183,7 +182,6 @@ static struct wm8903_platform_data wm8903_pdata = { | |||
| 183 | static struct i2c_board_info __initdata wm8903_device = { | 182 | static struct i2c_board_info __initdata wm8903_device = { |
| 184 | I2C_BOARD_INFO("wm8903", 0x1a), | 183 | I2C_BOARD_INFO("wm8903", 0x1a), |
| 185 | .platform_data = &wm8903_pdata, | 184 | .platform_data = &wm8903_pdata, |
| 186 | .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ), | ||
| 187 | }; | 185 | }; |
| 188 | 186 | ||
| 189 | static int seaboard_ehci_init(void) | 187 | static int seaboard_ehci_init(void) |
| @@ -214,7 +212,10 @@ static void __init seaboard_i2c_init(void) | |||
| 214 | gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018"); | 212 | gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018"); |
| 215 | gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ); | 213 | gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ); |
| 216 | 214 | ||
| 215 | isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ); | ||
| 217 | i2c_register_board_info(0, &isl29018_device, 1); | 216 | i2c_register_board_info(0, &isl29018_device, 1); |
| 217 | |||
| 218 | wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ); | ||
| 218 | i2c_register_board_info(0, &wm8903_device, 1); | 219 | i2c_register_board_info(0, &wm8903_device, 1); |
| 219 | 220 | ||
| 220 | i2c_register_board_info(3, &adt7461_device, 1); | 221 | i2c_register_board_info(3, &adt7461_device, 1); |
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 2db20da1d585..47ad750209ae 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c | |||
| @@ -31,6 +31,24 @@ | |||
| 31 | #include "board.h" | 31 | #include "board.h" |
| 32 | #include "clock.h" | 32 | #include "clock.h" |
| 33 | #include "fuse.h" | 33 | #include "fuse.h" |
| 34 | #include "pmc.h" | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Storage for debug-macro.S's state. | ||
| 38 | * | ||
| 39 | * This must be in .data not .bss so that it gets initialized each time the | ||
| 40 | * kernel is loaded. The data is declared here rather than debug-macro.S so | ||
| 41 | * that multiple inclusions of debug-macro.S point at the same data. | ||
| 42 | */ | ||
| 43 | #define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF) | ||
| 44 | u32 tegra_uart_config[3] = { | ||
| 45 | /* Debug UART initialization required */ | ||
| 46 | 1, | ||
| 47 | /* Debug UART physical address */ | ||
| 48 | (u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET), | ||
| 49 | /* Debug UART virtual address */ | ||
| 50 | (u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET), | ||
| 51 | }; | ||
| 34 | 52 | ||
| 35 | #ifdef CONFIG_OF | 53 | #ifdef CONFIG_OF |
| 36 | static const struct of_device_id tegra_dt_irq_match[] __initconst = { | 54 | static const struct of_device_id tegra_dt_irq_match[] __initconst = { |
| @@ -101,11 +119,13 @@ void __init tegra20_init_early(void) | |||
| 101 | tegra2_init_clocks(); | 119 | tegra2_init_clocks(); |
| 102 | tegra_clk_init_from_table(tegra20_clk_init_table); | 120 | tegra_clk_init_from_table(tegra20_clk_init_table); |
| 103 | tegra_init_cache(0x331, 0x441); | 121 | tegra_init_cache(0x331, 0x441); |
| 122 | tegra_pmc_init(); | ||
| 104 | } | 123 | } |
| 105 | #endif | 124 | #endif |
| 106 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | 125 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC |
| 107 | void __init tegra30_init_early(void) | 126 | void __init tegra30_init_early(void) |
| 108 | { | 127 | { |
| 109 | tegra_init_cache(0x441, 0x551); | 128 | tegra_init_cache(0x441, 0x551); |
| 129 | tegra_pmc_init(); | ||
| 110 | } | 130 | } |
| 111 | #endif | 131 | #endif |
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index c0cf967e47d3..abea4f6e2dd5 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c | |||
| @@ -33,6 +33,8 @@ | |||
| 33 | #include <mach/iomap.h> | 33 | #include <mach/iomap.h> |
| 34 | #include <mach/suspend.h> | 34 | #include <mach/suspend.h> |
| 35 | 35 | ||
| 36 | #include "apbio.h" | ||
| 37 | |||
| 36 | #define APB_DMA_GEN 0x000 | 38 | #define APB_DMA_GEN 0x000 |
| 37 | #define GEN_ENABLE (1<<31) | 39 | #define GEN_ENABLE (1<<31) |
| 38 | 40 | ||
| @@ -50,8 +52,6 @@ | |||
| 50 | #define CSR_ONCE (1<<27) | 52 | #define CSR_ONCE (1<<27) |
| 51 | #define CSR_FLOW (1<<21) | 53 | #define CSR_FLOW (1<<21) |
| 52 | #define CSR_REQ_SEL_SHIFT 16 | 54 | #define CSR_REQ_SEL_SHIFT 16 |
| 53 | #define CSR_REQ_SEL_MASK (0x1F<<CSR_REQ_SEL_SHIFT) | ||
| 54 | #define CSR_REQ_SEL_INVALID (31<<CSR_REQ_SEL_SHIFT) | ||
| 55 | #define CSR_WCOUNT_SHIFT 2 | 55 | #define CSR_WCOUNT_SHIFT 2 |
| 56 | #define CSR_WCOUNT_MASK 0xFFFC | 56 | #define CSR_WCOUNT_MASK 0xFFFC |
| 57 | 57 | ||
| @@ -133,6 +133,7 @@ struct tegra_dma_channel { | |||
| 133 | 133 | ||
| 134 | static bool tegra_dma_initialized; | 134 | static bool tegra_dma_initialized; |
| 135 | static DEFINE_MUTEX(tegra_dma_lock); | 135 | static DEFINE_MUTEX(tegra_dma_lock); |
| 136 | static DEFINE_SPINLOCK(enable_lock); | ||
| 136 | 137 | ||
| 137 | static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS); | 138 | static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS); |
| 138 | static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS]; | 139 | static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS]; |
| @@ -180,36 +181,94 @@ static void tegra_dma_stop(struct tegra_dma_channel *ch) | |||
| 180 | 181 | ||
| 181 | static int tegra_dma_cancel(struct tegra_dma_channel *ch) | 182 | static int tegra_dma_cancel(struct tegra_dma_channel *ch) |
| 182 | { | 183 | { |
| 183 | u32 csr; | ||
| 184 | unsigned long irq_flags; | 184 | unsigned long irq_flags; |
| 185 | 185 | ||
| 186 | spin_lock_irqsave(&ch->lock, irq_flags); | 186 | spin_lock_irqsave(&ch->lock, irq_flags); |
| 187 | while (!list_empty(&ch->list)) | 187 | while (!list_empty(&ch->list)) |
| 188 | list_del(ch->list.next); | 188 | list_del(ch->list.next); |
| 189 | 189 | ||
| 190 | csr = readl(ch->addr + APB_DMA_CHAN_CSR); | ||
| 191 | csr &= ~CSR_REQ_SEL_MASK; | ||
| 192 | csr |= CSR_REQ_SEL_INVALID; | ||
| 193 | writel(csr, ch->addr + APB_DMA_CHAN_CSR); | ||
| 194 | |||
| 195 | tegra_dma_stop(ch); | 190 | tegra_dma_stop(ch); |
| 196 | 191 | ||
| 197 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 192 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
| 198 | return 0; | 193 | return 0; |
| 199 | } | 194 | } |
| 200 | 195 | ||
| 196 | static unsigned int get_channel_status(struct tegra_dma_channel *ch, | ||
| 197 | struct tegra_dma_req *req, bool is_stop_dma) | ||
| 198 | { | ||
| 199 | void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE); | ||
| 200 | unsigned int status; | ||
| 201 | |||
| 202 | if (is_stop_dma) { | ||
| 203 | /* | ||
| 204 | * STOP the DMA and get the transfer count. | ||
| 205 | * Getting the transfer count is tricky. | ||
| 206 | * - Globally disable DMA on all channels | ||
| 207 | * - Read the channel's status register to know the number | ||
| 208 | * of pending bytes to be transfered. | ||
| 209 | * - Stop the dma channel | ||
| 210 | * - Globally re-enable DMA to resume other transfers | ||
| 211 | */ | ||
| 212 | spin_lock(&enable_lock); | ||
| 213 | writel(0, addr + APB_DMA_GEN); | ||
| 214 | udelay(20); | ||
| 215 | status = readl(ch->addr + APB_DMA_CHAN_STA); | ||
| 216 | tegra_dma_stop(ch); | ||
| 217 | writel(GEN_ENABLE, addr + APB_DMA_GEN); | ||
| 218 | spin_unlock(&enable_lock); | ||
| 219 | if (status & STA_ISE_EOC) { | ||
| 220 | pr_err("Got Dma Int here clearing"); | ||
| 221 | writel(status, ch->addr + APB_DMA_CHAN_STA); | ||
| 222 | } | ||
| 223 | req->status = TEGRA_DMA_REQ_ERROR_ABORTED; | ||
| 224 | } else { | ||
| 225 | status = readl(ch->addr + APB_DMA_CHAN_STA); | ||
| 226 | } | ||
| 227 | return status; | ||
| 228 | } | ||
| 229 | |||
| 230 | /* should be called with the channel lock held */ | ||
| 231 | static unsigned int dma_active_count(struct tegra_dma_channel *ch, | ||
| 232 | struct tegra_dma_req *req, unsigned int status) | ||
| 233 | { | ||
| 234 | unsigned int to_transfer; | ||
| 235 | unsigned int req_transfer_count; | ||
| 236 | unsigned int bytes_transferred; | ||
| 237 | |||
| 238 | to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1; | ||
| 239 | req_transfer_count = ch->req_transfer_count + 1; | ||
| 240 | bytes_transferred = req_transfer_count; | ||
| 241 | if (status & STA_BUSY) | ||
| 242 | bytes_transferred -= to_transfer; | ||
| 243 | /* | ||
| 244 | * In continuous transfer mode, DMA only tracks the count of the | ||
| 245 | * half DMA buffer. So, if the DMA already finished half the DMA | ||
| 246 | * then add the half buffer to the completed count. | ||
| 247 | */ | ||
| 248 | if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) { | ||
| 249 | if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) | ||
| 250 | bytes_transferred += req_transfer_count; | ||
| 251 | if (status & STA_ISE_EOC) | ||
| 252 | bytes_transferred += req_transfer_count; | ||
| 253 | } | ||
| 254 | bytes_transferred *= 4; | ||
| 255 | return bytes_transferred; | ||
| 256 | } | ||
| 257 | |||
| 201 | int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, | 258 | int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, |
| 202 | struct tegra_dma_req *_req) | 259 | struct tegra_dma_req *_req) |
| 203 | { | 260 | { |
| 204 | unsigned int csr; | ||
| 205 | unsigned int status; | 261 | unsigned int status; |
| 206 | struct tegra_dma_req *req = NULL; | 262 | struct tegra_dma_req *req = NULL; |
| 207 | int found = 0; | 263 | int found = 0; |
| 208 | unsigned long irq_flags; | 264 | unsigned long irq_flags; |
| 209 | int to_transfer; | 265 | int stop = 0; |
| 210 | int req_transfer_count; | ||
| 211 | 266 | ||
| 212 | spin_lock_irqsave(&ch->lock, irq_flags); | 267 | spin_lock_irqsave(&ch->lock, irq_flags); |
| 268 | |||
| 269 | if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req) | ||
| 270 | stop = 1; | ||
| 271 | |||
| 213 | list_for_each_entry(req, &ch->list, node) { | 272 | list_for_each_entry(req, &ch->list, node) { |
| 214 | if (req == _req) { | 273 | if (req == _req) { |
| 215 | list_del(&req->node); | 274 | list_del(&req->node); |
| @@ -222,47 +281,12 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, | |||
| 222 | return 0; | 281 | return 0; |
| 223 | } | 282 | } |
| 224 | 283 | ||
| 225 | /* STOP the DMA and get the transfer count. | 284 | if (!stop) |
| 226 | * Getting the transfer count is tricky. | 285 | goto skip_stop_dma; |
| 227 | * - Change the source selector to invalid to stop the DMA from | ||
| 228 | * FIFO to memory. | ||
| 229 | * - Read the status register to know the number of pending | ||
| 230 | * bytes to be transferred. | ||
| 231 | * - Finally stop or program the DMA to the next buffer in the | ||
| 232 | * list. | ||
| 233 | */ | ||
| 234 | csr = readl(ch->addr + APB_DMA_CHAN_CSR); | ||
| 235 | csr &= ~CSR_REQ_SEL_MASK; | ||
| 236 | csr |= CSR_REQ_SEL_INVALID; | ||
| 237 | writel(csr, ch->addr + APB_DMA_CHAN_CSR); | ||
| 238 | |||
| 239 | /* Get the transfer count */ | ||
| 240 | status = readl(ch->addr + APB_DMA_CHAN_STA); | ||
| 241 | to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT; | ||
| 242 | req_transfer_count = ch->req_transfer_count; | ||
| 243 | req_transfer_count += 1; | ||
| 244 | to_transfer += 1; | ||
| 245 | |||
| 246 | req->bytes_transferred = req_transfer_count; | ||
| 247 | |||
| 248 | if (status & STA_BUSY) | ||
| 249 | req->bytes_transferred -= to_transfer; | ||
| 250 | |||
| 251 | /* In continuous transfer mode, DMA only tracks the count of the | ||
| 252 | * half DMA buffer. So, if the DMA already finished half the DMA | ||
| 253 | * then add the half buffer to the completed count. | ||
| 254 | * | ||
| 255 | * FIXME: There can be a race here. What if the req to | ||
| 256 | * dequue happens at the same time as the DMA just moved to | ||
| 257 | * the new buffer and SW didn't yet received the interrupt? | ||
| 258 | */ | ||
| 259 | if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) | ||
| 260 | if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) | ||
| 261 | req->bytes_transferred += req_transfer_count; | ||
| 262 | 286 | ||
| 263 | req->bytes_transferred *= 4; | 287 | status = get_channel_status(ch, req, true); |
| 288 | req->bytes_transferred = dma_active_count(ch, req, status); | ||
| 264 | 289 | ||
| 265 | tegra_dma_stop(ch); | ||
| 266 | if (!list_empty(&ch->list)) { | 290 | if (!list_empty(&ch->list)) { |
| 267 | /* if the list is not empty, queue the next request */ | 291 | /* if the list is not empty, queue the next request */ |
| 268 | struct tegra_dma_req *next_req; | 292 | struct tegra_dma_req *next_req; |
| @@ -270,6 +294,8 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, | |||
| 270 | typeof(*next_req), node); | 294 | typeof(*next_req), node); |
| 271 | tegra_dma_update_hw(ch, next_req); | 295 | tegra_dma_update_hw(ch, next_req); |
| 272 | } | 296 | } |
| 297 | |||
| 298 | skip_stop_dma: | ||
| 273 | req->status = -TEGRA_DMA_REQ_ERROR_ABORTED; | 299 | req->status = -TEGRA_DMA_REQ_ERROR_ABORTED; |
| 274 | 300 | ||
| 275 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 301 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
| @@ -357,7 +383,7 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode) | |||
| 357 | int channel; | 383 | int channel; |
| 358 | struct tegra_dma_channel *ch = NULL; | 384 | struct tegra_dma_channel *ch = NULL; |
| 359 | 385 | ||
| 360 | if (WARN_ON(!tegra_dma_initialized)) | 386 | if (!tegra_dma_initialized) |
| 361 | return NULL; | 387 | return NULL; |
| 362 | 388 | ||
| 363 | mutex_lock(&tegra_dma_lock); | 389 | mutex_lock(&tegra_dma_lock); |
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 1fa26d9a1a68..17fdd4086e6f 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c | |||
| @@ -23,20 +23,70 @@ | |||
| 23 | #include <mach/iomap.h> | 23 | #include <mach/iomap.h> |
| 24 | 24 | ||
| 25 | #include "fuse.h" | 25 | #include "fuse.h" |
| 26 | #include "apbio.h" | ||
| 26 | 27 | ||
| 27 | #define FUSE_UID_LOW 0x108 | 28 | #define FUSE_UID_LOW 0x108 |
| 28 | #define FUSE_UID_HIGH 0x10c | 29 | #define FUSE_UID_HIGH 0x10c |
| 29 | #define FUSE_SKU_INFO 0x110 | 30 | #define FUSE_SKU_INFO 0x110 |
| 30 | #define FUSE_SPARE_BIT 0x200 | 31 | #define FUSE_SPARE_BIT 0x200 |
| 31 | 32 | ||
| 32 | static inline u32 fuse_readl(unsigned long offset) | 33 | int tegra_sku_id; |
| 34 | int tegra_cpu_process_id; | ||
| 35 | int tegra_core_process_id; | ||
| 36 | enum tegra_revision tegra_revision; | ||
| 37 | |||
| 38 | /* The BCT to use at boot is specified by board straps that can be read | ||
| 39 | * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs. | ||
| 40 | */ | ||
| 41 | int tegra_bct_strapping; | ||
| 42 | |||
| 43 | #define STRAP_OPT 0x008 | ||
| 44 | #define GMI_AD0 (1 << 4) | ||
| 45 | #define GMI_AD1 (1 << 5) | ||
| 46 | #define RAM_ID_MASK (GMI_AD0 | GMI_AD1) | ||
| 47 | #define RAM_CODE_SHIFT 4 | ||
| 48 | |||
| 49 | static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { | ||
| 50 | [TEGRA_REVISION_UNKNOWN] = "unknown", | ||
| 51 | [TEGRA_REVISION_A01] = "A01", | ||
| 52 | [TEGRA_REVISION_A02] = "A02", | ||
| 53 | [TEGRA_REVISION_A03] = "A03", | ||
| 54 | [TEGRA_REVISION_A03p] = "A03 prime", | ||
| 55 | [TEGRA_REVISION_A04] = "A04", | ||
| 56 | }; | ||
| 57 | |||
| 58 | static inline u32 tegra_fuse_readl(unsigned long offset) | ||
| 59 | { | ||
| 60 | return tegra_apb_readl(TEGRA_FUSE_BASE + offset); | ||
| 61 | } | ||
| 62 | |||
| 63 | static inline bool get_spare_fuse(int bit) | ||
| 33 | { | 64 | { |
| 34 | return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); | 65 | return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4); |
| 35 | } | 66 | } |
| 36 | 67 | ||
| 37 | static inline void fuse_writel(u32 value, unsigned long offset) | 68 | static enum tegra_revision tegra_get_revision(void) |
| 38 | { | 69 | { |
| 39 | writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); | 70 | void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804; |
| 71 | u32 id = readl(chip_id); | ||
| 72 | u32 minor_rev = (id >> 16) & 0xf; | ||
| 73 | u32 chipid = (id >> 8) & 0xff; | ||
| 74 | |||
| 75 | switch (minor_rev) { | ||
| 76 | case 1: | ||
| 77 | return TEGRA_REVISION_A01; | ||
| 78 | case 2: | ||
| 79 | return TEGRA_REVISION_A02; | ||
| 80 | case 3: | ||
| 81 | if (chipid == 0x20 && (get_spare_fuse(18) || get_spare_fuse(19))) | ||
| 82 | return TEGRA_REVISION_A03p; | ||
| 83 | else | ||
| 84 | return TEGRA_REVISION_A03; | ||
| 85 | case 4: | ||
| 86 | return TEGRA_REVISION_A04; | ||
| 87 | default: | ||
| 88 | return TEGRA_REVISION_UNKNOWN; | ||
| 89 | } | ||
| 40 | } | 90 | } |
| 41 | 91 | ||
| 42 | void tegra_init_fuse(void) | 92 | void tegra_init_fuse(void) |
| @@ -45,40 +95,31 @@ void tegra_init_fuse(void) | |||
| 45 | reg |= 1 << 28; | 95 | reg |= 1 << 28; |
| 46 | writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); | 96 | writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); |
| 47 | 97 | ||
| 48 | pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n", | 98 | reg = tegra_fuse_readl(FUSE_SKU_INFO); |
| 49 | tegra_sku_id(), tegra_cpu_process_id(), | 99 | tegra_sku_id = reg & 0xFF; |
| 50 | tegra_core_process_id()); | ||
| 51 | } | ||
| 52 | 100 | ||
| 53 | unsigned long long tegra_chip_uid(void) | 101 | reg = tegra_fuse_readl(FUSE_SPARE_BIT); |
| 54 | { | 102 | tegra_cpu_process_id = (reg >> 6) & 3; |
| 55 | unsigned long long lo, hi; | ||
| 56 | 103 | ||
| 57 | lo = fuse_readl(FUSE_UID_LOW); | 104 | reg = tegra_fuse_readl(FUSE_SPARE_BIT); |
| 58 | hi = fuse_readl(FUSE_UID_HIGH); | 105 | tegra_core_process_id = (reg >> 12) & 3; |
| 59 | return (hi << 32ull) | lo; | ||
| 60 | } | ||
| 61 | 106 | ||
| 62 | int tegra_sku_id(void) | 107 | reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); |
| 63 | { | 108 | tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; |
| 64 | int sku_id; | ||
| 65 | u32 reg = fuse_readl(FUSE_SKU_INFO); | ||
| 66 | sku_id = reg & 0xFF; | ||
| 67 | return sku_id; | ||
| 68 | } | ||
| 69 | 109 | ||
| 70 | int tegra_cpu_process_id(void) | 110 | tegra_revision = tegra_get_revision(); |
| 71 | { | 111 | |
| 72 | int cpu_process_id; | 112 | pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", |
| 73 | u32 reg = fuse_readl(FUSE_SPARE_BIT); | 113 | tegra_revision_name[tegra_get_revision()], |
| 74 | cpu_process_id = (reg >> 6) & 3; | 114 | tegra_sku_id, tegra_cpu_process_id, |
| 75 | return cpu_process_id; | 115 | tegra_core_process_id); |
| 76 | } | 116 | } |
| 77 | 117 | ||
| 78 | int tegra_core_process_id(void) | 118 | unsigned long long tegra_chip_uid(void) |
| 79 | { | 119 | { |
| 80 | int core_process_id; | 120 | unsigned long long lo, hi; |
| 81 | u32 reg = fuse_readl(FUSE_SPARE_BIT); | 121 | |
| 82 | core_process_id = (reg >> 12) & 3; | 122 | lo = tegra_fuse_readl(FUSE_UID_LOW); |
| 83 | return core_process_id; | 123 | hi = tegra_fuse_readl(FUSE_UID_HIGH); |
| 124 | return (hi << 32ull) | lo; | ||
| 84 | } | 125 | } |
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index 584b2e27dbda..d65d2abf803b 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * arch/arm/mach-tegra/fuse.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Google, Inc. | 2 | * Copyright (C) 2010 Google, Inc. |
| 5 | * | 3 | * |
| 6 | * Author: | 4 | * Author: |
| @@ -17,8 +15,34 @@ | |||
| 17 | * | 15 | * |
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 18 | #ifndef __MACH_TEGRA_FUSE_H | ||
| 19 | #define __MACH_TEGRA_FUSE_H | ||
| 20 | |||
| 21 | enum tegra_revision { | ||
| 22 | TEGRA_REVISION_UNKNOWN = 0, | ||
| 23 | TEGRA_REVISION_A01, | ||
| 24 | TEGRA_REVISION_A02, | ||
| 25 | TEGRA_REVISION_A03, | ||
| 26 | TEGRA_REVISION_A03p, | ||
| 27 | TEGRA_REVISION_A04, | ||
| 28 | TEGRA_REVISION_MAX, | ||
| 29 | }; | ||
| 30 | |||
| 31 | #define SKU_ID_T20 8 | ||
| 32 | #define SKU_ID_T25SE 20 | ||
| 33 | #define SKU_ID_AP25 23 | ||
| 34 | #define SKU_ID_T25 24 | ||
| 35 | #define SKU_ID_AP25E 27 | ||
| 36 | #define SKU_ID_T25E 28 | ||
| 37 | |||
| 38 | extern int tegra_sku_id; | ||
| 39 | extern int tegra_cpu_process_id; | ||
| 40 | extern int tegra_core_process_id; | ||
| 41 | extern enum tegra_revision tegra_revision; | ||
| 42 | |||
| 43 | extern int tegra_bct_strapping; | ||
| 44 | |||
| 20 | unsigned long long tegra_chip_uid(void); | 45 | unsigned long long tegra_chip_uid(void); |
| 21 | int tegra_sku_id(void); | ||
| 22 | int tegra_cpu_process_id(void); | ||
| 23 | int tegra_core_process_id(void); | ||
| 24 | void tegra_init_fuse(void); | 46 | void tegra_init_fuse(void); |
| 47 | |||
| 48 | #endif | ||
diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S index 619abc63aee8..90069abd37bd 100644 --- a/arch/arm/mach-tegra/include/mach/debug-macro.S +++ b/arch/arm/mach-tegra/include/mach/debug-macro.S | |||
| @@ -1,11 +1,17 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * arch/arm/mach-tegra/include/mach/debug-macro.S | 2 | * arch/arm/mach-tegra/include/mach/debug-macro.S |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010 Google, Inc. | 4 | * Copyright (C) 2010,2011 Google, Inc. |
| 5 | * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved. | ||
| 5 | * | 6 | * |
| 6 | * Author: | 7 | * Author: |
| 7 | * Colin Cross <ccross@google.com> | 8 | * Colin Cross <ccross@google.com> |
| 8 | * Erik Gilling <konkers@google.com> | 9 | * Erik Gilling <konkers@google.com> |
| 10 | * Doug Anderson <dianders@chromium.org> | ||
| 11 | * Stephen Warren <swarren@nvidia.com> | ||
| 12 | * | ||
| 13 | * Portions based on mach-omap2's debug-macro.S | ||
| 14 | * Copyright (C) 1994-1999 Russell King | ||
| 9 | * | 15 | * |
| 10 | * This software is licensed under the terms of the GNU General Public | 16 | * This software is licensed under the terms of the GNU General Public |
| 11 | * License version 2, as published by the Free Software Foundation, and | 17 | * License version 2, as published by the Free Software Foundation, and |
| @@ -18,18 +24,78 @@ | |||
| 18 | * | 24 | * |
| 19 | */ | 25 | */ |
| 20 | 26 | ||
| 27 | #include <linux/serial_reg.h> | ||
| 28 | |||
| 21 | #include <mach/io.h> | 29 | #include <mach/io.h> |
| 22 | #include <mach/iomap.h> | 30 | #include <mach/iomap.h> |
| 31 | #include <mach/irammap.h> | ||
| 32 | |||
| 33 | .macro addruart, rp, rv, tmp | ||
| 34 | adr \rp, 99f @ actual addr of 99f | ||
| 35 | ldr \rv, [\rp] @ linked addr is stored there | ||
| 36 | sub \rv, \rv, \rp @ offset between the two | ||
| 37 | ldr \rp, [\rp, #4] @ linked tegra_uart_config | ||
| 38 | sub \tmp, \rp, \rv @ actual tegra_uart_config | ||
| 39 | ldr \rp, [\tmp] @ Load tegra_uart_config | ||
| 40 | cmp \rp, #1 @ needs intitialization? | ||
| 41 | bne 100f @ no; go load the addresses | ||
| 42 | mov \rv, #0 @ yes; record init is done | ||
| 43 | str \rv, [\tmp] | ||
| 44 | mov \rp, #TEGRA_IRAM_BASE @ See if cookie is in IRAM | ||
| 45 | ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET] | ||
| 46 | movw \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff | ||
| 47 | movt \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16 | ||
| 48 | cmp \rv, \rp @ Cookie present? | ||
| 49 | bne 100f @ No, use default UART | ||
| 50 | mov \rp, #TEGRA_IRAM_BASE @ Load UART address from IRAM | ||
| 51 | ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4] | ||
| 52 | str \rv, [\tmp, #4] @ Store in tegra_uart_phys | ||
| 53 | sub \rv, \rv, #IO_APB_PHYS @ Calculate virt address | ||
| 54 | add \rv, \rv, #IO_APB_VIRT | ||
| 55 | str \rv, [\tmp, #8] @ Store in tegra_uart_virt | ||
| 56 | b 100f | ||
| 57 | |||
| 58 | .align | ||
| 59 | 99: .word . | ||
| 60 | .word tegra_uart_config | ||
| 61 | .ltorg | ||
| 62 | |||
| 63 | 100: ldr \rp, [\tmp, #4] @ Load tegra_uart_phys | ||
| 64 | ldr \rv, [\tmp, #8] @ Load tegra_uart_virt | ||
| 65 | .endm | ||
| 66 | |||
| 67 | #define UART_SHIFT 2 | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Code below is swiped from <asm/hardware/debug-8250.S>, but add an extra | ||
| 71 | * check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case. | ||
| 72 | * We use the fact that all 5 valid UART addresses all have something in the | ||
| 73 | * 2nd-to-lowest byte. | ||
| 74 | */ | ||
| 23 | 75 | ||
| 24 | .macro addruart, rp, rv, tmp | 76 | .macro senduart, rd, rx |
| 25 | ldr \rp, =IO_APB_PHYS @ physical | 77 | tst \rx, #0x0000ff00 |
| 26 | ldr \rv, =IO_APB_VIRT @ virtual | 78 | strneb \rd, [\rx, #UART_TX << UART_SHIFT] |
| 27 | orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF) | 79 | 1001: |
| 28 | orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00) | 80 | .endm |
| 29 | orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF) | ||
| 30 | orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00) | ||
| 31 | .endm | ||
| 32 | 81 | ||
| 33 | #define UART_SHIFT 2 | 82 | .macro busyuart, rd, rx |
| 34 | #include <asm/hardware/debug-8250.S> | 83 | tst \rx, #0x0000ff00 |
| 84 | beq 1002f | ||
| 85 | 1001: ldrb \rd, [\rx, #UART_LSR << UART_SHIFT] | ||
| 86 | and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE | ||
| 87 | teq \rd, #UART_LSR_TEMT | UART_LSR_THRE | ||
| 88 | bne 1001b | ||
| 89 | 1002: | ||
| 90 | .endm | ||
| 35 | 91 | ||
| 92 | .macro waituart, rd, rx | ||
| 93 | #ifdef FLOW_CONTROL | ||
| 94 | tst \rx, #0x0000ff00 | ||
| 95 | beq 1002f | ||
| 96 | 1001: ldrb \rd, [\rx, #UART_MSR << UART_SHIFT] | ||
| 97 | tst \rd, #UART_MSR_CTS | ||
| 98 | beq 1001b | ||
| 99 | 1002: | ||
| 100 | #endif | ||
| 101 | .endm | ||
diff --git a/arch/arm/mach-tegra/include/mach/gpio-tegra.h b/arch/arm/mach-tegra/include/mach/gpio-tegra.h index 87d37fdf5084..6140820555e1 100644 --- a/arch/arm/mach-tegra/include/mach/gpio-tegra.h +++ b/arch/arm/mach-tegra/include/mach/gpio-tegra.h | |||
| @@ -25,8 +25,6 @@ | |||
| 25 | 25 | ||
| 26 | #define TEGRA_NR_GPIOS INT_GPIO_NR | 26 | #define TEGRA_NR_GPIOS INT_GPIO_NR |
| 27 | 27 | ||
| 28 | #define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio)) | ||
| 29 | |||
| 30 | struct tegra_gpio_table { | 28 | struct tegra_gpio_table { |
| 31 | int gpio; /* GPIO number */ | 29 | int gpio; /* GPIO number */ |
| 32 | bool enable; /* Enable for GPIO at init? */ | 30 | bool enable; /* Enable for GPIO at init? */ |
diff --git a/arch/arm/mach-tegra/include/mach/irammap.h b/arch/arm/mach-tegra/include/mach/irammap.h new file mode 100644 index 000000000000..0cbe63261854 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/irammap.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __MACH_TEGRA_IRAMMAP_H | ||
| 18 | #define __MACH_TEGRA_IRAMMAP_H | ||
| 19 | |||
| 20 | #include <asm/sizes.h> | ||
| 21 | |||
| 22 | /* The first 1K of IRAM is permanently reserved for the CPU reset handler */ | ||
| 23 | #define TEGRA_IRAM_RESET_HANDLER_OFFSET 0 | ||
| 24 | #define TEGRA_IRAM_RESET_HANDLER_SIZE SZ_1K | ||
| 25 | |||
| 26 | /* | ||
| 27 | * These locations are written to by uncompress.h, and read by debug-macro.S. | ||
| 28 | * The first word holds the cookie value if the data is valid. The second | ||
| 29 | * word holds the UART physical address. | ||
| 30 | */ | ||
| 31 | #define TEGRA_IRAM_DEBUG_UART_OFFSET SZ_1K | ||
| 32 | #define TEGRA_IRAM_DEBUG_UART_SIZE 8 | ||
| 33 | #define TEGRA_IRAM_DEBUG_UART_COOKIE 0x55415254 | ||
| 34 | |||
| 35 | #endif | ||
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 4e8323770c79..5a440f315e57 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h | |||
| @@ -2,10 +2,14 @@ | |||
| 2 | * arch/arm/mach-tegra/include/mach/uncompress.h | 2 | * arch/arm/mach-tegra/include/mach/uncompress.h |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010 Google, Inc. | 4 | * Copyright (C) 2010 Google, Inc. |
| 5 | * Copyright (C) 2011 Google, Inc. | ||
| 6 | * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved. | ||
| 5 | * | 7 | * |
| 6 | * Author: | 8 | * Author: |
| 7 | * Colin Cross <ccross@google.com> | 9 | * Colin Cross <ccross@google.com> |
| 8 | * Erik Gilling <konkers@google.com> | 10 | * Erik Gilling <konkers@google.com> |
| 11 | * Doug Anderson <dianders@chromium.org> | ||
| 12 | * Stephen Warren <swarren@nvidia.com> | ||
| 9 | * | 13 | * |
| 10 | * This software is licensed under the terms of the GNU General Public | 14 | * This software is licensed under the terms of the GNU General Public |
| 11 | * License version 2, as published by the Free Software Foundation, and | 15 | * License version 2, as published by the Free Software Foundation, and |
| @@ -25,36 +29,130 @@ | |||
| 25 | #include <linux/serial_reg.h> | 29 | #include <linux/serial_reg.h> |
| 26 | 30 | ||
| 27 | #include <mach/iomap.h> | 31 | #include <mach/iomap.h> |
| 32 | #include <mach/irammap.h> | ||
| 33 | |||
| 34 | #define BIT(x) (1 << (x)) | ||
| 35 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
| 36 | |||
| 37 | #define DEBUG_UART_SHIFT 2 | ||
| 38 | |||
| 39 | volatile u8 *uart; | ||
| 28 | 40 | ||
| 29 | static void putc(int c) | 41 | static void putc(int c) |
| 30 | { | 42 | { |
| 31 | volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; | ||
| 32 | int shift = 2; | ||
| 33 | |||
| 34 | if (uart == NULL) | 43 | if (uart == NULL) |
| 35 | return; | 44 | return; |
| 36 | 45 | ||
| 37 | while (!(uart[UART_LSR << shift] & UART_LSR_THRE)) | 46 | while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE)) |
| 38 | barrier(); | 47 | barrier(); |
| 39 | uart[UART_TX << shift] = c; | 48 | uart[UART_TX << DEBUG_UART_SHIFT] = c; |
| 40 | } | 49 | } |
| 41 | 50 | ||
| 42 | static inline void flush(void) | 51 | static inline void flush(void) |
| 43 | { | 52 | { |
| 44 | } | 53 | } |
| 45 | 54 | ||
| 55 | static inline void save_uart_address(void) | ||
| 56 | { | ||
| 57 | u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET); | ||
| 58 | |||
| 59 | if (uart) { | ||
| 60 | buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE; | ||
| 61 | buf[1] = (u32)uart; | ||
| 62 | } else | ||
| 63 | buf[0] = 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Setup before decompression. This is where we do UART selection for | ||
| 68 | * earlyprintk and init the uart_base register. | ||
| 69 | */ | ||
| 46 | static inline void arch_decomp_setup(void) | 70 | static inline void arch_decomp_setup(void) |
| 47 | { | 71 | { |
| 48 | volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; | 72 | static const struct { |
| 49 | int shift = 2; | 73 | u32 base; |
| 74 | u32 reset_reg; | ||
| 75 | u32 clock_reg; | ||
| 76 | u32 bit; | ||
| 77 | } uarts[] = { | ||
| 78 | { | ||
| 79 | TEGRA_UARTA_BASE, | ||
| 80 | TEGRA_CLK_RESET_BASE + 0x04, | ||
| 81 | TEGRA_CLK_RESET_BASE + 0x10, | ||
| 82 | 6, | ||
| 83 | }, | ||
| 84 | { | ||
| 85 | TEGRA_UARTB_BASE, | ||
| 86 | TEGRA_CLK_RESET_BASE + 0x04, | ||
| 87 | TEGRA_CLK_RESET_BASE + 0x10, | ||
| 88 | 7, | ||
| 89 | }, | ||
| 90 | { | ||
| 91 | TEGRA_UARTC_BASE, | ||
| 92 | TEGRA_CLK_RESET_BASE + 0x08, | ||
| 93 | TEGRA_CLK_RESET_BASE + 0x14, | ||
| 94 | 23, | ||
| 95 | }, | ||
| 96 | { | ||
| 97 | TEGRA_UARTD_BASE, | ||
| 98 | TEGRA_CLK_RESET_BASE + 0x0c, | ||
| 99 | TEGRA_CLK_RESET_BASE + 0x18, | ||
| 100 | 1, | ||
| 101 | }, | ||
| 102 | { | ||
| 103 | TEGRA_UARTE_BASE, | ||
| 104 | TEGRA_CLK_RESET_BASE + 0x0c, | ||
| 105 | TEGRA_CLK_RESET_BASE + 0x18, | ||
| 106 | 2, | ||
| 107 | }, | ||
| 108 | }; | ||
| 109 | int i; | ||
| 110 | volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; | ||
| 111 | u32 chip, div; | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Look for the first UART that: | ||
| 115 | * a) Is not in reset. | ||
| 116 | * b) Is clocked. | ||
| 117 | * c) Has a 'D' in the scratchpad register. | ||
| 118 | * | ||
| 119 | * Note that on Tegra30, the first two conditions are required, since | ||
| 120 | * if not true, accesses to the UART scratch register will hang. | ||
| 121 | * Tegra20 doesn't have this issue. | ||
| 122 | * | ||
| 123 | * The intent is that the bootloader will tell the kernel which UART | ||
| 124 | * to use by setting up those conditions. If nothing found, we'll fall | ||
| 125 | * back to what's specified in TEGRA_DEBUG_UART_BASE. | ||
| 126 | */ | ||
| 127 | for (i = 0; i < ARRAY_SIZE(uarts); i++) { | ||
| 128 | if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit)) | ||
| 129 | continue; | ||
| 50 | 130 | ||
| 131 | if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit))) | ||
| 132 | continue; | ||
| 133 | |||
| 134 | uart = (volatile u8 *)uarts[i].base; | ||
| 135 | if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D') | ||
| 136 | continue; | ||
| 137 | |||
| 138 | break; | ||
| 139 | } | ||
| 140 | if (i == ARRAY_SIZE(uarts)) | ||
| 141 | uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; | ||
| 142 | save_uart_address(); | ||
| 51 | if (uart == NULL) | 143 | if (uart == NULL) |
| 52 | return; | 144 | return; |
| 53 | 145 | ||
| 54 | uart[UART_LCR << shift] |= UART_LCR_DLAB; | 146 | chip = (apb_misc[0x804 / 4] >> 8) & 0xff; |
| 55 | uart[UART_DLL << shift] = 0x75; | 147 | if (chip == 0x20) |
| 56 | uart[UART_DLM << shift] = 0x0; | 148 | div = 0x0075; |
| 57 | uart[UART_LCR << shift] = 3; | 149 | else |
| 150 | div = 0x00dd; | ||
| 151 | |||
| 152 | uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB; | ||
| 153 | uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff; | ||
| 154 | uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8; | ||
| 155 | uart[UART_LCR << DEBUG_UART_SHIFT] = 3; | ||
| 58 | } | 156 | } |
| 59 | 157 | ||
| 60 | static inline void arch_decomp_wdog(void) | 158 | static inline void arch_decomp_wdog(void) |
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c new file mode 100644 index 000000000000..7af6a54404be --- /dev/null +++ b/arch/arm/mach-tegra/pmc.c | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/io.h> | ||
| 20 | #include <linux/of.h> | ||
| 21 | |||
| 22 | #include <mach/iomap.h> | ||
| 23 | |||
| 24 | #define PMC_CTRL 0x0 | ||
| 25 | #define PMC_CTRL_INTR_LOW (1 << 17) | ||
| 26 | |||
| 27 | static inline u32 tegra_pmc_readl(u32 reg) | ||
| 28 | { | ||
| 29 | return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg)); | ||
| 30 | } | ||
| 31 | |||
| 32 | static inline void tegra_pmc_writel(u32 val, u32 reg) | ||
| 33 | { | ||
| 34 | writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg)); | ||
| 35 | } | ||
| 36 | |||
| 37 | #ifdef CONFIG_OF | ||
| 38 | static const struct of_device_id matches[] __initconst = { | ||
| 39 | { .compatible = "nvidia,tegra20-pmc" }, | ||
| 40 | { } | ||
| 41 | }; | ||
| 42 | #endif | ||
| 43 | |||
| 44 | void __init tegra_pmc_init(void) | ||
| 45 | { | ||
| 46 | /* | ||
| 47 | * For now, Harmony is the only board that uses the PMC, and it wants | ||
| 48 | * the signal inverted. Seaboard would too if it used the PMC. | ||
| 49 | * Hopefully by the time other boards want to use the PMC, everything | ||
| 50 | * will be device-tree, or they also want it inverted. | ||
| 51 | */ | ||
| 52 | bool invert_interrupt = true; | ||
| 53 | u32 val; | ||
| 54 | |||
| 55 | #ifdef CONFIG_OF | ||
| 56 | if (of_have_populated_dt()) { | ||
| 57 | struct device_node *np; | ||
| 58 | |||
| 59 | invert_interrupt = false; | ||
| 60 | |||
| 61 | np = of_find_matching_node(NULL, matches); | ||
| 62 | if (np) { | ||
| 63 | if (of_find_property(np, "nvidia,invert-interrupt", | ||
| 64 | NULL)) | ||
| 65 | invert_interrupt = true; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | #endif | ||
| 69 | |||
| 70 | val = tegra_pmc_readl(PMC_CTRL); | ||
| 71 | if (invert_interrupt) | ||
| 72 | val |= PMC_CTRL_INTR_LOW; | ||
| 73 | else | ||
| 74 | val &= ~PMC_CTRL_INTR_LOW; | ||
| 75 | tegra_pmc_writel(val, PMC_CTRL); | ||
| 76 | } | ||
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h new file mode 100644 index 000000000000..8995ee4a8768 --- /dev/null +++ b/arch/arm/mach-tegra/pmc.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef __MACH_TEGRA_PMC_H | ||
| 19 | #define __MACH_TEGRA_PMC_H | ||
| 20 | |||
| 21 | void tegra_pmc_init(void); | ||
| 22 | |||
| 23 | #endif | ||
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index ff9e6b6c0460..74d314fdf2f9 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c | |||
| @@ -720,7 +720,7 @@ static void tegra2_pllx_clk_init(struct clk *c) | |||
| 720 | { | 720 | { |
| 721 | tegra2_pll_clk_init(c); | 721 | tegra2_pll_clk_init(c); |
| 722 | 722 | ||
| 723 | if (tegra_sku_id() == 7) | 723 | if (tegra_sku_id == 7) |
| 724 | c->max_rate = 750000000; | 724 | c->max_rate = 750000000; |
| 725 | } | 725 | } |
| 726 | 726 | ||
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index 0f7ae6e90b55..5070d833bdd1 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c | |||
| @@ -16,14 +16,19 @@ | |||
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/device.h> | ||
| 19 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
| 20 | #include <linux/err.h> | 21 | #include <linux/err.h> |
| 21 | #include <linux/io.h> | 22 | #include <linux/io.h> |
| 22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| 24 | #include <linux/of.h> | ||
| 25 | #include <linux/platform_device.h> | ||
| 26 | #include <linux/platform_data/tegra_emc.h> | ||
| 23 | 27 | ||
| 24 | #include <mach/iomap.h> | 28 | #include <mach/iomap.h> |
| 25 | 29 | ||
| 26 | #include "tegra2_emc.h" | 30 | #include "tegra2_emc.h" |
| 31 | #include "fuse.h" | ||
| 27 | 32 | ||
| 28 | #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE | 33 | #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE |
| 29 | static bool emc_enable = true; | 34 | static bool emc_enable = true; |
| @@ -32,18 +37,17 @@ static bool emc_enable; | |||
| 32 | #endif | 37 | #endif |
| 33 | module_param(emc_enable, bool, 0644); | 38 | module_param(emc_enable, bool, 0644); |
| 34 | 39 | ||
| 35 | static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE); | 40 | static struct platform_device *emc_pdev; |
| 36 | static const struct tegra_emc_table *tegra_emc_table; | 41 | static void __iomem *emc_regbase; |
| 37 | static int tegra_emc_table_size; | ||
| 38 | 42 | ||
| 39 | static inline void emc_writel(u32 val, unsigned long addr) | 43 | static inline void emc_writel(u32 val, unsigned long addr) |
| 40 | { | 44 | { |
| 41 | writel(val, emc + addr); | 45 | writel(val, emc_regbase + addr); |
| 42 | } | 46 | } |
| 43 | 47 | ||
| 44 | static inline u32 emc_readl(unsigned long addr) | 48 | static inline u32 emc_readl(unsigned long addr) |
| 45 | { | 49 | { |
| 46 | return readl(emc + addr); | 50 | return readl(emc_regbase + addr); |
| 47 | } | 51 | } |
| 48 | 52 | ||
| 49 | static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { | 53 | static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { |
| @@ -98,15 +102,15 @@ static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { | |||
| 98 | /* Select the closest EMC rate that is higher than the requested rate */ | 102 | /* Select the closest EMC rate that is higher than the requested rate */ |
| 99 | long tegra_emc_round_rate(unsigned long rate) | 103 | long tegra_emc_round_rate(unsigned long rate) |
| 100 | { | 104 | { |
| 105 | struct tegra_emc_pdata *pdata; | ||
| 101 | int i; | 106 | int i; |
| 102 | int best = -1; | 107 | int best = -1; |
| 103 | unsigned long distance = ULONG_MAX; | 108 | unsigned long distance = ULONG_MAX; |
| 104 | 109 | ||
| 105 | if (!tegra_emc_table) | 110 | if (!emc_pdev) |
| 106 | return -EINVAL; | 111 | return -EINVAL; |
| 107 | 112 | ||
| 108 | if (!emc_enable) | 113 | pdata = emc_pdev->dev.platform_data; |
| 109 | return -EINVAL; | ||
| 110 | 114 | ||
| 111 | pr_debug("%s: %lu\n", __func__, rate); | 115 | pr_debug("%s: %lu\n", __func__, rate); |
| 112 | 116 | ||
| @@ -116,10 +120,10 @@ long tegra_emc_round_rate(unsigned long rate) | |||
| 116 | */ | 120 | */ |
| 117 | rate = rate / 2 / 1000; | 121 | rate = rate / 2 / 1000; |
| 118 | 122 | ||
| 119 | for (i = 0; i < tegra_emc_table_size; i++) { | 123 | for (i = 0; i < pdata->num_tables; i++) { |
| 120 | if (tegra_emc_table[i].rate >= rate && | 124 | if (pdata->tables[i].rate >= rate && |
| 121 | (tegra_emc_table[i].rate - rate) < distance) { | 125 | (pdata->tables[i].rate - rate) < distance) { |
| 122 | distance = tegra_emc_table[i].rate - rate; | 126 | distance = pdata->tables[i].rate - rate; |
| 123 | best = i; | 127 | best = i; |
| 124 | } | 128 | } |
| 125 | } | 129 | } |
| @@ -127,9 +131,9 @@ long tegra_emc_round_rate(unsigned long rate) | |||
| 127 | if (best < 0) | 131 | if (best < 0) |
| 128 | return -EINVAL; | 132 | return -EINVAL; |
| 129 | 133 | ||
| 130 | pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate); | 134 | pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate); |
| 131 | 135 | ||
| 132 | return tegra_emc_table[best].rate * 2 * 1000; | 136 | return pdata->tables[best].rate * 2 * 1000; |
| 133 | } | 137 | } |
| 134 | 138 | ||
| 135 | /* | 139 | /* |
| @@ -142,37 +146,211 @@ long tegra_emc_round_rate(unsigned long rate) | |||
| 142 | */ | 146 | */ |
| 143 | int tegra_emc_set_rate(unsigned long rate) | 147 | int tegra_emc_set_rate(unsigned long rate) |
| 144 | { | 148 | { |
| 149 | struct tegra_emc_pdata *pdata; | ||
| 145 | int i; | 150 | int i; |
| 146 | int j; | 151 | int j; |
| 147 | 152 | ||
| 148 | if (!tegra_emc_table) | 153 | if (!emc_pdev) |
| 149 | return -EINVAL; | 154 | return -EINVAL; |
| 150 | 155 | ||
| 156 | pdata = emc_pdev->dev.platform_data; | ||
| 157 | |||
| 151 | /* | 158 | /* |
| 152 | * The EMC clock rate is twice the bus rate, and the bus rate is | 159 | * The EMC clock rate is twice the bus rate, and the bus rate is |
| 153 | * measured in kHz | 160 | * measured in kHz |
| 154 | */ | 161 | */ |
| 155 | rate = rate / 2 / 1000; | 162 | rate = rate / 2 / 1000; |
| 156 | 163 | ||
| 157 | for (i = 0; i < tegra_emc_table_size; i++) | 164 | for (i = 0; i < pdata->num_tables; i++) |
| 158 | if (tegra_emc_table[i].rate == rate) | 165 | if (pdata->tables[i].rate == rate) |
| 159 | break; | 166 | break; |
| 160 | 167 | ||
| 161 | if (i >= tegra_emc_table_size) | 168 | if (i >= pdata->num_tables) |
| 162 | return -EINVAL; | 169 | return -EINVAL; |
| 163 | 170 | ||
| 164 | pr_debug("%s: setting to %lu\n", __func__, rate); | 171 | pr_debug("%s: setting to %lu\n", __func__, rate); |
| 165 | 172 | ||
| 166 | for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) | 173 | for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) |
| 167 | emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]); | 174 | emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]); |
| 168 | 175 | ||
| 169 | emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]); | 176 | emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]); |
| 170 | 177 | ||
| 171 | return 0; | 178 | return 0; |
| 172 | } | 179 | } |
| 173 | 180 | ||
| 174 | void tegra_init_emc(const struct tegra_emc_table *table, int table_size) | 181 | #ifdef CONFIG_OF |
| 182 | static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np) | ||
| 183 | { | ||
| 184 | struct device_node *iter; | ||
| 185 | u32 reg; | ||
| 186 | |||
| 187 | for_each_child_of_node(np, iter) { | ||
| 188 | if (of_property_read_u32(np, "nvidia,ram-code", ®)) | ||
| 189 | continue; | ||
| 190 | if (reg == tegra_bct_strapping) | ||
| 191 | return of_node_get(iter); | ||
| 192 | } | ||
| 193 | |||
| 194 | return NULL; | ||
| 195 | } | ||
| 196 | |||
| 197 | static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( | ||
| 198 | struct platform_device *pdev) | ||
| 199 | { | ||
| 200 | struct device_node *np = pdev->dev.of_node; | ||
| 201 | struct device_node *tnp, *iter; | ||
| 202 | struct tegra_emc_pdata *pdata; | ||
| 203 | int ret, i, num_tables; | ||
| 204 | |||
| 205 | if (!np) | ||
| 206 | return NULL; | ||
| 207 | |||
| 208 | if (of_find_property(np, "nvidia,use-ram-code", NULL)) { | ||
| 209 | tnp = tegra_emc_ramcode_devnode(np); | ||
| 210 | if (!tnp) | ||
| 211 | dev_warn(&pdev->dev, | ||
| 212 | "can't find emc table for ram-code 0x%02x\n", | ||
| 213 | tegra_bct_strapping); | ||
| 214 | } else | ||
| 215 | tnp = of_node_get(np); | ||
| 216 | |||
| 217 | if (!tnp) | ||
| 218 | return NULL; | ||
| 219 | |||
| 220 | num_tables = 0; | ||
| 221 | for_each_child_of_node(tnp, iter) | ||
| 222 | if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table")) | ||
| 223 | num_tables++; | ||
| 224 | |||
| 225 | if (!num_tables) { | ||
| 226 | pdata = NULL; | ||
| 227 | goto out; | ||
| 228 | } | ||
| 229 | |||
| 230 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
| 231 | pdata->tables = devm_kzalloc(&pdev->dev, | ||
| 232 | sizeof(*pdata->tables) * num_tables, | ||
| 233 | GFP_KERNEL); | ||
| 234 | |||
| 235 | i = 0; | ||
| 236 | for_each_child_of_node(tnp, iter) { | ||
| 237 | u32 prop; | ||
| 238 | |||
| 239 | ret = of_property_read_u32(iter, "clock-frequency", &prop); | ||
| 240 | if (ret) { | ||
| 241 | dev_err(&pdev->dev, "no clock-frequency in %s\n", | ||
| 242 | iter->full_name); | ||
| 243 | continue; | ||
| 244 | } | ||
| 245 | pdata->tables[i].rate = prop; | ||
| 246 | |||
| 247 | ret = of_property_read_u32_array(iter, "nvidia,emc-registers", | ||
| 248 | pdata->tables[i].regs, | ||
| 249 | TEGRA_EMC_NUM_REGS); | ||
| 250 | if (ret) { | ||
| 251 | dev_err(&pdev->dev, | ||
| 252 | "malformed emc-registers property in %s\n", | ||
| 253 | iter->full_name); | ||
| 254 | continue; | ||
| 255 | } | ||
| 256 | |||
| 257 | i++; | ||
| 258 | } | ||
| 259 | pdata->num_tables = i; | ||
| 260 | |||
| 261 | out: | ||
| 262 | of_node_put(tnp); | ||
| 263 | return pdata; | ||
| 264 | } | ||
| 265 | #else | ||
| 266 | static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( | ||
| 267 | struct platform_device *pdev) | ||
| 268 | { | ||
| 269 | return NULL; | ||
| 270 | } | ||
| 271 | #endif | ||
| 272 | |||
| 273 | static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev) | ||
| 274 | { | ||
| 275 | struct clk *c = clk_get_sys(NULL, "emc"); | ||
| 276 | struct tegra_emc_pdata *pdata; | ||
| 277 | unsigned long khz; | ||
| 278 | int i; | ||
| 279 | |||
| 280 | WARN_ON(pdev->dev.platform_data); | ||
| 281 | BUG_ON(IS_ERR_OR_NULL(c)); | ||
| 282 | |||
| 283 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
| 284 | pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables), | ||
| 285 | GFP_KERNEL); | ||
| 286 | |||
| 287 | pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000; | ||
| 288 | |||
| 289 | for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) | ||
| 290 | pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]); | ||
| 291 | |||
| 292 | pdata->num_tables = 1; | ||
| 293 | |||
| 294 | khz = pdata->tables[0].rate; | ||
| 295 | dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, " | ||
| 296 | "%ld kHz mem\n", khz * 2, khz); | ||
| 297 | |||
| 298 | return pdata; | ||
| 299 | } | ||
| 300 | |||
| 301 | static int __devinit tegra_emc_probe(struct platform_device *pdev) | ||
| 302 | { | ||
| 303 | struct tegra_emc_pdata *pdata; | ||
| 304 | struct resource *res; | ||
| 305 | |||
| 306 | if (!emc_enable) { | ||
| 307 | dev_err(&pdev->dev, "disabled per module parameter\n"); | ||
| 308 | return -ENODEV; | ||
| 309 | } | ||
| 310 | |||
| 311 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 312 | if (!res) { | ||
| 313 | dev_err(&pdev->dev, "missing register base\n"); | ||
| 314 | return -ENOMEM; | ||
| 315 | } | ||
| 316 | |||
| 317 | emc_regbase = devm_request_and_ioremap(&pdev->dev, res); | ||
| 318 | if (!emc_regbase) { | ||
| 319 | dev_err(&pdev->dev, "failed to remap registers\n"); | ||
| 320 | return -ENOMEM; | ||
| 321 | } | ||
| 322 | |||
| 323 | pdata = pdev->dev.platform_data; | ||
| 324 | |||
| 325 | if (!pdata) | ||
| 326 | pdata = tegra_emc_dt_parse_pdata(pdev); | ||
| 327 | |||
| 328 | if (!pdata) | ||
| 329 | pdata = tegra_emc_fill_pdata(pdev); | ||
| 330 | |||
| 331 | pdev->dev.platform_data = pdata; | ||
| 332 | |||
| 333 | emc_pdev = pdev; | ||
| 334 | |||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | static struct of_device_id tegra_emc_of_match[] __devinitdata = { | ||
| 339 | { .compatible = "nvidia,tegra20-emc", }, | ||
| 340 | { }, | ||
| 341 | }; | ||
| 342 | |||
| 343 | static struct platform_driver tegra_emc_driver = { | ||
| 344 | .driver = { | ||
| 345 | .name = "tegra-emc", | ||
| 346 | .owner = THIS_MODULE, | ||
| 347 | .of_match_table = tegra_emc_of_match, | ||
| 348 | }, | ||
| 349 | .probe = tegra_emc_probe, | ||
| 350 | }; | ||
| 351 | |||
| 352 | static int __init tegra_emc_init(void) | ||
| 175 | { | 353 | { |
| 176 | tegra_emc_table = table; | 354 | return platform_driver_register(&tegra_emc_driver); |
| 177 | tegra_emc_table_size = table_size; | ||
| 178 | } | 355 | } |
| 356 | device_initcall(tegra_emc_init); | ||
diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h index 19f08cb31603..f61409b54cb7 100644 --- a/arch/arm/mach-tegra/tegra2_emc.h +++ b/arch/arm/mach-tegra/tegra2_emc.h | |||
| @@ -15,13 +15,10 @@ | |||
| 15 | * | 15 | * |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #define TEGRA_EMC_NUM_REGS 46 | 18 | #ifndef __MACH_TEGRA_TEGRA2_EMC_H_ |
| 19 | 19 | #define __MACH_TEGRA_TEGRA2_EMC_H | |
| 20 | struct tegra_emc_table { | ||
| 21 | unsigned long rate; | ||
| 22 | u32 regs[TEGRA_EMC_NUM_REGS]; | ||
| 23 | }; | ||
| 24 | 20 | ||
| 25 | int tegra_emc_set_rate(unsigned long rate); | 21 | int tegra_emc_set_rate(unsigned long rate); |
| 26 | long tegra_emc_round_rate(unsigned long rate); | 22 | long tegra_emc_round_rate(unsigned long rate); |
| 27 | void tegra_init_emc(const struct tegra_emc_table *table, int table_size); | 23 | |
| 24 | #endif | ||
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bdc293791590..6f17671260e1 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/of.h> | 25 | #include <linux/of.h> |
| 26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
| 27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
| 28 | #include <linux/irqdomain.h> | ||
| 28 | 29 | ||
| 29 | #include <asm/mach/irq.h> | 30 | #include <asm/mach/irq.h> |
| 30 | 31 | ||
| @@ -74,9 +75,10 @@ struct tegra_gpio_bank { | |||
| 74 | #endif | 75 | #endif |
| 75 | }; | 76 | }; |
| 76 | 77 | ||
| 77 | 78 | static struct irq_domain *irq_domain; | |
| 78 | static void __iomem *regs; | 79 | static void __iomem *regs; |
| 79 | static struct tegra_gpio_bank tegra_gpio_banks[7]; | 80 | static u32 tegra_gpio_bank_count; |
| 81 | static struct tegra_gpio_bank *tegra_gpio_banks; | ||
| 80 | 82 | ||
| 81 | static inline void tegra_gpio_writel(u32 val, u32 reg) | 83 | static inline void tegra_gpio_writel(u32 val, u32 reg) |
| 82 | { | 84 | { |
| @@ -139,7 +141,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | |||
| 139 | 141 | ||
| 140 | static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | 142 | static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) |
| 141 | { | 143 | { |
| 142 | return TEGRA_GPIO_TO_IRQ(offset); | 144 | return irq_find_mapping(irq_domain, offset); |
| 143 | } | 145 | } |
| 144 | 146 | ||
| 145 | static struct gpio_chip tegra_gpio_chip = { | 147 | static struct gpio_chip tegra_gpio_chip = { |
| @@ -155,28 +157,28 @@ static struct gpio_chip tegra_gpio_chip = { | |||
| 155 | 157 | ||
| 156 | static void tegra_gpio_irq_ack(struct irq_data *d) | 158 | static void tegra_gpio_irq_ack(struct irq_data *d) |
| 157 | { | 159 | { |
| 158 | int gpio = d->irq - INT_GPIO_BASE; | 160 | int gpio = d->hwirq; |
| 159 | 161 | ||
| 160 | tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); | 162 | tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); |
| 161 | } | 163 | } |
| 162 | 164 | ||
| 163 | static void tegra_gpio_irq_mask(struct irq_data *d) | 165 | static void tegra_gpio_irq_mask(struct irq_data *d) |
| 164 | { | 166 | { |
| 165 | int gpio = d->irq - INT_GPIO_BASE; | 167 | int gpio = d->hwirq; |
| 166 | 168 | ||
| 167 | tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); | 169 | tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); |
| 168 | } | 170 | } |
| 169 | 171 | ||
| 170 | static void tegra_gpio_irq_unmask(struct irq_data *d) | 172 | static void tegra_gpio_irq_unmask(struct irq_data *d) |
| 171 | { | 173 | { |
| 172 | int gpio = d->irq - INT_GPIO_BASE; | 174 | int gpio = d->hwirq; |
| 173 | 175 | ||
| 174 | tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); | 176 | tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); |
| 175 | } | 177 | } |
| 176 | 178 | ||
| 177 | static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) | 179 | static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) |
| 178 | { | 180 | { |
| 179 | int gpio = d->irq - INT_GPIO_BASE; | 181 | int gpio = d->hwirq; |
| 180 | struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); | 182 | struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); |
| 181 | int port = GPIO_PORT(gpio); | 183 | int port = GPIO_PORT(gpio); |
| 182 | int lvl_type; | 184 | int lvl_type; |
| @@ -273,7 +275,7 @@ void tegra_gpio_resume(void) | |||
| 273 | 275 | ||
| 274 | local_irq_save(flags); | 276 | local_irq_save(flags); |
| 275 | 277 | ||
| 276 | for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { | 278 | for (b = 0; b < tegra_gpio_bank_count; b++) { |
| 277 | struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; | 279 | struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; |
| 278 | 280 | ||
| 279 | for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { | 281 | for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { |
| @@ -296,7 +298,7 @@ void tegra_gpio_suspend(void) | |||
| 296 | int p; | 298 | int p; |
| 297 | 299 | ||
| 298 | local_irq_save(flags); | 300 | local_irq_save(flags); |
| 299 | for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { | 301 | for (b = 0; b < tegra_gpio_bank_count; b++) { |
| 300 | struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; | 302 | struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; |
| 301 | 303 | ||
| 302 | for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { | 304 | for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { |
| @@ -337,13 +339,44 @@ static struct lock_class_key gpio_lock_class; | |||
| 337 | 339 | ||
| 338 | static int __devinit tegra_gpio_probe(struct platform_device *pdev) | 340 | static int __devinit tegra_gpio_probe(struct platform_device *pdev) |
| 339 | { | 341 | { |
| 342 | int irq_base; | ||
| 340 | struct resource *res; | 343 | struct resource *res; |
| 341 | struct tegra_gpio_bank *bank; | 344 | struct tegra_gpio_bank *bank; |
| 342 | int gpio; | 345 | int gpio; |
| 343 | int i; | 346 | int i; |
| 344 | int j; | 347 | int j; |
| 345 | 348 | ||
| 346 | for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { | 349 | for (;;) { |
| 350 | res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); | ||
| 351 | if (!res) | ||
| 352 | break; | ||
| 353 | tegra_gpio_bank_count++; | ||
| 354 | } | ||
| 355 | if (!tegra_gpio_bank_count) { | ||
| 356 | dev_err(&pdev->dev, "Missing IRQ resource\n"); | ||
| 357 | return -ENODEV; | ||
| 358 | } | ||
| 359 | |||
| 360 | tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32; | ||
| 361 | |||
| 362 | tegra_gpio_banks = devm_kzalloc(&pdev->dev, | ||
| 363 | tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), | ||
| 364 | GFP_KERNEL); | ||
| 365 | if (!tegra_gpio_banks) { | ||
| 366 | dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); | ||
| 367 | return -ENODEV; | ||
| 368 | } | ||
| 369 | |||
| 370 | irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0); | ||
| 371 | if (irq_base < 0) { | ||
| 372 | dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); | ||
| 373 | return -ENODEV; | ||
| 374 | } | ||
| 375 | irq_domain = irq_domain_add_legacy(pdev->dev.of_node, | ||
| 376 | tegra_gpio_chip.ngpio, irq_base, 0, | ||
| 377 | &irq_domain_simple_ops, NULL); | ||
| 378 | |||
| 379 | for (i = 0; i < tegra_gpio_bank_count; i++) { | ||
| 347 | res = platform_get_resource(pdev, IORESOURCE_IRQ, i); | 380 | res = platform_get_resource(pdev, IORESOURCE_IRQ, i); |
| 348 | if (!res) { | 381 | if (!res) { |
| 349 | dev_err(&pdev->dev, "Missing IRQ resource\n"); | 382 | dev_err(&pdev->dev, "Missing IRQ resource\n"); |
| @@ -380,8 +413,8 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) | |||
| 380 | 413 | ||
| 381 | gpiochip_add(&tegra_gpio_chip); | 414 | gpiochip_add(&tegra_gpio_chip); |
| 382 | 415 | ||
| 383 | for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { | 416 | for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { |
| 384 | int irq = TEGRA_GPIO_TO_IRQ(gpio); | 417 | int irq = irq_find_mapping(irq_domain, gpio); |
| 385 | /* No validity check; all Tegra GPIOs are valid IRQs */ | 418 | /* No validity check; all Tegra GPIOs are valid IRQs */ |
| 386 | 419 | ||
| 387 | bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; | 420 | bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; |
| @@ -393,7 +426,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) | |||
| 393 | set_irq_flags(irq, IRQF_VALID); | 426 | set_irq_flags(irq, IRQF_VALID); |
| 394 | } | 427 | } |
| 395 | 428 | ||
| 396 | for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { | 429 | for (i = 0; i < tegra_gpio_bank_count; i++) { |
| 397 | bank = &tegra_gpio_banks[i]; | 430 | bank = &tegra_gpio_banks[i]; |
| 398 | 431 | ||
| 399 | irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); | 432 | irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); |
diff --git a/include/linux/platform_data/tegra_emc.h b/include/linux/platform_data/tegra_emc.h new file mode 100644 index 000000000000..df67505e98f8 --- /dev/null +++ b/include/linux/platform_data/tegra_emc.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 Google, Inc. | ||
| 3 | * | ||
| 4 | * Author: | ||
| 5 | * Colin Cross <ccross@android.com> | ||
| 6 | * Olof Johansson <olof@lixom.net> | ||
| 7 | * | ||
| 8 | * This software is licensed under the terms of the GNU General Public | ||
| 9 | * License version 2, as published by the Free Software Foundation, and | ||
| 10 | * may be copied, distributed, and modified under those terms. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __TEGRA_EMC_H_ | ||
| 20 | #define __TEGRA_EMC_H_ | ||
| 21 | |||
| 22 | #define TEGRA_EMC_NUM_REGS 46 | ||
| 23 | |||
| 24 | struct tegra_emc_table { | ||
| 25 | unsigned long rate; | ||
| 26 | u32 regs[TEGRA_EMC_NUM_REGS]; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct tegra_emc_pdata { | ||
| 30 | int num_tables; | ||
| 31 | struct tegra_emc_table *tables; | ||
| 32 | }; | ||
| 33 | |||
| 34 | #endif | ||
