mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
commit
7cb7f82611
|
@ -0,0 +1,100 @@
|
|||
Embedded Memory Controller
|
||||
|
||||
Properties:
|
||||
- name : Should be emc
|
||||
- #address-cells : Should be 1
|
||||
- #size-cells : Should be 0
|
||||
- compatible : Should contain "nvidia,tegra20-emc".
|
||||
- reg : Offset and length of the register set for the device
|
||||
- nvidia,use-ram-code : If present, the sub-nodes will be addressed
|
||||
and chosen using the ramcode board selector. If omitted, only one
|
||||
set of tables can be present and said tables will be used
|
||||
irrespective of ram-code configuration.
|
||||
|
||||
Child device nodes describe the memory settings for different configurations and clock rates.
|
||||
|
||||
Example:
|
||||
|
||||
emc@7000f400 {
|
||||
#address-cells = < 1 >;
|
||||
#size-cells = < 0 >;
|
||||
compatible = "nvidia,tegra20-emc";
|
||||
reg = <0x7000f4000 0x200>;
|
||||
}
|
||||
|
||||
|
||||
Embedded Memory Controller ram-code table
|
||||
|
||||
If the emc node has the nvidia,use-ram-code property present, then the
|
||||
next level of nodes below the emc table are used to specify which settings
|
||||
apply for which ram-code settings.
|
||||
|
||||
If the emc node lacks the nvidia,use-ram-code property, this level is omitted
|
||||
and the tables are stored directly under the emc node (see below).
|
||||
|
||||
Properties:
|
||||
|
||||
- name : Should be emc-tables
|
||||
- nvidia,ram-code : the binary representation of the ram-code board strappings
|
||||
for which this node (and children) are valid.
|
||||
|
||||
|
||||
|
||||
Embedded Memory Controller configuration table
|
||||
|
||||
This is a table containing the EMC register settings for the various
|
||||
operating speeds of the memory controller. They are always located as
|
||||
subnodes of the emc controller node.
|
||||
|
||||
There are two ways of specifying which tables to use:
|
||||
|
||||
* The simplest is if there is just one set of tables in the device tree,
|
||||
and they will always be used (based on which frequency is used).
|
||||
This is the preferred method, especially when firmware can fill in
|
||||
this information based on the specific system information and just
|
||||
pass it on to the kernel.
|
||||
|
||||
* The slightly more complex one is when more than one memory configuration
|
||||
might exist on the system. The Tegra20 platform handles this during
|
||||
early boot by selecting one out of possible 4 memory settings based
|
||||
on a 2-pin "ram code" bootstrap setting on the board. The values of
|
||||
these strappings can be read through a register in the SoC, and thus
|
||||
used to select which tables to use.
|
||||
|
||||
Properties:
|
||||
- name : Should be emc-table
|
||||
- compatible : Should contain "nvidia,tegra20-emc-table".
|
||||
- reg : either an opaque enumerator to tell different tables apart, or
|
||||
the valid frequency for which the table should be used (in kHz).
|
||||
- clock-frequency : the clock frequency for the EMC at which this
|
||||
table should be used (in kHz).
|
||||
- nvidia,emc-registers : a 46 word array of EMC registers to be programmed
|
||||
for operation at the 'clock-frequency' setting.
|
||||
The order and contents of the registers are:
|
||||
RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT,
|
||||
WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR,
|
||||
PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW,
|
||||
TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE,
|
||||
ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE,
|
||||
ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0,
|
||||
CFG_CLKTRIM_1, CFG_CLKTRIM_2
|
||||
|
||||
emc-table@166000 {
|
||||
reg = <166000>;
|
||||
compatible = "nvidia,tegra20-emc-table";
|
||||
clock-frequency = < 166000 >;
|
||||
nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 >;
|
||||
};
|
||||
|
||||
emc-table@333000 {
|
||||
reg = <333000>;
|
||||
compatible = "nvidia,tegra20-emc-table";
|
||||
clock-frequency = < 333000 >;
|
||||
nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 >;
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
NVIDIA Tegra Power Management Controller (PMC)
|
||||
|
||||
Properties:
|
||||
- name : Should be pmc
|
||||
- compatible : Should contain "nvidia,tegra<chip>-pmc".
|
||||
- reg : Offset and length of the register set for the device
|
||||
- nvidia,invert-interrupt : If present, inverts the PMU interrupt signal.
|
||||
The PMU is an external Power Management Unit, whose interrupt output
|
||||
signal is fed into the PMC. This signal is optionally inverted, and then
|
||||
fed into the ARM GIC. The PMC is not involved in the detection or
|
||||
handling of this interrupt signal, merely its inversion.
|
||||
|
||||
Example:
|
||||
|
||||
pmc@7000f400 {
|
||||
compatible = "nvidia,tegra20-pmc";
|
||||
reg = <0x7000e400 0x400>;
|
||||
nvidia,invert-interrupt;
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
* NVIDIA Tegra APB DMA controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "nvidia,<chip>-apbdma"
|
||||
- reg: Should contain DMA registers location and length. This shuld include
|
||||
all of the per-channel registers.
|
||||
- interrupts: Should contain all of the per-channel DMA interrupts.
|
||||
|
||||
Examples:
|
||||
|
||||
apbdma: dma@6000a000 {
|
||||
compatible = "nvidia,tegra20-apbdma";
|
||||
reg = <0x6000a000 0x1200>;
|
||||
interrupts = < 0 136 0x04
|
||||
0 137 0x04
|
||||
0 138 0x04
|
||||
0 139 0x04
|
||||
0 140 0x04
|
||||
0 141 0x04
|
||||
0 142 0x04
|
||||
0 143 0x04
|
||||
0 144 0x04
|
||||
0 145 0x04
|
||||
0 146 0x04
|
||||
0 147 0x04
|
||||
0 148 0x04
|
||||
0 149 0x04
|
||||
0 150 0x04
|
||||
0 151 0x04 >;
|
||||
};
|
|
@ -1,8 +1,40 @@
|
|||
NVIDIA Tegra 2 GPIO controller
|
||||
NVIDIA Tegra GPIO controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "nvidia,tegra20-gpio"
|
||||
- compatible : "nvidia,tegra<chip>-gpio"
|
||||
- reg : Physical base address and length of the controller's registers.
|
||||
- interrupts : The interrupt outputs from the controller. For Tegra20,
|
||||
there should be 7 interrupts specified, and for Tegra30, there should
|
||||
be 8 interrupts specified.
|
||||
- #gpio-cells : Should be two. The first cell is the pin number and the
|
||||
second cell is used to specify optional parameters:
|
||||
- bit 0 specifies polarity (0 for normal, 1 for inverted)
|
||||
- gpio-controller : Marks the device node as a GPIO controller.
|
||||
- #interrupt-cells : Should be 2.
|
||||
The first cell is the GPIO number.
|
||||
The second cell is used to specify flags:
|
||||
bits[3:0] trigger type and level flags:
|
||||
1 = low-to-high edge triggered.
|
||||
2 = high-to-low edge triggered.
|
||||
4 = active high level-sensitive.
|
||||
8 = active low level-sensitive.
|
||||
Valid combinations are 1, 2, 3, 4, 8.
|
||||
- interrupt-controller : Marks the device node as an interrupt controller.
|
||||
|
||||
Example:
|
||||
|
||||
gpio: gpio@6000d000 {
|
||||
compatible = "nvidia,tegra20-gpio";
|
||||
reg = < 0x6000d000 0x1000 >;
|
||||
interrupts = < 0 32 0x04
|
||||
0 33 0x04
|
||||
0 34 0x04
|
||||
0 35 0x04
|
||||
0 55 0x04
|
||||
0 87 0x04
|
||||
0 89 0x04 >;
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
};
|
||||
|
|
|
@ -10,19 +10,25 @@ memory@0 {
|
|||
reg = < 0x00000000 0x40000000 >;
|
||||
};
|
||||
|
||||
pmc@7000f400 {
|
||||
nvidia,invert-interrupt;
|
||||
};
|
||||
|
||||
i2c@7000c000 {
|
||||
clock-frequency = <400000>;
|
||||
|
||||
codec: wm8903@1a {
|
||||
wm8903: wm8903@1a {
|
||||
compatible = "wlf,wm8903";
|
||||
reg = <0x1a>;
|
||||
interrupts = < 347 >;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = < 187 0x04 >;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
/* 0x8000 = Not configured */
|
||||
gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
|
||||
micdet-cfg = <0>;
|
||||
micdet-delay = <100>;
|
||||
gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -38,13 +44,32 @@ i2c@7000d000 {
|
|||
clock-frequency = <400000>;
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903";
|
||||
i2s@70002a00 {
|
||||
status = "disable";
|
||||
};
|
||||
|
||||
spkr-en-gpios = <&codec 2 0>;
|
||||
hp-det-gpios = <&gpio 178 0>;
|
||||
int-mic-en-gpios = <&gpio 184 0>;
|
||||
ext-mic-en-gpios = <&gpio 185 0>;
|
||||
sound {
|
||||
compatible = "nvidia,tegra-audio-wm8903-harmony",
|
||||
"nvidia,tegra-audio-wm8903";
|
||||
nvidia,model = "NVIDIA Tegra Harmony";
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Headphone Jack", "HPOUTR",
|
||||
"Headphone Jack", "HPOUTL",
|
||||
"Int Spk", "ROP",
|
||||
"Int Spk", "RON",
|
||||
"Int Spk", "LOP",
|
||||
"Int Spk", "LON",
|
||||
"Mic Jack", "MICBIAS",
|
||||
"IN1L", "Mic Jack";
|
||||
|
||||
nvidia,i2s-controller = <&tegra_i2s1>;
|
||||
nvidia,audio-codec = <&wm8903>;
|
||||
|
||||
nvidia,spkr-en-gpios = <&wm8903 2 0>;
|
||||
nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
|
||||
nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
|
||||
nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
|
||||
};
|
||||
|
||||
serial@70006000 {
|
||||
|
|
|
@ -12,6 +12,13 @@ memory@0 {
|
|||
|
||||
i2c@7000c000 {
|
||||
clock-frequency = <400000>;
|
||||
|
||||
alc5632: alc5632@1e {
|
||||
compatible = "realtek,alc5632";
|
||||
reg = <0x1e>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@7000c400 {
|
||||
|
@ -37,6 +44,29 @@ i2c@7000d000 {
|
|||
clock-frequency = <400000>;
|
||||
};
|
||||
|
||||
i2s@70002a00 {
|
||||
status = "disable";
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "nvidia,tegra-audio-alc5632-paz00",
|
||||
"nvidia,tegra-audio-alc5632";
|
||||
|
||||
nvidia,model = "Compal PAZ00";
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Int Spk", "SPKOUT",
|
||||
"Int Spk", "SPKOUTN",
|
||||
"Headset Mic", "MICBIAS1",
|
||||
"MIC1", "Headset Mic",
|
||||
"Headset Stereophone", "HPR",
|
||||
"Headset Stereophone", "HPL";
|
||||
|
||||
nvidia,audio-codec = <&alc5632>;
|
||||
nvidia,i2s-controller = <&tegra_i2s1>;
|
||||
nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
|
||||
};
|
||||
|
||||
serial@70006000 {
|
||||
clock-frequency = <216000000>;
|
||||
};
|
||||
|
|
|
@ -13,6 +13,20 @@ memory {
|
|||
|
||||
i2c@7000c000 {
|
||||
clock-frequency = <400000>;
|
||||
|
||||
wm8903: wm8903@1a {
|
||||
compatible = "wlf,wm8903";
|
||||
reg = <0x1a>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = < 187 0x04 >;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
micdet-cfg = <0>;
|
||||
micdet-delay = <100>;
|
||||
gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@7000c400 {
|
||||
|
@ -32,6 +46,32 @@ adt7461@4c {
|
|||
};
|
||||
};
|
||||
|
||||
i2s@70002a00 {
|
||||
status = "disable";
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "nvidia,tegra-audio-wm8903-seaboard",
|
||||
"nvidia,tegra-audio-wm8903";
|
||||
nvidia,model = "NVIDIA Tegra Seaboard";
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Headphone Jack", "HPOUTR",
|
||||
"Headphone Jack", "HPOUTL",
|
||||
"Int Spk", "ROP",
|
||||
"Int Spk", "RON",
|
||||
"Int Spk", "LOP",
|
||||
"Int Spk", "LON",
|
||||
"Mic Jack", "MICBIAS",
|
||||
"IN1R", "Mic Jack";
|
||||
|
||||
nvidia,i2s-controller = <&tegra_i2s1>;
|
||||
nvidia,audio-codec = <&wm8903>;
|
||||
|
||||
nvidia,spkr-en-gpios = <&wm8903 2 0>;
|
||||
nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */
|
||||
};
|
||||
|
||||
serial@70006000 {
|
||||
status = "disable";
|
||||
};
|
||||
|
@ -93,4 +133,42 @@ lid {
|
|||
gpio-key,wakeup;
|
||||
};
|
||||
};
|
||||
|
||||
emc@7000f400 {
|
||||
emc-table@190000 {
|
||||
reg = < 190000 >;
|
||||
compatible = "nvidia,tegra20-emc-table";
|
||||
clock-frequency = < 190000 >;
|
||||
nvidia,emc-registers = < 0x0000000c 0x00000026
|
||||
0x00000009 0x00000003 0x00000004 0x00000004
|
||||
0x00000002 0x0000000c 0x00000003 0x00000003
|
||||
0x00000002 0x00000001 0x00000004 0x00000005
|
||||
0x00000004 0x00000009 0x0000000d 0x0000059f
|
||||
0x00000000 0x00000003 0x00000003 0x00000003
|
||||
0x00000003 0x00000001 0x0000000b 0x000000c8
|
||||
0x00000003 0x00000007 0x00000004 0x0000000f
|
||||
0x00000002 0x00000000 0x00000000 0x00000002
|
||||
0x00000000 0x00000000 0x00000083 0xa06204ae
|
||||
0x007dc010 0x00000000 0x00000000 0x00000000
|
||||
0x00000000 0x00000000 0x00000000 0x00000000 >;
|
||||
};
|
||||
|
||||
emc-table@380000 {
|
||||
reg = < 380000 >;
|
||||
compatible = "nvidia,tegra20-emc-table";
|
||||
clock-frequency = < 380000 >;
|
||||
nvidia,emc-registers = < 0x00000017 0x0000004b
|
||||
0x00000012 0x00000006 0x00000004 0x00000005
|
||||
0x00000003 0x0000000c 0x00000006 0x00000006
|
||||
0x00000003 0x00000001 0x00000004 0x00000005
|
||||
0x00000004 0x00000009 0x0000000d 0x00000b5f
|
||||
0x00000000 0x00000003 0x00000003 0x00000006
|
||||
0x00000006 0x00000001 0x00000011 0x000000c8
|
||||
0x00000003 0x0000000e 0x00000007 0x0000000f
|
||||
0x00000002 0x00000000 0x00000000 0x00000002
|
||||
0x00000000 0x00000000 0x00000083 0xe044048b
|
||||
0x007d8010 0x00000000 0x00000000 0x00000000
|
||||
0x00000000 0x00000000 0x00000000 0x00000000 >;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -26,6 +26,18 @@ i2c@7000d000 {
|
|||
status = "disable";
|
||||
};
|
||||
|
||||
i2s@70002800 {
|
||||
status = "disable";
|
||||
};
|
||||
|
||||
i2s@70002a00 {
|
||||
status = "disable";
|
||||
};
|
||||
|
||||
das@70000c00 {
|
||||
status = "disable";
|
||||
};
|
||||
|
||||
serial@70006000 {
|
||||
clock-frequency = < 216000000 >;
|
||||
};
|
||||
|
|
|
@ -12,6 +12,20 @@ memory {
|
|||
|
||||
i2c@7000c000 {
|
||||
clock-frequency = <400000>;
|
||||
|
||||
wm8903: wm8903@1a {
|
||||
compatible = "wlf,wm8903";
|
||||
reg = <0x1a>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = < 187 0x04 >;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
micdet-cfg = <0>;
|
||||
micdet-delay = <100>;
|
||||
gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@7000c400 {
|
||||
|
@ -26,6 +40,34 @@ i2c@7000d000 {
|
|||
clock-frequency = <400000>;
|
||||
};
|
||||
|
||||
i2s@70002a00 {
|
||||
status = "disable";
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "nvidia,tegra-audio-wm8903-ventana",
|
||||
"nvidia,tegra-audio-wm8903";
|
||||
nvidia,model = "NVIDIA Tegra Ventana";
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Headphone Jack", "HPOUTR",
|
||||
"Headphone Jack", "HPOUTL",
|
||||
"Int Spk", "ROP",
|
||||
"Int Spk", "RON",
|
||||
"Int Spk", "LOP",
|
||||
"Int Spk", "LON",
|
||||
"Mic Jack", "MICBIAS",
|
||||
"IN1L", "Mic Jack";
|
||||
|
||||
nvidia,i2s-controller = <&tegra_i2s1>;
|
||||
nvidia,audio-codec = <&wm8903>;
|
||||
|
||||
nvidia,spkr-en-gpios = <&wm8903 2 0>;
|
||||
nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
|
||||
nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
|
||||
nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
|
||||
};
|
||||
|
||||
serial@70006000 {
|
||||
status = "disable";
|
||||
};
|
||||
|
|
|
@ -4,6 +4,11 @@ / {
|
|||
compatible = "nvidia,tegra20";
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
pmc@7000f400 {
|
||||
compatible = "nvidia,tegra20-pmc";
|
||||
reg = <0x7000e400 0x400>;
|
||||
};
|
||||
|
||||
intc: interrupt-controller@50041000 {
|
||||
compatible = "arm,cortex-a9-gic";
|
||||
interrupt-controller;
|
||||
|
@ -12,6 +17,27 @@ intc: interrupt-controller@50041000 {
|
|||
< 0x50040100 0x0100 >;
|
||||
};
|
||||
|
||||
apbdma: dma@6000a000 {
|
||||
compatible = "nvidia,tegra20-apbdma";
|
||||
reg = <0x6000a000 0x1200>;
|
||||
interrupts = < 0 104 0x04
|
||||
0 105 0x04
|
||||
0 106 0x04
|
||||
0 107 0x04
|
||||
0 108 0x04
|
||||
0 109 0x04
|
||||
0 110 0x04
|
||||
0 111 0x04
|
||||
0 112 0x04
|
||||
0 113 0x04
|
||||
0 114 0x04
|
||||
0 115 0x04
|
||||
0 116 0x04
|
||||
0 117 0x04
|
||||
0 118 0x04
|
||||
0 119 0x04 >;
|
||||
};
|
||||
|
||||
i2c@7000c000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -44,18 +70,18 @@ i2c@7000d000 {
|
|||
interrupts = < 0 53 0x04 >;
|
||||
};
|
||||
|
||||
i2s@70002800 {
|
||||
tegra_i2s1: i2s@70002800 {
|
||||
compatible = "nvidia,tegra20-i2s";
|
||||
reg = <0x70002800 0x200>;
|
||||
interrupts = < 0 13 0x04 >;
|
||||
dma-channel = < 2 >;
|
||||
nvidia,dma-request-selector = < &apbdma 2 >;
|
||||
};
|
||||
|
||||
i2s@70002a00 {
|
||||
tegra_i2s2: i2s@70002a00 {
|
||||
compatible = "nvidia,tegra20-i2s";
|
||||
reg = <0x70002a00 0x200>;
|
||||
interrupts = < 0 3 0x04 >;
|
||||
dma-channel = < 1 >;
|
||||
nvidia,dma-request-selector = < &apbdma 1 >;
|
||||
};
|
||||
|
||||
das@70000c00 {
|
||||
|
@ -75,6 +101,8 @@ gpio: gpio@6000d000 {
|
|||
0 89 0x04 >;
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
};
|
||||
|
||||
pinmux: pinmux@70000000 {
|
||||
|
@ -120,6 +148,13 @@ serial@70006400 {
|
|||
interrupts = < 0 91 0x04 >;
|
||||
};
|
||||
|
||||
emc@7000f400 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "nvidia,tegra20-emc";
|
||||
reg = <0x7000f400 0x200>;
|
||||
};
|
||||
|
||||
sdhci@c8000000 {
|
||||
compatible = "nvidia,tegra20-sdhci";
|
||||
reg = <0xc8000000 0x200>;
|
||||
|
|
|
@ -4,6 +4,11 @@ / {
|
|||
compatible = "nvidia,tegra30";
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
pmc@7000f400 {
|
||||
compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc";
|
||||
reg = <0x7000e400 0x400>;
|
||||
};
|
||||
|
||||
intc: interrupt-controller@50041000 {
|
||||
compatible = "arm,cortex-a9-gic";
|
||||
interrupt-controller;
|
||||
|
@ -12,6 +17,43 @@ intc: interrupt-controller@50041000 {
|
|||
< 0x50040100 0x0100 >;
|
||||
};
|
||||
|
||||
apbdma: dma@6000a000 {
|
||||
compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma";
|
||||
reg = <0x6000a000 0x1400>;
|
||||
interrupts = < 0 104 0x04
|
||||
0 105 0x04
|
||||
0 106 0x04
|
||||
0 107 0x04
|
||||
0 108 0x04
|
||||
0 109 0x04
|
||||
0 110 0x04
|
||||
0 111 0x04
|
||||
0 112 0x04
|
||||
0 113 0x04
|
||||
0 114 0x04
|
||||
0 115 0x04
|
||||
0 116 0x04
|
||||
0 117 0x04
|
||||
0 118 0x04
|
||||
0 119 0x04
|
||||
0 128 0x04
|
||||
0 129 0x04
|
||||
0 130 0x04
|
||||
0 131 0x04
|
||||
0 132 0x04
|
||||
0 133 0x04
|
||||
0 134 0x04
|
||||
0 135 0x04
|
||||
0 136 0x04
|
||||
0 137 0x04
|
||||
0 138 0x04
|
||||
0 139 0x04
|
||||
0 140 0x04
|
||||
0 141 0x04
|
||||
0 142 0x04
|
||||
0 143 0x04 >;
|
||||
};
|
||||
|
||||
i2c@7000c000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -55,9 +97,18 @@ i2c@7000d000 {
|
|||
gpio: gpio@6000d000 {
|
||||
compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio";
|
||||
reg = < 0x6000d000 0x1000 >;
|
||||
interrupts = < 0 32 0x04 0 33 0x04 0 34 0x04 0 35 0x04 0 55 0x04 0 87 0x04 0 89 0x04 >;
|
||||
interrupts = < 0 32 0x04
|
||||
0 33 0x04
|
||||
0 34 0x04
|
||||
0 35 0x04
|
||||
0 55 0x04
|
||||
0 87 0x04
|
||||
0 89 0x04
|
||||
0 125 0x04 >;
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
};
|
||||
|
||||
serial@70006000 {
|
||||
|
|
|
@ -7,6 +7,7 @@ obj-y += clock.o
|
|||
obj-y += timer.o
|
||||
obj-y += pinmux.o
|
||||
obj-y += fuse.o
|
||||
obj-y += pmc.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
|
||||
|
@ -15,7 +16,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pinmux-tegra30-tables.o
|
|||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
|
||||
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o apbio.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
|
||||
obj-$(CONFIG_TEGRA_PCI) += pcie.o
|
||||
obj-$(CONFIG_USB_SUPPORT) += usb_phy.o
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2010 NVIDIA Corporation.
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#include "apbio.h"
|
||||
|
||||
static DEFINE_MUTEX(tegra_apb_dma_lock);
|
||||
|
||||
static struct tegra_dma_channel *tegra_apb_dma;
|
||||
static u32 *tegra_apb_bb;
|
||||
static dma_addr_t tegra_apb_bb_phys;
|
||||
static DECLARE_COMPLETION(tegra_apb_wait);
|
||||
|
||||
bool tegra_apb_init(void)
|
||||
{
|
||||
struct tegra_dma_channel *ch;
|
||||
|
||||
mutex_lock(&tegra_apb_dma_lock);
|
||||
|
||||
/* Check to see if we raced to setup */
|
||||
if (tegra_apb_dma)
|
||||
goto out;
|
||||
|
||||
ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
|
||||
TEGRA_DMA_SHARED);
|
||||
|
||||
if (!ch)
|
||||
goto out_fail;
|
||||
|
||||
tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
|
||||
&tegra_apb_bb_phys, GFP_KERNEL);
|
||||
if (!tegra_apb_bb) {
|
||||
pr_err("%s: can not allocate bounce buffer\n", __func__);
|
||||
tegra_dma_free_channel(ch);
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
tegra_apb_dma = ch;
|
||||
out:
|
||||
mutex_unlock(&tegra_apb_dma_lock);
|
||||
return true;
|
||||
|
||||
out_fail:
|
||||
mutex_unlock(&tegra_apb_dma_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void apb_dma_complete(struct tegra_dma_req *req)
|
||||
{
|
||||
complete(&tegra_apb_wait);
|
||||
}
|
||||
|
||||
u32 tegra_apb_readl(unsigned long offset)
|
||||
{
|
||||
struct tegra_dma_req req;
|
||||
int ret;
|
||||
|
||||
if (!tegra_apb_dma && !tegra_apb_init())
|
||||
return readl(IO_TO_VIRT(offset));
|
||||
|
||||
mutex_lock(&tegra_apb_dma_lock);
|
||||
req.complete = apb_dma_complete;
|
||||
req.to_memory = 1;
|
||||
req.dest_addr = tegra_apb_bb_phys;
|
||||
req.dest_bus_width = 32;
|
||||
req.dest_wrap = 1;
|
||||
req.source_addr = offset;
|
||||
req.source_bus_width = 32;
|
||||
req.source_wrap = 4;
|
||||
req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
|
||||
req.size = 4;
|
||||
|
||||
INIT_COMPLETION(tegra_apb_wait);
|
||||
|
||||
tegra_dma_enqueue_req(tegra_apb_dma, &req);
|
||||
|
||||
ret = wait_for_completion_timeout(&tegra_apb_wait,
|
||||
msecs_to_jiffies(50));
|
||||
|
||||
if (WARN(ret == 0, "apb read dma timed out")) {
|
||||
tegra_dma_dequeue_req(tegra_apb_dma, &req);
|
||||
*(u32 *)tegra_apb_bb = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&tegra_apb_dma_lock);
|
||||
return *((u32 *)tegra_apb_bb);
|
||||
}
|
||||
|
||||
void tegra_apb_writel(u32 value, unsigned long offset)
|
||||
{
|
||||
struct tegra_dma_req req;
|
||||
int ret;
|
||||
|
||||
if (!tegra_apb_dma && !tegra_apb_init()) {
|
||||
writel(value, IO_TO_VIRT(offset));
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&tegra_apb_dma_lock);
|
||||
*((u32 *)tegra_apb_bb) = value;
|
||||
req.complete = apb_dma_complete;
|
||||
req.to_memory = 0;
|
||||
req.dest_addr = offset;
|
||||
req.dest_wrap = 4;
|
||||
req.dest_bus_width = 32;
|
||||
req.source_addr = tegra_apb_bb_phys;
|
||||
req.source_bus_width = 32;
|
||||
req.source_wrap = 1;
|
||||
req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
|
||||
req.size = 4;
|
||||
|
||||
INIT_COMPLETION(tegra_apb_wait);
|
||||
|
||||
tegra_dma_enqueue_req(tegra_apb_dma, &req);
|
||||
|
||||
ret = wait_for_completion_timeout(&tegra_apb_wait,
|
||||
msecs_to_jiffies(50));
|
||||
|
||||
if (WARN(ret == 0, "apb write dma timed out"))
|
||||
tegra_dma_dequeue_req(tegra_apb_dma, &req);
|
||||
|
||||
mutex_unlock(&tegra_apb_dma_lock);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2010 NVIDIA Corporation.
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_APBIO_H
|
||||
#define __MACH_TEGRA_APBIO_H
|
||||
|
||||
#ifdef CONFIG_TEGRA_SYSTEM_DMA
|
||||
|
||||
u32 tegra_apb_readl(unsigned long offset);
|
||||
void tegra_apb_writel(u32 value, unsigned long offset);
|
||||
|
||||
#else
|
||||
#include <asm/io.h>
|
||||
#include <mach/io.h>
|
||||
|
||||
static inline u32 tegra_apb_readl(unsigned long offset)
|
||||
{
|
||||
return readl(IO_TO_VIRT(offset));
|
||||
}
|
||||
|
||||
static inline void tegra_apb_writel(u32 value, unsigned long offset)
|
||||
{
|
||||
writel(value, IO_TO_VIRT(offset));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -18,18 +18,13 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/mfd/tps6586x.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
#include "board-harmony.h"
|
||||
|
||||
#define PMC_CTRL 0x0
|
||||
#define PMC_CTRL_INTR_LOW (1 << 17)
|
||||
|
||||
static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
|
||||
REGULATOR_SUPPLY("pex_clk", NULL),
|
||||
};
|
||||
|
@ -114,16 +109,6 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
|
|||
|
||||
int __init harmony_regulator_init(void)
|
||||
{
|
||||
void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
|
||||
u32 pmc_ctrl;
|
||||
|
||||
/*
|
||||
* Configure the power management controller to trigger PMU
|
||||
* interrupts when low
|
||||
*/
|
||||
pmc_ctrl = readl(pmc + PMC_CTRL);
|
||||
writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
|
||||
|
||||
i2c_register_board_info(3, harmony_regulators, 1);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -101,7 +101,6 @@ static struct wm8903_platform_data harmony_wm8903_pdata = {
|
|||
static struct i2c_board_info __initdata wm8903_board_info = {
|
||||
I2C_BOARD_INFO("wm8903", 0x1a),
|
||||
.platform_data = &harmony_wm8903_pdata,
|
||||
.irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
|
||||
};
|
||||
|
||||
static void __init harmony_i2c_init(void)
|
||||
|
@ -111,6 +110,7 @@ static void __init harmony_i2c_init(void)
|
|||
platform_device_register(&tegra_i2c_device3);
|
||||
platform_device_register(&tegra_i2c_device4);
|
||||
|
||||
wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
|
||||
i2c_register_board_info(0, &wm8903_board_info, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,6 @@ static struct platform_device *seaboard_devices[] __initdata = {
|
|||
|
||||
static struct i2c_board_info __initdata isl29018_device = {
|
||||
I2C_BOARD_INFO("isl29018", 0x44),
|
||||
.irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ),
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata adt7461_device = {
|
||||
|
@ -183,7 +182,6 @@ static struct wm8903_platform_data wm8903_pdata = {
|
|||
static struct i2c_board_info __initdata wm8903_device = {
|
||||
I2C_BOARD_INFO("wm8903", 0x1a),
|
||||
.platform_data = &wm8903_pdata,
|
||||
.irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
|
||||
};
|
||||
|
||||
static int seaboard_ehci_init(void)
|
||||
|
@ -214,7 +212,10 @@ static void __init seaboard_i2c_init(void)
|
|||
gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
|
||||
gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
|
||||
|
||||
isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ);
|
||||
i2c_register_board_info(0, &isl29018_device, 1);
|
||||
|
||||
wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
|
||||
i2c_register_board_info(0, &wm8903_device, 1);
|
||||
|
||||
i2c_register_board_info(3, &adt7461_device, 1);
|
||||
|
|
|
@ -31,6 +31,24 @@
|
|||
#include "board.h"
|
||||
#include "clock.h"
|
||||
#include "fuse.h"
|
||||
#include "pmc.h"
|
||||
|
||||
/*
|
||||
* Storage for debug-macro.S's state.
|
||||
*
|
||||
* This must be in .data not .bss so that it gets initialized each time the
|
||||
* kernel is loaded. The data is declared here rather than debug-macro.S so
|
||||
* that multiple inclusions of debug-macro.S point at the same data.
|
||||
*/
|
||||
#define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF)
|
||||
u32 tegra_uart_config[3] = {
|
||||
/* Debug UART initialization required */
|
||||
1,
|
||||
/* Debug UART physical address */
|
||||
(u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET),
|
||||
/* Debug UART virtual address */
|
||||
(u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id tegra_dt_irq_match[] __initconst = {
|
||||
|
@ -101,11 +119,13 @@ void __init tegra20_init_early(void)
|
|||
tegra2_init_clocks();
|
||||
tegra_clk_init_from_table(tegra20_clk_init_table);
|
||||
tegra_init_cache(0x331, 0x441);
|
||||
tegra_pmc_init();
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
void __init tegra30_init_early(void)
|
||||
{
|
||||
tegra_init_cache(0x441, 0x551);
|
||||
tegra_pmc_init();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <mach/iomap.h>
|
||||
#include <mach/suspend.h>
|
||||
|
||||
#include "apbio.h"
|
||||
|
||||
#define APB_DMA_GEN 0x000
|
||||
#define GEN_ENABLE (1<<31)
|
||||
|
||||
|
@ -50,8 +52,6 @@
|
|||
#define CSR_ONCE (1<<27)
|
||||
#define CSR_FLOW (1<<21)
|
||||
#define CSR_REQ_SEL_SHIFT 16
|
||||
#define CSR_REQ_SEL_MASK (0x1F<<CSR_REQ_SEL_SHIFT)
|
||||
#define CSR_REQ_SEL_INVALID (31<<CSR_REQ_SEL_SHIFT)
|
||||
#define CSR_WCOUNT_SHIFT 2
|
||||
#define CSR_WCOUNT_MASK 0xFFFC
|
||||
|
||||
|
@ -133,6 +133,7 @@ struct tegra_dma_channel {
|
|||
|
||||
static bool tegra_dma_initialized;
|
||||
static DEFINE_MUTEX(tegra_dma_lock);
|
||||
static DEFINE_SPINLOCK(enable_lock);
|
||||
|
||||
static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
|
||||
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)
|
|||
|
||||
static int tegra_dma_cancel(struct tegra_dma_channel *ch)
|
||||
{
|
||||
u32 csr;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&ch->lock, irq_flags);
|
||||
while (!list_empty(&ch->list))
|
||||
list_del(ch->list.next);
|
||||
|
||||
csr = readl(ch->addr + APB_DMA_CHAN_CSR);
|
||||
csr &= ~CSR_REQ_SEL_MASK;
|
||||
csr |= CSR_REQ_SEL_INVALID;
|
||||
writel(csr, ch->addr + APB_DMA_CHAN_CSR);
|
||||
|
||||
tegra_dma_stop(ch);
|
||||
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int get_channel_status(struct tegra_dma_channel *ch,
|
||||
struct tegra_dma_req *req, bool is_stop_dma)
|
||||
{
|
||||
void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
|
||||
unsigned int status;
|
||||
|
||||
if (is_stop_dma) {
|
||||
/*
|
||||
* STOP the DMA and get the transfer count.
|
||||
* Getting the transfer count is tricky.
|
||||
* - Globally disable DMA on all channels
|
||||
* - Read the channel's status register to know the number
|
||||
* of pending bytes to be transfered.
|
||||
* - Stop the dma channel
|
||||
* - Globally re-enable DMA to resume other transfers
|
||||
*/
|
||||
spin_lock(&enable_lock);
|
||||
writel(0, addr + APB_DMA_GEN);
|
||||
udelay(20);
|
||||
status = readl(ch->addr + APB_DMA_CHAN_STA);
|
||||
tegra_dma_stop(ch);
|
||||
writel(GEN_ENABLE, addr + APB_DMA_GEN);
|
||||
spin_unlock(&enable_lock);
|
||||
if (status & STA_ISE_EOC) {
|
||||
pr_err("Got Dma Int here clearing");
|
||||
writel(status, ch->addr + APB_DMA_CHAN_STA);
|
||||
}
|
||||
req->status = TEGRA_DMA_REQ_ERROR_ABORTED;
|
||||
} else {
|
||||
status = readl(ch->addr + APB_DMA_CHAN_STA);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* should be called with the channel lock held */
|
||||
static unsigned int dma_active_count(struct tegra_dma_channel *ch,
|
||||
struct tegra_dma_req *req, unsigned int status)
|
||||
{
|
||||
unsigned int to_transfer;
|
||||
unsigned int req_transfer_count;
|
||||
unsigned int bytes_transferred;
|
||||
|
||||
to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1;
|
||||
req_transfer_count = ch->req_transfer_count + 1;
|
||||
bytes_transferred = req_transfer_count;
|
||||
if (status & STA_BUSY)
|
||||
bytes_transferred -= to_transfer;
|
||||
/*
|
||||
* In continuous transfer mode, DMA only tracks the count of the
|
||||
* half DMA buffer. So, if the DMA already finished half the DMA
|
||||
* then add the half buffer to the completed count.
|
||||
*/
|
||||
if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) {
|
||||
if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
|
||||
bytes_transferred += req_transfer_count;
|
||||
if (status & STA_ISE_EOC)
|
||||
bytes_transferred += req_transfer_count;
|
||||
}
|
||||
bytes_transferred *= 4;
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
|
||||
struct tegra_dma_req *_req)
|
||||
{
|
||||
unsigned int csr;
|
||||
unsigned int status;
|
||||
struct tegra_dma_req *req = NULL;
|
||||
int found = 0;
|
||||
unsigned long irq_flags;
|
||||
int to_transfer;
|
||||
int req_transfer_count;
|
||||
int stop = 0;
|
||||
|
||||
spin_lock_irqsave(&ch->lock, irq_flags);
|
||||
|
||||
if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req)
|
||||
stop = 1;
|
||||
|
||||
list_for_each_entry(req, &ch->list, node) {
|
||||
if (req == _req) {
|
||||
list_del(&req->node);
|
||||
|
@ -222,47 +281,12 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* STOP the DMA and get the transfer count.
|
||||
* Getting the transfer count is tricky.
|
||||
* - Change the source selector to invalid to stop the DMA from
|
||||
* FIFO to memory.
|
||||
* - Read the status register to know the number of pending
|
||||
* bytes to be transferred.
|
||||
* - Finally stop or program the DMA to the next buffer in the
|
||||
* list.
|
||||
*/
|
||||
csr = readl(ch->addr + APB_DMA_CHAN_CSR);
|
||||
csr &= ~CSR_REQ_SEL_MASK;
|
||||
csr |= CSR_REQ_SEL_INVALID;
|
||||
writel(csr, ch->addr + APB_DMA_CHAN_CSR);
|
||||
if (!stop)
|
||||
goto skip_stop_dma;
|
||||
|
||||
/* Get the transfer count */
|
||||
status = readl(ch->addr + APB_DMA_CHAN_STA);
|
||||
to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
|
||||
req_transfer_count = ch->req_transfer_count;
|
||||
req_transfer_count += 1;
|
||||
to_transfer += 1;
|
||||
status = get_channel_status(ch, req, true);
|
||||
req->bytes_transferred = dma_active_count(ch, req, status);
|
||||
|
||||
req->bytes_transferred = req_transfer_count;
|
||||
|
||||
if (status & STA_BUSY)
|
||||
req->bytes_transferred -= to_transfer;
|
||||
|
||||
/* In continuous transfer mode, DMA only tracks the count of the
|
||||
* half DMA buffer. So, if the DMA already finished half the DMA
|
||||
* then add the half buffer to the completed count.
|
||||
*
|
||||
* FIXME: There can be a race here. What if the req to
|
||||
* dequue happens at the same time as the DMA just moved to
|
||||
* the new buffer and SW didn't yet received the interrupt?
|
||||
*/
|
||||
if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
|
||||
if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
|
||||
req->bytes_transferred += req_transfer_count;
|
||||
|
||||
req->bytes_transferred *= 4;
|
||||
|
||||
tegra_dma_stop(ch);
|
||||
if (!list_empty(&ch->list)) {
|
||||
/* if the list is not empty, queue the next request */
|
||||
struct tegra_dma_req *next_req;
|
||||
|
@ -270,6 +294,8 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
|
|||
typeof(*next_req), node);
|
||||
tegra_dma_update_hw(ch, next_req);
|
||||
}
|
||||
|
||||
skip_stop_dma:
|
||||
req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
|
||||
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
|
@ -357,7 +383,7 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
|
|||
int channel;
|
||||
struct tegra_dma_channel *ch = NULL;
|
||||
|
||||
if (WARN_ON(!tegra_dma_initialized))
|
||||
if (!tegra_dma_initialized)
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&tegra_dma_lock);
|
||||
|
|
|
@ -23,20 +23,70 @@
|
|||
#include <mach/iomap.h>
|
||||
|
||||
#include "fuse.h"
|
||||
#include "apbio.h"
|
||||
|
||||
#define FUSE_UID_LOW 0x108
|
||||
#define FUSE_UID_HIGH 0x10c
|
||||
#define FUSE_SKU_INFO 0x110
|
||||
#define FUSE_SPARE_BIT 0x200
|
||||
|
||||
static inline u32 fuse_readl(unsigned long offset)
|
||||
int tegra_sku_id;
|
||||
int tegra_cpu_process_id;
|
||||
int tegra_core_process_id;
|
||||
enum tegra_revision tegra_revision;
|
||||
|
||||
/* The BCT to use at boot is specified by board straps that can be read
|
||||
* through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
|
||||
*/
|
||||
int tegra_bct_strapping;
|
||||
|
||||
#define STRAP_OPT 0x008
|
||||
#define GMI_AD0 (1 << 4)
|
||||
#define GMI_AD1 (1 << 5)
|
||||
#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
|
||||
#define RAM_CODE_SHIFT 4
|
||||
|
||||
static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
|
||||
[TEGRA_REVISION_UNKNOWN] = "unknown",
|
||||
[TEGRA_REVISION_A01] = "A01",
|
||||
[TEGRA_REVISION_A02] = "A02",
|
||||
[TEGRA_REVISION_A03] = "A03",
|
||||
[TEGRA_REVISION_A03p] = "A03 prime",
|
||||
[TEGRA_REVISION_A04] = "A04",
|
||||
};
|
||||
|
||||
static inline u32 tegra_fuse_readl(unsigned long offset)
|
||||
{
|
||||
return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
|
||||
return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
|
||||
}
|
||||
|
||||
static inline void fuse_writel(u32 value, unsigned long offset)
|
||||
static inline bool get_spare_fuse(int bit)
|
||||
{
|
||||
writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
|
||||
return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
|
||||
}
|
||||
|
||||
static enum tegra_revision tegra_get_revision(void)
|
||||
{
|
||||
void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
|
||||
u32 id = readl(chip_id);
|
||||
u32 minor_rev = (id >> 16) & 0xf;
|
||||
u32 chipid = (id >> 8) & 0xff;
|
||||
|
||||
switch (minor_rev) {
|
||||
case 1:
|
||||
return TEGRA_REVISION_A01;
|
||||
case 2:
|
||||
return TEGRA_REVISION_A02;
|
||||
case 3:
|
||||
if (chipid == 0x20 && (get_spare_fuse(18) || get_spare_fuse(19)))
|
||||
return TEGRA_REVISION_A03p;
|
||||
else
|
||||
return TEGRA_REVISION_A03;
|
||||
case 4:
|
||||
return TEGRA_REVISION_A04;
|
||||
default:
|
||||
return TEGRA_REVISION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void tegra_init_fuse(void)
|
||||
|
@ -45,40 +95,31 @@ void tegra_init_fuse(void)
|
|||
reg |= 1 << 28;
|
||||
writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
|
||||
|
||||
pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
|
||||
tegra_sku_id(), tegra_cpu_process_id(),
|
||||
tegra_core_process_id());
|
||||
reg = tegra_fuse_readl(FUSE_SKU_INFO);
|
||||
tegra_sku_id = reg & 0xFF;
|
||||
|
||||
reg = tegra_fuse_readl(FUSE_SPARE_BIT);
|
||||
tegra_cpu_process_id = (reg >> 6) & 3;
|
||||
|
||||
reg = tegra_fuse_readl(FUSE_SPARE_BIT);
|
||||
tegra_core_process_id = (reg >> 12) & 3;
|
||||
|
||||
reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
|
||||
tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
|
||||
|
||||
tegra_revision = tegra_get_revision();
|
||||
|
||||
pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
|
||||
tegra_revision_name[tegra_get_revision()],
|
||||
tegra_sku_id, tegra_cpu_process_id,
|
||||
tegra_core_process_id);
|
||||
}
|
||||
|
||||
unsigned long long tegra_chip_uid(void)
|
||||
{
|
||||
unsigned long long lo, hi;
|
||||
|
||||
lo = fuse_readl(FUSE_UID_LOW);
|
||||
hi = fuse_readl(FUSE_UID_HIGH);
|
||||
lo = tegra_fuse_readl(FUSE_UID_LOW);
|
||||
hi = tegra_fuse_readl(FUSE_UID_HIGH);
|
||||
return (hi << 32ull) | lo;
|
||||
}
|
||||
|
||||
int tegra_sku_id(void)
|
||||
{
|
||||
int sku_id;
|
||||
u32 reg = fuse_readl(FUSE_SKU_INFO);
|
||||
sku_id = reg & 0xFF;
|
||||
return sku_id;
|
||||
}
|
||||
|
||||
int tegra_cpu_process_id(void)
|
||||
{
|
||||
int cpu_process_id;
|
||||
u32 reg = fuse_readl(FUSE_SPARE_BIT);
|
||||
cpu_process_id = (reg >> 6) & 3;
|
||||
return cpu_process_id;
|
||||
}
|
||||
|
||||
int tegra_core_process_id(void)
|
||||
{
|
||||
int core_process_id;
|
||||
u32 reg = fuse_readl(FUSE_SPARE_BIT);
|
||||
core_process_id = (reg >> 12) & 3;
|
||||
return core_process_id;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/fuse.c
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
|
@ -17,8 +15,34 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_FUSE_H
|
||||
#define __MACH_TEGRA_FUSE_H
|
||||
|
||||
enum tegra_revision {
|
||||
TEGRA_REVISION_UNKNOWN = 0,
|
||||
TEGRA_REVISION_A01,
|
||||
TEGRA_REVISION_A02,
|
||||
TEGRA_REVISION_A03,
|
||||
TEGRA_REVISION_A03p,
|
||||
TEGRA_REVISION_A04,
|
||||
TEGRA_REVISION_MAX,
|
||||
};
|
||||
|
||||
#define SKU_ID_T20 8
|
||||
#define SKU_ID_T25SE 20
|
||||
#define SKU_ID_AP25 23
|
||||
#define SKU_ID_T25 24
|
||||
#define SKU_ID_AP25E 27
|
||||
#define SKU_ID_T25E 28
|
||||
|
||||
extern int tegra_sku_id;
|
||||
extern int tegra_cpu_process_id;
|
||||
extern int tegra_core_process_id;
|
||||
extern enum tegra_revision tegra_revision;
|
||||
|
||||
extern int tegra_bct_strapping;
|
||||
|
||||
unsigned long long tegra_chip_uid(void);
|
||||
int tegra_sku_id(void);
|
||||
int tegra_cpu_process_id(void);
|
||||
int tegra_core_process_id(void);
|
||||
void tegra_init_fuse(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/include/mach/debug-macro.S
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (C) 2010,2011 Google, Inc.
|
||||
* Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
* Erik Gilling <konkers@google.com>
|
||||
* Doug Anderson <dianders@chromium.org>
|
||||
* Stephen Warren <swarren@nvidia.com>
|
||||
*
|
||||
* Portions based on mach-omap2's debug-macro.S
|
||||
* Copyright (C) 1994-1999 Russell King
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -18,18 +24,78 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#include <mach/io.h>
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/irammap.h>
|
||||
|
||||
.macro addruart, rp, rv, tmp
|
||||
ldr \rp, =IO_APB_PHYS @ physical
|
||||
ldr \rv, =IO_APB_VIRT @ virtual
|
||||
orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF)
|
||||
orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
|
||||
orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF)
|
||||
orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
|
||||
.endm
|
||||
.macro addruart, rp, rv, tmp
|
||||
adr \rp, 99f @ actual addr of 99f
|
||||
ldr \rv, [\rp] @ linked addr is stored there
|
||||
sub \rv, \rv, \rp @ offset between the two
|
||||
ldr \rp, [\rp, #4] @ linked tegra_uart_config
|
||||
sub \tmp, \rp, \rv @ actual tegra_uart_config
|
||||
ldr \rp, [\tmp] @ Load tegra_uart_config
|
||||
cmp \rp, #1 @ needs intitialization?
|
||||
bne 100f @ no; go load the addresses
|
||||
mov \rv, #0 @ yes; record init is done
|
||||
str \rv, [\tmp]
|
||||
mov \rp, #TEGRA_IRAM_BASE @ See if cookie is in IRAM
|
||||
ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET]
|
||||
movw \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff
|
||||
movt \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16
|
||||
cmp \rv, \rp @ Cookie present?
|
||||
bne 100f @ No, use default UART
|
||||
mov \rp, #TEGRA_IRAM_BASE @ Load UART address from IRAM
|
||||
ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4]
|
||||
str \rv, [\tmp, #4] @ Store in tegra_uart_phys
|
||||
sub \rv, \rv, #IO_APB_PHYS @ Calculate virt address
|
||||
add \rv, \rv, #IO_APB_VIRT
|
||||
str \rv, [\tmp, #8] @ Store in tegra_uart_virt
|
||||
b 100f
|
||||
|
||||
#define UART_SHIFT 2
|
||||
#include <asm/hardware/debug-8250.S>
|
||||
.align
|
||||
99: .word .
|
||||
.word tegra_uart_config
|
||||
.ltorg
|
||||
|
||||
100: ldr \rp, [\tmp, #4] @ Load tegra_uart_phys
|
||||
ldr \rv, [\tmp, #8] @ Load tegra_uart_virt
|
||||
.endm
|
||||
|
||||
#define UART_SHIFT 2
|
||||
|
||||
/*
|
||||
* Code below is swiped from <asm/hardware/debug-8250.S>, but add an extra
|
||||
* check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case.
|
||||
* We use the fact that all 5 valid UART addresses all have something in the
|
||||
* 2nd-to-lowest byte.
|
||||
*/
|
||||
|
||||
.macro senduart, rd, rx
|
||||
tst \rx, #0x0000ff00
|
||||
strneb \rd, [\rx, #UART_TX << UART_SHIFT]
|
||||
1001:
|
||||
.endm
|
||||
|
||||
.macro busyuart, rd, rx
|
||||
tst \rx, #0x0000ff00
|
||||
beq 1002f
|
||||
1001: ldrb \rd, [\rx, #UART_LSR << UART_SHIFT]
|
||||
and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
|
||||
teq \rd, #UART_LSR_TEMT | UART_LSR_THRE
|
||||
bne 1001b
|
||||
1002:
|
||||
.endm
|
||||
|
||||
.macro waituart, rd, rx
|
||||
#ifdef FLOW_CONTROL
|
||||
tst \rx, #0x0000ff00
|
||||
beq 1002f
|
||||
1001: ldrb \rd, [\rx, #UART_MSR << UART_SHIFT]
|
||||
tst \rd, #UART_MSR_CTS
|
||||
beq 1001b
|
||||
1002:
|
||||
#endif
|
||||
.endm
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
#define TEGRA_NR_GPIOS INT_GPIO_NR
|
||||
|
||||
#define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio))
|
||||
|
||||
struct tegra_gpio_table {
|
||||
int gpio; /* GPIO number */
|
||||
bool enable; /* Enable for GPIO at init? */
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_IRAMMAP_H
|
||||
#define __MACH_TEGRA_IRAMMAP_H
|
||||
|
||||
#include <asm/sizes.h>
|
||||
|
||||
/* The first 1K of IRAM is permanently reserved for the CPU reset handler */
|
||||
#define TEGRA_IRAM_RESET_HANDLER_OFFSET 0
|
||||
#define TEGRA_IRAM_RESET_HANDLER_SIZE SZ_1K
|
||||
|
||||
/*
|
||||
* These locations are written to by uncompress.h, and read by debug-macro.S.
|
||||
* The first word holds the cookie value if the data is valid. The second
|
||||
* word holds the UART physical address.
|
||||
*/
|
||||
#define TEGRA_IRAM_DEBUG_UART_OFFSET SZ_1K
|
||||
#define TEGRA_IRAM_DEBUG_UART_SIZE 8
|
||||
#define TEGRA_IRAM_DEBUG_UART_COOKIE 0x55415254
|
||||
|
||||
#endif
|
|
@ -2,10 +2,14 @@
|
|||
* arch/arm/mach-tegra/include/mach/uncompress.h
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
* Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
* Erik Gilling <konkers@google.com>
|
||||
* Doug Anderson <dianders@chromium.org>
|
||||
* Stephen Warren <swarren@nvidia.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -25,36 +29,130 @@
|
|||
#include <linux/serial_reg.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/irammap.h>
|
||||
|
||||
#define BIT(x) (1 << (x))
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define DEBUG_UART_SHIFT 2
|
||||
|
||||
volatile u8 *uart;
|
||||
|
||||
static void putc(int c)
|
||||
{
|
||||
volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
|
||||
int shift = 2;
|
||||
|
||||
if (uart == NULL)
|
||||
return;
|
||||
|
||||
while (!(uart[UART_LSR << shift] & UART_LSR_THRE))
|
||||
while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE))
|
||||
barrier();
|
||||
uart[UART_TX << shift] = c;
|
||||
uart[UART_TX << DEBUG_UART_SHIFT] = c;
|
||||
}
|
||||
|
||||
static inline void flush(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void save_uart_address(void)
|
||||
{
|
||||
u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET);
|
||||
|
||||
if (uart) {
|
||||
buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE;
|
||||
buf[1] = (u32)uart;
|
||||
} else
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup before decompression. This is where we do UART selection for
|
||||
* earlyprintk and init the uart_base register.
|
||||
*/
|
||||
static inline void arch_decomp_setup(void)
|
||||
{
|
||||
volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
|
||||
int shift = 2;
|
||||
static const struct {
|
||||
u32 base;
|
||||
u32 reset_reg;
|
||||
u32 clock_reg;
|
||||
u32 bit;
|
||||
} uarts[] = {
|
||||
{
|
||||
TEGRA_UARTA_BASE,
|
||||
TEGRA_CLK_RESET_BASE + 0x04,
|
||||
TEGRA_CLK_RESET_BASE + 0x10,
|
||||
6,
|
||||
},
|
||||
{
|
||||
TEGRA_UARTB_BASE,
|
||||
TEGRA_CLK_RESET_BASE + 0x04,
|
||||
TEGRA_CLK_RESET_BASE + 0x10,
|
||||
7,
|
||||
},
|
||||
{
|
||||
TEGRA_UARTC_BASE,
|
||||
TEGRA_CLK_RESET_BASE + 0x08,
|
||||
TEGRA_CLK_RESET_BASE + 0x14,
|
||||
23,
|
||||
},
|
||||
{
|
||||
TEGRA_UARTD_BASE,
|
||||
TEGRA_CLK_RESET_BASE + 0x0c,
|
||||
TEGRA_CLK_RESET_BASE + 0x18,
|
||||
1,
|
||||
},
|
||||
{
|
||||
TEGRA_UARTE_BASE,
|
||||
TEGRA_CLK_RESET_BASE + 0x0c,
|
||||
TEGRA_CLK_RESET_BASE + 0x18,
|
||||
2,
|
||||
},
|
||||
};
|
||||
int i;
|
||||
volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
|
||||
u32 chip, div;
|
||||
|
||||
/*
|
||||
* Look for the first UART that:
|
||||
* a) Is not in reset.
|
||||
* b) Is clocked.
|
||||
* c) Has a 'D' in the scratchpad register.
|
||||
*
|
||||
* Note that on Tegra30, the first two conditions are required, since
|
||||
* if not true, accesses to the UART scratch register will hang.
|
||||
* Tegra20 doesn't have this issue.
|
||||
*
|
||||
* The intent is that the bootloader will tell the kernel which UART
|
||||
* to use by setting up those conditions. If nothing found, we'll fall
|
||||
* back to what's specified in TEGRA_DEBUG_UART_BASE.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(uarts); i++) {
|
||||
if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
|
||||
continue;
|
||||
|
||||
if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
|
||||
continue;
|
||||
|
||||
uart = (volatile u8 *)uarts[i].base;
|
||||
if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(uarts))
|
||||
uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
|
||||
save_uart_address();
|
||||
if (uart == NULL)
|
||||
return;
|
||||
|
||||
uart[UART_LCR << shift] |= UART_LCR_DLAB;
|
||||
uart[UART_DLL << shift] = 0x75;
|
||||
uart[UART_DLM << shift] = 0x0;
|
||||
uart[UART_LCR << shift] = 3;
|
||||
chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
|
||||
if (chip == 0x20)
|
||||
div = 0x0075;
|
||||
else
|
||||
div = 0x00dd;
|
||||
|
||||
uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB;
|
||||
uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff;
|
||||
uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8;
|
||||
uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
|
||||
}
|
||||
|
||||
static inline void arch_decomp_wdog(void)
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#define PMC_CTRL 0x0
|
||||
#define PMC_CTRL_INTR_LOW (1 << 17)
|
||||
|
||||
static inline u32 tegra_pmc_readl(u32 reg)
|
||||
{
|
||||
return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg));
|
||||
}
|
||||
|
||||
static inline void tegra_pmc_writel(u32 val, u32 reg)
|
||||
{
|
||||
writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id matches[] __initconst = {
|
||||
{ .compatible = "nvidia,tegra20-pmc" },
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
void __init tegra_pmc_init(void)
|
||||
{
|
||||
/*
|
||||
* For now, Harmony is the only board that uses the PMC, and it wants
|
||||
* the signal inverted. Seaboard would too if it used the PMC.
|
||||
* Hopefully by the time other boards want to use the PMC, everything
|
||||
* will be device-tree, or they also want it inverted.
|
||||
*/
|
||||
bool invert_interrupt = true;
|
||||
u32 val;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (of_have_populated_dt()) {
|
||||
struct device_node *np;
|
||||
|
||||
invert_interrupt = false;
|
||||
|
||||
np = of_find_matching_node(NULL, matches);
|
||||
if (np) {
|
||||
if (of_find_property(np, "nvidia,invert-interrupt",
|
||||
NULL))
|
||||
invert_interrupt = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
val = tegra_pmc_readl(PMC_CTRL);
|
||||
if (invert_interrupt)
|
||||
val |= PMC_CTRL_INTR_LOW;
|
||||
else
|
||||
val &= ~PMC_CTRL_INTR_LOW;
|
||||
tegra_pmc_writel(val, PMC_CTRL);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_PMC_H
|
||||
#define __MACH_TEGRA_PMC_H
|
||||
|
||||
void tegra_pmc_init(void);
|
||||
|
||||
#endif
|
|
@ -720,7 +720,7 @@ static void tegra2_pllx_clk_init(struct clk *c)
|
|||
{
|
||||
tegra2_pll_clk_init(c);
|
||||
|
||||
if (tegra_sku_id() == 7)
|
||||
if (tegra_sku_id == 7)
|
||||
c->max_rate = 750000000;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,14 +16,19 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/tegra_emc.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#include "tegra2_emc.h"
|
||||
#include "fuse.h"
|
||||
|
||||
#ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
|
||||
static bool emc_enable = true;
|
||||
|
@ -32,18 +37,17 @@ static bool emc_enable;
|
|||
#endif
|
||||
module_param(emc_enable, bool, 0644);
|
||||
|
||||
static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE);
|
||||
static const struct tegra_emc_table *tegra_emc_table;
|
||||
static int tegra_emc_table_size;
|
||||
static struct platform_device *emc_pdev;
|
||||
static void __iomem *emc_regbase;
|
||||
|
||||
static inline void emc_writel(u32 val, unsigned long addr)
|
||||
{
|
||||
writel(val, emc + addr);
|
||||
writel(val, emc_regbase + addr);
|
||||
}
|
||||
|
||||
static inline u32 emc_readl(unsigned long addr)
|
||||
{
|
||||
return readl(emc + addr);
|
||||
return readl(emc_regbase + addr);
|
||||
}
|
||||
|
||||
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] = {
|
|||
/* Select the closest EMC rate that is higher than the requested rate */
|
||||
long tegra_emc_round_rate(unsigned long rate)
|
||||
{
|
||||
struct tegra_emc_pdata *pdata;
|
||||
int i;
|
||||
int best = -1;
|
||||
unsigned long distance = ULONG_MAX;
|
||||
|
||||
if (!tegra_emc_table)
|
||||
if (!emc_pdev)
|
||||
return -EINVAL;
|
||||
|
||||
if (!emc_enable)
|
||||
return -EINVAL;
|
||||
pdata = emc_pdev->dev.platform_data;
|
||||
|
||||
pr_debug("%s: %lu\n", __func__, rate);
|
||||
|
||||
|
@ -116,10 +120,10 @@ long tegra_emc_round_rate(unsigned long rate)
|
|||
*/
|
||||
rate = rate / 2 / 1000;
|
||||
|
||||
for (i = 0; i < tegra_emc_table_size; i++) {
|
||||
if (tegra_emc_table[i].rate >= rate &&
|
||||
(tegra_emc_table[i].rate - rate) < distance) {
|
||||
distance = tegra_emc_table[i].rate - rate;
|
||||
for (i = 0; i < pdata->num_tables; i++) {
|
||||
if (pdata->tables[i].rate >= rate &&
|
||||
(pdata->tables[i].rate - rate) < distance) {
|
||||
distance = pdata->tables[i].rate - rate;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
@ -127,9 +131,9 @@ long tegra_emc_round_rate(unsigned long rate)
|
|||
if (best < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate);
|
||||
pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate);
|
||||
|
||||
return tegra_emc_table[best].rate * 2 * 1000;
|
||||
return pdata->tables[best].rate * 2 * 1000;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -142,37 +146,211 @@ long tegra_emc_round_rate(unsigned long rate)
|
|||
*/
|
||||
int tegra_emc_set_rate(unsigned long rate)
|
||||
{
|
||||
struct tegra_emc_pdata *pdata;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (!tegra_emc_table)
|
||||
if (!emc_pdev)
|
||||
return -EINVAL;
|
||||
|
||||
pdata = emc_pdev->dev.platform_data;
|
||||
|
||||
/*
|
||||
* The EMC clock rate is twice the bus rate, and the bus rate is
|
||||
* measured in kHz
|
||||
*/
|
||||
rate = rate / 2 / 1000;
|
||||
|
||||
for (i = 0; i < tegra_emc_table_size; i++)
|
||||
if (tegra_emc_table[i].rate == rate)
|
||||
for (i = 0; i < pdata->num_tables; i++)
|
||||
if (pdata->tables[i].rate == rate)
|
||||
break;
|
||||
|
||||
if (i >= tegra_emc_table_size)
|
||||
if (i >= pdata->num_tables)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("%s: setting to %lu\n", __func__, rate);
|
||||
|
||||
for (j = 0; j < TEGRA_EMC_NUM_REGS; j++)
|
||||
emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]);
|
||||
emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]);
|
||||
|
||||
emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]);
|
||||
emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
|
||||
#ifdef CONFIG_OF
|
||||
static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np)
|
||||
{
|
||||
tegra_emc_table = table;
|
||||
tegra_emc_table_size = table_size;
|
||||
struct device_node *iter;
|
||||
u32 reg;
|
||||
|
||||
for_each_child_of_node(np, iter) {
|
||||
if (of_property_read_u32(np, "nvidia,ram-code", ®))
|
||||
continue;
|
||||
if (reg == tegra_bct_strapping)
|
||||
return of_node_get(iter);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *tnp, *iter;
|
||||
struct tegra_emc_pdata *pdata;
|
||||
int ret, i, num_tables;
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
|
||||
tnp = tegra_emc_ramcode_devnode(np);
|
||||
if (!tnp)
|
||||
dev_warn(&pdev->dev,
|
||||
"can't find emc table for ram-code 0x%02x\n",
|
||||
tegra_bct_strapping);
|
||||
} else
|
||||
tnp = of_node_get(np);
|
||||
|
||||
if (!tnp)
|
||||
return NULL;
|
||||
|
||||
num_tables = 0;
|
||||
for_each_child_of_node(tnp, iter)
|
||||
if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table"))
|
||||
num_tables++;
|
||||
|
||||
if (!num_tables) {
|
||||
pdata = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
pdata->tables = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*pdata->tables) * num_tables,
|
||||
GFP_KERNEL);
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node(tnp, iter) {
|
||||
u32 prop;
|
||||
|
||||
ret = of_property_read_u32(iter, "clock-frequency", &prop);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "no clock-frequency in %s\n",
|
||||
iter->full_name);
|
||||
continue;
|
||||
}
|
||||
pdata->tables[i].rate = prop;
|
||||
|
||||
ret = of_property_read_u32_array(iter, "nvidia,emc-registers",
|
||||
pdata->tables[i].regs,
|
||||
TEGRA_EMC_NUM_REGS);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"malformed emc-registers property in %s\n",
|
||||
iter->full_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
pdata->num_tables = i;
|
||||
|
||||
out:
|
||||
of_node_put(tnp);
|
||||
return pdata;
|
||||
}
|
||||
#else
|
||||
static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *c = clk_get_sys(NULL, "emc");
|
||||
struct tegra_emc_pdata *pdata;
|
||||
unsigned long khz;
|
||||
int i;
|
||||
|
||||
WARN_ON(pdev->dev.platform_data);
|
||||
BUG_ON(IS_ERR_OR_NULL(c));
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables),
|
||||
GFP_KERNEL);
|
||||
|
||||
pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000;
|
||||
|
||||
for (i = 0; i < TEGRA_EMC_NUM_REGS; i++)
|
||||
pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]);
|
||||
|
||||
pdata->num_tables = 1;
|
||||
|
||||
khz = pdata->tables[0].rate;
|
||||
dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, "
|
||||
"%ld kHz mem\n", khz * 2, khz);
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static int __devinit tegra_emc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_emc_pdata *pdata;
|
||||
struct resource *res;
|
||||
|
||||
if (!emc_enable) {
|
||||
dev_err(&pdev->dev, "disabled per module parameter\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "missing register base\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
emc_regbase = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!emc_regbase) {
|
||||
dev_err(&pdev->dev, "failed to remap registers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
|
||||
if (!pdata)
|
||||
pdata = tegra_emc_dt_parse_pdata(pdev);
|
||||
|
||||
if (!pdata)
|
||||
pdata = tegra_emc_fill_pdata(pdev);
|
||||
|
||||
pdev->dev.platform_data = pdata;
|
||||
|
||||
emc_pdev = pdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id tegra_emc_of_match[] __devinitdata = {
|
||||
{ .compatible = "nvidia,tegra20-emc", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver tegra_emc_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-emc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = tegra_emc_of_match,
|
||||
},
|
||||
.probe = tegra_emc_probe,
|
||||
};
|
||||
|
||||
static int __init tegra_emc_init(void)
|
||||
{
|
||||
return platform_driver_register(&tegra_emc_driver);
|
||||
}
|
||||
device_initcall(tegra_emc_init);
|
||||
|
|
|
@ -15,13 +15,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define TEGRA_EMC_NUM_REGS 46
|
||||
|
||||
struct tegra_emc_table {
|
||||
unsigned long rate;
|
||||
u32 regs[TEGRA_EMC_NUM_REGS];
|
||||
};
|
||||
#ifndef __MACH_TEGRA_TEGRA2_EMC_H_
|
||||
#define __MACH_TEGRA_TEGRA2_EMC_H
|
||||
|
||||
int tegra_emc_set_rate(unsigned long rate);
|
||||
long tegra_emc_round_rate(unsigned long rate);
|
||||
void tegra_init_emc(const struct tegra_emc_table *table, int table_size);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
|
@ -74,9 +75,10 @@ struct tegra_gpio_bank {
|
|||
#endif
|
||||
};
|
||||
|
||||
|
||||
static struct irq_domain *irq_domain;
|
||||
static void __iomem *regs;
|
||||
static struct tegra_gpio_bank tegra_gpio_banks[7];
|
||||
static u32 tegra_gpio_bank_count;
|
||||
static struct tegra_gpio_bank *tegra_gpio_banks;
|
||||
|
||||
static inline void tegra_gpio_writel(u32 val, u32 reg)
|
||||
{
|
||||
|
@ -139,7 +141,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
|||
|
||||
static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return TEGRA_GPIO_TO_IRQ(offset);
|
||||
return irq_find_mapping(irq_domain, offset);
|
||||
}
|
||||
|
||||
static struct gpio_chip tegra_gpio_chip = {
|
||||
|
@ -155,28 +157,28 @@ static struct gpio_chip tegra_gpio_chip = {
|
|||
|
||||
static void tegra_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
int gpio = d->irq - INT_GPIO_BASE;
|
||||
int gpio = d->hwirq;
|
||||
|
||||
tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
|
||||
}
|
||||
|
||||
static void tegra_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
int gpio = d->irq - INT_GPIO_BASE;
|
||||
int gpio = d->hwirq;
|
||||
|
||||
tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0);
|
||||
}
|
||||
|
||||
static void tegra_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
int gpio = d->irq - INT_GPIO_BASE;
|
||||
int gpio = d->hwirq;
|
||||
|
||||
tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1);
|
||||
}
|
||||
|
||||
static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
int gpio = d->irq - INT_GPIO_BASE;
|
||||
int gpio = d->hwirq;
|
||||
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||
int port = GPIO_PORT(gpio);
|
||||
int lvl_type;
|
||||
|
@ -273,7 +275,7 @@ void tegra_gpio_resume(void)
|
|||
|
||||
local_irq_save(flags);
|
||||
|
||||
for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
|
||||
for (b = 0; b < tegra_gpio_bank_count; b++) {
|
||||
struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
|
||||
|
||||
for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
|
||||
|
@ -296,7 +298,7 @@ void tegra_gpio_suspend(void)
|
|||
int p;
|
||||
|
||||
local_irq_save(flags);
|
||||
for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
|
||||
for (b = 0; b < tegra_gpio_bank_count; b++) {
|
||||
struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
|
||||
|
||||
for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
|
||||
|
@ -337,13 +339,44 @@ static struct lock_class_key gpio_lock_class;
|
|||
|
||||
static int __devinit tegra_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int irq_base;
|
||||
struct resource *res;
|
||||
struct tegra_gpio_bank *bank;
|
||||
int gpio;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
|
||||
for (;;) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count);
|
||||
if (!res)
|
||||
break;
|
||||
tegra_gpio_bank_count++;
|
||||
}
|
||||
if (!tegra_gpio_bank_count) {
|
||||
dev_err(&pdev->dev, "Missing IRQ resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32;
|
||||
|
||||
tegra_gpio_banks = devm_kzalloc(&pdev->dev,
|
||||
tegra_gpio_bank_count * sizeof(*tegra_gpio_banks),
|
||||
GFP_KERNEL);
|
||||
if (!tegra_gpio_banks) {
|
||||
dev_err(&pdev->dev, "Couldn't allocate bank structure\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
|
||||
tegra_gpio_chip.ngpio, irq_base, 0,
|
||||
&irq_domain_simple_ops, NULL);
|
||||
|
||||
for (i = 0; i < tegra_gpio_bank_count; i++) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Missing IRQ resource\n");
|
||||
|
@ -380,8 +413,8 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
gpiochip_add(&tegra_gpio_chip);
|
||||
|
||||
for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) {
|
||||
int irq = TEGRA_GPIO_TO_IRQ(gpio);
|
||||
for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {
|
||||
int irq = irq_find_mapping(irq_domain, gpio);
|
||||
/* No validity check; all Tegra GPIOs are valid IRQs */
|
||||
|
||||
bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
|
||||
|
@ -393,7 +426,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
|
|||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
|
||||
for (i = 0; i < tegra_gpio_bank_count; i++) {
|
||||
bank = &tegra_gpio_banks[i];
|
||||
|
||||
irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler);
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@android.com>
|
||||
* Olof Johansson <olof@lixom.net>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TEGRA_EMC_H_
|
||||
#define __TEGRA_EMC_H_
|
||||
|
||||
#define TEGRA_EMC_NUM_REGS 46
|
||||
|
||||
struct tegra_emc_table {
|
||||
unsigned long rate;
|
||||
u32 regs[TEGRA_EMC_NUM_REGS];
|
||||
};
|
||||
|
||||
struct tegra_emc_pdata {
|
||||
int num_tables;
|
||||
struct tegra_emc_table *tables;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue