9
0
Fork 0

Merge branch 'for-next/tegra'

This commit is contained in:
Sascha Hauer 2014-11-05 15:47:39 +01:00
commit 7b4cc54579
55 changed files with 4241 additions and 2942 deletions

View File

@ -198,6 +198,7 @@ config ARCH_TEGRA
bool "NVIDIA Tegra"
select CPU_V7
select HAS_DEBUG_LL
select HW_HAS_PCI
select COMMON_CLK
select COMMON_CLK_OF_PROVIDER
select CLKDEV_LOOKUP

View File

@ -15,10 +15,12 @@
*/
#include <common.h>
#include <init.h>
#include <dt-bindings/gpio/tegra-gpio.h>
#include <gpio.h>
#include <i2c/i2c.h>
#include <init.h>
static int nvidia_beaver_devices_init(void)
static int nvidia_beaver_fs_init(void)
{
struct i2c_client client;
u8 data;
@ -33,6 +35,24 @@ static int nvidia_beaver_devices_init(void)
data = 0x65;
i2c_write_reg(&client, 0x32, &data, 1);
/* TPS659110: LDO1_REG = 1.05v, ACTIVE to PEX */
data = 0x15;
i2c_write_reg(&client, 0x30, &data, 1);
/* enable SYS_3V3_PEXS */
gpio_direction_output(TEGRA_GPIO(L, 7), 1);
return 0;
}
device_initcall(nvidia_beaver_devices_init);
fs_initcall(nvidia_beaver_fs_init);
static int nvidia_beaver_device_init(void)
{
if (!of_machine_is_compatible("nvidia,beaver"))
return 0;
barebox_set_hostname("beaver");
return 0;
}
device_initcall(nvidia_beaver_device_init);

View File

@ -3,5 +3,5 @@ CFLAGS_pbl-entry.o := \
-fno-tree-switch-conversion -fno-jump-tables
soc := tegra124
lwl-y += entry.o
#obj-y += board.o
obj-y += board.o
extra-y += jetson-tk1-2gb-emmc.bct

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2014 Lucas Stach <l.stach@pengutronix.de>
*
* 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 <common.h>
#include <dt-bindings/gpio/tegra-gpio.h>
#include <gpio.h>
#include <i2c/i2c.h>
#include <init.h>
#define AS3722_SD_VOLTAGE(n) (0x00 + (n))
#define AS3722_GPIO_CONTROL(n) (0x08 + (n))
#define AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH (1 << 0)
#define AS3722_GPIO_SIGNAL_OUT 0x20
#define AS3722_SD_CONTROL 0x4d
static int nvidia_jetson_tk1_fs_init(void)
{
struct i2c_client client;
u8 data;
if (!of_machine_is_compatible("nvidia,jetson-tk1"))
return 0;
client.adapter = i2c_get_adapter(4);
client.addr = 0x40;
/* AS3722: enable SD4 and set voltage to 1.05v */
i2c_read_reg(&client, AS3722_SD_CONTROL, &data, 1);
data |= 1 << 4;
i2c_write_reg(&client, AS3722_SD_CONTROL, &data, 1);
data = 0x24;
i2c_write_reg(&client, AS3722_SD_VOLTAGE(4), &data, 1);
return 0;
}
fs_initcall(nvidia_jetson_tk1_fs_init);
static int nvidia_jetson_tk1_device_init(void)
{
if (!of_machine_is_compatible("nvidia,jetson-tk1"))
return 0;
barebox_set_hostname("jetson-tk1");
return 0;
}
device_initcall(nvidia_jetson_tk1_device_init);

View File

@ -3,6 +3,7 @@ CFLAGS_pbl-entry.o := \
-fno-tree-switch-conversion -fno-jump-tables
soc := tegra20
lwl-y += entry.o
obj-y += board.o
extra-y += colibri-t20_256_hsmmc.bct colibri-t20_256_v11_nand.bct \
colibri-t20_256_v12_nand.bct colibri-t20_512_hsmmc.bct \
colibri-t20_512_v11_nand.bct colibri-t20_512_v12_nand.bct

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2014 Lucas Stach <l.stach@pengutronix.de>
*
* 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 <common.h>
#include <init.h>
static int toradex_colibri_t20_device_init(void)
{
if (!of_machine_is_compatible("toradex,colibri_t20-512"))
return 0;
barebox_set_hostname("colibri-t20");
return 0;
}
device_initcall(toradex_colibri_t20_device_init);

View File

@ -16,6 +16,7 @@ CONFIG_AUTO_COMPLETE=y
CONFIG_MENU=y
CONFIG_BLSPEC=y
CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
CONFIG_RESET_SOURCE=y
CONFIG_LONGHELP=y
CONFIG_CMD_IOMEM=y
CONFIG_CMD_MEMINFO=y
@ -27,16 +28,25 @@ CONFIG_CMD_RESET=y
CONFIG_CMD_EXPORT=y
CONFIG_CMD_LOADENV=y
CONFIG_CMD_SAVEENV=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_MIITOOL=y
CONFIG_CMD_PING=y
CONFIG_CMD_EDIT=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_CLK=y
CONFIG_CMD_DETECT=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_OFTREE=y
CONFIG_NET=y
CONFIG_OF_BAREBOX_DRIVERS=y
CONFIG_DRIVER_SERIAL_NS16550=y
CONFIG_DRIVER_NET_RTL8169=y
CONFIG_MCI=y
CONFIG_MCI_MMC_BOOT_PARTITIONS=y
CONFIG_MCI_TEGRA=y
CONFIG_PCI_TEGRA=y
CONFIG_FS_EXT4=y
CONFIG_FS_TFTP=y
CONFIG_FS_NFS=y
CONFIG_FS_FAT=y
CONFIG_FS_FAT_LFN=y

File diff suppressed because it is too large Load Diff

View File

@ -1 +1,8 @@
#include <arm/tegra124.dtsi>
/ {
aliases {
serial0 = "/serial@0,70006000/";
serial1 = "/serial@0,70006040/";
serial2 = "/serial@0,70006200/";
serial3 = "/serial@0,70006300/";
};
};

View File

@ -6,6 +6,10 @@
model = "Toradex Colibri T20 on Iris";
compatible = "toradex,iris", "toradex,colibri_t20", "nvidia,tegra20";
chosen {
stdout-path = &uarta;
};
host1x@50000000 {
hdmi@54280000 {
status = "okay";

View File

@ -1,6 +1,6 @@
/dts-v1/;
#include "tegra30.dtsi"
#include <arm/tegra30.dtsi>
/ {
model = "NVIDIA Tegra30 Beaver evaluation board";
@ -11,6 +11,15 @@
rtc1 = "/rtc@7000e000";
};
chosen {
stdout-path = &uarta;
environment@0 {
compatible = "barebox,environment";
device-path = &emmc, "partname:boot1";
};
};
memory {
reg = <0x80000000 0x7ff00000>;
};
@ -750,7 +759,7 @@
bus-width = <4>;
};
sdhci@78000600 {
emmc: sdhci@78000600 {
status = "okay";
bus-width = <8>;
non-removable;

View File

@ -1,892 +0,0 @@
#include <dt-bindings/clock/tegra30-car.h>
#include <dt-bindings/gpio/tegra-gpio.h>
#include <dt-bindings/pinctrl/pinctrl-tegra.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "skeleton.dtsi"
/ {
compatible = "nvidia,tegra30";
interrupt-parent = <&intc>;
aliases {
serial0 = &uarta;
serial1 = &uartb;
serial2 = &uartc;
serial3 = &uartd;
serial4 = &uarte;
};
pcie-controller@00003000 {
compatible = "nvidia,tegra30-pcie";
device_type = "pci";
reg = <0x00003000 0x00000800 /* PADS registers */
0x00003800 0x00000200 /* AFI registers */
0x10000000 0x10000000>; /* configuration space */
reg-names = "pads", "afi", "cs";
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH /* controller interrupt */
GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */
interrupt-names = "intr", "msi";
bus-range = <0x00 0xff>;
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x82000000 0 0x00000000 0x00000000 0 0x00001000 /* port 0 configuration space */
0x82000000 0 0x00001000 0x00001000 0 0x00001000 /* port 1 configuration space */
0x82000000 0 0x00004000 0x00004000 0 0x00001000 /* port 2 configuration space */
0x81000000 0 0 0x02000000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x20000000 0x20000000 0 0x08000000 /* non-prefetchable memory */
0xc2000000 0 0x28000000 0x28000000 0 0x18000000>; /* prefetchable memory */
clocks = <&tegra_car TEGRA30_CLK_PCIE>,
<&tegra_car TEGRA30_CLK_AFI>,
<&tegra_car TEGRA30_CLK_PLL_E>,
<&tegra_car TEGRA30_CLK_CML0>;
clock-names = "pex", "afi", "pll_e", "cml";
resets = <&tegra_car 70>,
<&tegra_car 72>,
<&tegra_car 74>;
reset-names = "pex", "afi", "pcie_x";
status = "disabled";
pci@1,0 {
device_type = "pci";
assigned-addresses = <0x82000800 0 0x00000000 0 0x1000>;
reg = <0x000800 0 0 0 0>;
status = "disabled";
#address-cells = <3>;
#size-cells = <2>;
ranges;
nvidia,num-lanes = <2>;
};
pci@2,0 {
device_type = "pci";
assigned-addresses = <0x82001000 0 0x00001000 0 0x1000>;
reg = <0x001000 0 0 0 0>;
status = "disabled";
#address-cells = <3>;
#size-cells = <2>;
ranges;
nvidia,num-lanes = <2>;
};
pci@3,0 {
device_type = "pci";
assigned-addresses = <0x82001800 0 0x00004000 0 0x1000>;
reg = <0x001800 0 0 0 0>;
status = "disabled";
#address-cells = <3>;
#size-cells = <2>;
ranges;
nvidia,num-lanes = <2>;
};
};
host1x@50000000 {
compatible = "nvidia,tegra30-host1x", "simple-bus";
reg = <0x50000000 0x00024000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */
clocks = <&tegra_car TEGRA30_CLK_HOST1X>;
resets = <&tegra_car 28>;
reset-names = "host1x";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x54000000 0x54000000 0x04000000>;
mpe@54040000 {
compatible = "nvidia,tegra30-mpe";
reg = <0x54040000 0x00040000>;
interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_MPE>;
resets = <&tegra_car 60>;
reset-names = "mpe";
};
vi@54080000 {
compatible = "nvidia,tegra30-vi";
reg = <0x54080000 0x00040000>;
interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_VI>;
resets = <&tegra_car 20>;
reset-names = "vi";
};
epp@540c0000 {
compatible = "nvidia,tegra30-epp";
reg = <0x540c0000 0x00040000>;
interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_EPP>;
resets = <&tegra_car 19>;
reset-names = "epp";
};
isp@54100000 {
compatible = "nvidia,tegra30-isp";
reg = <0x54100000 0x00040000>;
interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_ISP>;
resets = <&tegra_car 23>;
reset-names = "isp";
};
gr2d@54140000 {
compatible = "nvidia,tegra30-gr2d";
reg = <0x54140000 0x00040000>;
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
resets = <&tegra_car 21>;
reset-names = "2d";
clocks = <&tegra_car TEGRA30_CLK_GR2D>;
};
gr3d@54180000 {
compatible = "nvidia,tegra30-gr3d";
reg = <0x54180000 0x00040000>;
clocks = <&tegra_car TEGRA30_CLK_GR3D
&tegra_car TEGRA30_CLK_GR3D2>;
clock-names = "3d", "3d2";
resets = <&tegra_car 24>,
<&tegra_car 98>;
reset-names = "3d", "3d2";
};
dc@54200000 {
compatible = "nvidia,tegra30-dc", "nvidia,tegra20-dc";
reg = <0x54200000 0x00040000>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_DISP1>,
<&tegra_car TEGRA30_CLK_PLL_P>;
clock-names = "dc", "parent";
resets = <&tegra_car 27>;
reset-names = "dc";
nvidia,head = <0>;
rgb {
status = "disabled";
};
};
dc@54240000 {
compatible = "nvidia,tegra30-dc";
reg = <0x54240000 0x00040000>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_DISP2>,
<&tegra_car TEGRA30_CLK_PLL_P>;
clock-names = "dc", "parent";
resets = <&tegra_car 26>;
reset-names = "dc";
nvidia,head = <1>;
rgb {
status = "disabled";
};
};
hdmi@54280000 {
compatible = "nvidia,tegra30-hdmi";
reg = <0x54280000 0x00040000>;
interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_HDMI>,
<&tegra_car TEGRA30_CLK_PLL_D2_OUT0>;
clock-names = "hdmi", "parent";
resets = <&tegra_car 51>;
reset-names = "hdmi";
status = "disabled";
};
tvo@542c0000 {
compatible = "nvidia,tegra30-tvo";
reg = <0x542c0000 0x00040000>;
interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_TVO>;
status = "disabled";
};
dsi@54300000 {
compatible = "nvidia,tegra30-dsi";
reg = <0x54300000 0x00040000>;
clocks = <&tegra_car TEGRA30_CLK_DSIA>;
resets = <&tegra_car 48>;
reset-names = "dsi";
status = "disabled";
};
};
timer@50004600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0x50040600 0x20>;
interrupts = <GIC_PPI 13
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
clocks = <&tegra_car TEGRA30_CLK_TWD>;
};
intc: interrupt-controller@50041000 {
compatible = "arm,cortex-a9-gic";
reg = <0x50041000 0x1000
0x50040100 0x0100>;
interrupt-controller;
#interrupt-cells = <3>;
};
cache-controller@50043000 {
compatible = "arm,pl310-cache";
reg = <0x50043000 0x1000>;
arm,data-latency = <6 6 2>;
arm,tag-latency = <5 5 2>;
cache-unified;
cache-level = <2>;
};
timer@60005000 {
compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer";
reg = <0x60005000 0x400>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_TIMER>;
};
tegra_car: clock@60006000 {
compatible = "nvidia,tegra30-car";
reg = <0x60006000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};
apbdma: dma@6000a000 {
compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma";
reg = <0x6000a000 0x1400>;
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_APBDMA>;
resets = <&tegra_car 34>;
reset-names = "dma";
#dma-cells = <1>;
};
ahb: ahb@6000c004 {
compatible = "nvidia,tegra30-ahb";
reg = <0x6000c004 0x14c>; /* AHB Arbitration + Gizmo Controller */
};
gpio: gpio@6000d000 {
compatible = "nvidia,tegra30-gpio";
reg = <0x6000d000 0x1000>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
#gpio-cells = <2>;
gpio-controller;
#interrupt-cells = <2>;
interrupt-controller;
};
pinmux: pinmux@70000868 {
compatible = "nvidia,tegra30-pinmux";
reg = <0x70000868 0xd4 /* Pad control registers */
0x70003000 0x3e4>; /* Mux registers */
};
/*
* There are two serial driver i.e. 8250 based simple serial
* driver and APB DMA based serial driver for higher baudrate
* and performace. To enable the 8250 based driver, the compatible
* is "nvidia,tegra30-uart", "nvidia,tegra20-uart" and to enable
* the APB DMA based serial driver, the comptible is
* "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart".
*/
uarta: serial@70006000 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006000 0x40>;
reg-shift = <2>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_UARTA>;
resets = <&tegra_car 6>;
reset-names = "serial";
dmas = <&apbdma 8>, <&apbdma 8>;
dma-names = "rx", "tx";
status = "disabled";
};
uartb: serial@70006040 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006040 0x40>;
reg-shift = <2>;
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_UARTB>;
resets = <&tegra_car 7>;
reset-names = "serial";
dmas = <&apbdma 9>, <&apbdma 9>;
dma-names = "rx", "tx";
status = "disabled";
};
uartc: serial@70006200 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006200 0x100>;
reg-shift = <2>;
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_UARTC>;
resets = <&tegra_car 55>;
reset-names = "serial";
dmas = <&apbdma 10>, <&apbdma 10>;
dma-names = "rx", "tx";
status = "disabled";
};
uartd: serial@70006300 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006300 0x100>;
reg-shift = <2>;
interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_UARTD>;
resets = <&tegra_car 65>;
reset-names = "serial";
dmas = <&apbdma 19>, <&apbdma 19>;
dma-names = "rx", "tx";
status = "disabled";
};
uarte: serial@70006400 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006400 0x100>;
reg-shift = <2>;
interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_UARTE>;
resets = <&tegra_car 66>;
reset-names = "serial";
dmas = <&apbdma 20>, <&apbdma 20>;
dma-names = "rx", "tx";
status = "disabled";
};
pwm: pwm@7000a000 {
compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";
reg = <0x7000a000 0x100>;
#pwm-cells = <2>;
clocks = <&tegra_car TEGRA30_CLK_PWM>;
resets = <&tegra_car 17>;
reset-names = "pwm";
status = "disabled";
};
rtc@7000e000 {
compatible = "nvidia,tegra30-rtc", "nvidia,tegra20-rtc";
reg = <0x7000e000 0x100>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_RTC>;
};
i2c@7000c000 {
compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
reg = <0x7000c000 0x100>;
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_I2C1>,
<&tegra_car TEGRA30_CLK_PLL_P_OUT3>;
clock-names = "div-clk", "fast-clk";
resets = <&tegra_car 12>;
reset-names = "i2c";
dmas = <&apbdma 21>, <&apbdma 21>;
dma-names = "rx", "tx";
status = "disabled";
};
i2c@7000c400 {
compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
reg = <0x7000c400 0x100>;
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_I2C2>,
<&tegra_car TEGRA30_CLK_PLL_P_OUT3>;
clock-names = "div-clk", "fast-clk";
resets = <&tegra_car 54>;
reset-names = "i2c";
dmas = <&apbdma 22>, <&apbdma 22>;
dma-names = "rx", "tx";
status = "disabled";
};
i2c@7000c500 {
compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
reg = <0x7000c500 0x100>;
interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_I2C3>,
<&tegra_car TEGRA30_CLK_PLL_P_OUT3>;
clock-names = "div-clk", "fast-clk";
resets = <&tegra_car 67>;
reset-names = "i2c";
dmas = <&apbdma 23>, <&apbdma 23>;
dma-names = "rx", "tx";
status = "disabled";
};
i2c@7000c700 {
compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
reg = <0x7000c700 0x100>;
interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_I2C4>,
<&tegra_car TEGRA30_CLK_PLL_P_OUT3>;
resets = <&tegra_car 103>;
reset-names = "i2c";
clock-names = "div-clk", "fast-clk";
dmas = <&apbdma 26>, <&apbdma 26>;
dma-names = "rx", "tx";
status = "disabled";
};
i2c@7000d000 {
compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
reg = <0x7000d000 0x100>;
interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_I2C5>,
<&tegra_car TEGRA30_CLK_PLL_P_OUT3>;
clock-names = "div-clk", "fast-clk";
resets = <&tegra_car 47>;
reset-names = "i2c";
dmas = <&apbdma 24>, <&apbdma 24>;
dma-names = "rx", "tx";
status = "disabled";
};
spi@7000d400 {
compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink";
reg = <0x7000d400 0x200>;
interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_SBC1>;
resets = <&tegra_car 41>;
reset-names = "spi";
dmas = <&apbdma 15>, <&apbdma 15>;
dma-names = "rx", "tx";
status = "disabled";
};
spi@7000d600 {
compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink";
reg = <0x7000d600 0x200>;
interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_SBC2>;
resets = <&tegra_car 44>;
reset-names = "spi";
dmas = <&apbdma 16>, <&apbdma 16>;
dma-names = "rx", "tx";
status = "disabled";
};
spi@7000d800 {
compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink";
reg = <0x7000d800 0x200>;
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_SBC3>;
resets = <&tegra_car 46>;
reset-names = "spi";
dmas = <&apbdma 17>, <&apbdma 17>;
dma-names = "rx", "tx";
status = "disabled";
};
spi@7000da00 {
compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink";
reg = <0x7000da00 0x200>;
interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_SBC4>;
resets = <&tegra_car 68>;
reset-names = "spi";
dmas = <&apbdma 18>, <&apbdma 18>;
dma-names = "rx", "tx";
status = "disabled";
};
spi@7000dc00 {
compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink";
reg = <0x7000dc00 0x200>;
interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_SBC5>;
resets = <&tegra_car 104>;
reset-names = "spi";
dmas = <&apbdma 27>, <&apbdma 27>;
dma-names = "rx", "tx";
status = "disabled";
};
spi@7000de00 {
compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink";
reg = <0x7000de00 0x200>;
interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA30_CLK_SBC6>;
resets = <&tegra_car 106>;
reset-names = "spi";
dmas = <&apbdma 28>, <&apbdma 28>;
dma-names = "rx", "tx";
status = "disabled";
};
kbc@7000e200 {
compatible = "nvidia,tegra30-kbc", "nvidia,tegra20-kbc";
reg = <0x7000e200 0x100>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_KBC>;
resets = <&tegra_car 36>;
reset-names = "kbc";
status = "disabled";
};
pmc@7000e400 {
compatible = "nvidia,tegra30-pmc";
reg = <0x7000e400 0x400>;
clocks = <&tegra_car TEGRA30_CLK_PCLK>, <&clk32k_in>;
clock-names = "pclk", "clk32k_in";
};
memory-controller@7000f000 {
compatible = "nvidia,tegra30-mc";
reg = <0x7000f000 0x010
0x7000f03c 0x1b4
0x7000f200 0x028
0x7000f284 0x17c>;
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
};
iommu@7000f010 {
compatible = "nvidia,tegra30-smmu";
reg = <0x7000f010 0x02c
0x7000f1f0 0x010
0x7000f228 0x05c>;
nvidia,#asids = <4>; /* # of ASIDs */
dma-window = <0 0x40000000>; /* IOVA start & length */
nvidia,ahb = <&ahb>;
};
ahub@70080000 {
compatible = "nvidia,tegra30-ahub";
reg = <0x70080000 0x200
0x70080200 0x100>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_D_AUDIO>,
<&tegra_car TEGRA30_CLK_APBIF>;
clock-names = "d_audio", "apbif";
resets = <&tegra_car 106>, /* d_audio */
<&tegra_car 107>, /* apbif */
<&tegra_car 30>, /* i2s0 */
<&tegra_car 11>, /* i2s1 */
<&tegra_car 18>, /* i2s2 */
<&tegra_car 101>, /* i2s3 */
<&tegra_car 102>, /* i2s4 */
<&tegra_car 108>, /* dam0 */
<&tegra_car 109>, /* dam1 */
<&tegra_car 110>, /* dam2 */
<&tegra_car 10>; /* spdif */
reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
"i2s3", "i2s4", "dam0", "dam1", "dam2",
"spdif";
dmas = <&apbdma 1>, <&apbdma 1>,
<&apbdma 2>, <&apbdma 2>,
<&apbdma 3>, <&apbdma 3>,
<&apbdma 4>, <&apbdma 4>;
dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2",
"rx3", "tx3";
ranges;
#address-cells = <1>;
#size-cells = <1>;
tegra_i2s0: i2s@70080300 {
compatible = "nvidia,tegra30-i2s";
reg = <0x70080300 0x100>;
nvidia,ahub-cif-ids = <4 4>;
clocks = <&tegra_car TEGRA30_CLK_I2S0>;
resets = <&tegra_car 30>;
reset-names = "i2s";
status = "disabled";
};
tegra_i2s1: i2s@70080400 {
compatible = "nvidia,tegra30-i2s";
reg = <0x70080400 0x100>;
nvidia,ahub-cif-ids = <5 5>;
clocks = <&tegra_car TEGRA30_CLK_I2S1>;
resets = <&tegra_car 11>;
reset-names = "i2s";
status = "disabled";
};
tegra_i2s2: i2s@70080500 {
compatible = "nvidia,tegra30-i2s";
reg = <0x70080500 0x100>;
nvidia,ahub-cif-ids = <6 6>;
clocks = <&tegra_car TEGRA30_CLK_I2S2>;
resets = <&tegra_car 18>;
reset-names = "i2s";
status = "disabled";
};
tegra_i2s3: i2s@70080600 {
compatible = "nvidia,tegra30-i2s";
reg = <0x70080600 0x100>;
nvidia,ahub-cif-ids = <7 7>;
clocks = <&tegra_car TEGRA30_CLK_I2S3>;
resets = <&tegra_car 101>;
reset-names = "i2s";
status = "disabled";
};
tegra_i2s4: i2s@70080700 {
compatible = "nvidia,tegra30-i2s";
reg = <0x70080700 0x100>;
nvidia,ahub-cif-ids = <8 8>;
clocks = <&tegra_car TEGRA30_CLK_I2S4>;
resets = <&tegra_car 102>;
reset-names = "i2s";
status = "disabled";
};
};
sdhci@78000000 {
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
reg = <0x78000000 0x200>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_SDMMC1>;
resets = <&tegra_car 14>;
reset-names = "sdhci";
status = "disabled";
};
sdhci@78000200 {
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
reg = <0x78000200 0x200>;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_SDMMC2>;
resets = <&tegra_car 9>;
reset-names = "sdhci";
status = "disabled";
};
sdhci@78000400 {
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
reg = <0x78000400 0x200>;
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_SDMMC3>;
resets = <&tegra_car 69>;
reset-names = "sdhci";
status = "disabled";
};
sdhci@78000600 {
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
reg = <0x78000600 0x200>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_SDMMC4>;
resets = <&tegra_car 15>;
reset-names = "sdhci";
status = "disabled";
};
usb@7d000000 {
compatible = "nvidia,tegra30-ehci", "usb-ehci";
reg = <0x7d000000 0x4000>;
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
phy_type = "utmi";
clocks = <&tegra_car TEGRA30_CLK_USBD>;
resets = <&tegra_car 22>;
reset-names = "usb";
nvidia,needs-double-reset;
nvidia,phy = <&phy1>;
status = "disabled";
};
phy1: usb-phy@7d000000 {
compatible = "nvidia,tegra30-usb-phy";
reg = <0x7d000000 0x4000 0x7d000000 0x4000>;
phy_type = "utmi";
clocks = <&tegra_car TEGRA30_CLK_USBD>,
<&tegra_car TEGRA30_CLK_PLL_U>,
<&tegra_car TEGRA30_CLK_USBD>;
clock-names = "reg", "pll_u", "utmi-pads";
nvidia,hssync-start-delay = <9>;
nvidia,idle-wait-delay = <17>;
nvidia,elastic-limit = <16>;
nvidia,term-range-adj = <6>;
nvidia,xcvr-setup = <51>;
nvidia.xcvr-setup-use-fuses;
nvidia,xcvr-lsfslew = <1>;
nvidia,xcvr-lsrslew = <1>;
nvidia,xcvr-hsslew = <32>;
nvidia,hssquelch-level = <2>;
nvidia,hsdiscon-level = <5>;
status = "disabled";
};
usb@7d004000 {
compatible = "nvidia,tegra30-ehci", "usb-ehci";
reg = <0x7d004000 0x4000>;
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
phy_type = "utmi";
clocks = <&tegra_car TEGRA30_CLK_USB2>;
resets = <&tegra_car 58>;
reset-names = "usb";
nvidia,phy = <&phy2>;
status = "disabled";
};
phy2: usb-phy@7d004000 {
compatible = "nvidia,tegra30-usb-phy";
reg = <0x7d004000 0x4000 0x7d000000 0x4000>;
phy_type = "utmi";
clocks = <&tegra_car TEGRA30_CLK_USB2>,
<&tegra_car TEGRA30_CLK_PLL_U>,
<&tegra_car TEGRA30_CLK_USBD>;
clock-names = "reg", "pll_u", "utmi-pads";
nvidia,hssync-start-delay = <9>;
nvidia,idle-wait-delay = <17>;
nvidia,elastic-limit = <16>;
nvidia,term-range-adj = <6>;
nvidia,xcvr-setup = <51>;
nvidia.xcvr-setup-use-fuses;
nvidia,xcvr-lsfslew = <2>;
nvidia,xcvr-lsrslew = <2>;
nvidia,xcvr-hsslew = <32>;
nvidia,hssquelch-level = <2>;
nvidia,hsdiscon-level = <5>;
status = "disabled";
};
usb@7d008000 {
compatible = "nvidia,tegra30-ehci", "usb-ehci";
reg = <0x7d008000 0x4000>;
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
phy_type = "utmi";
clocks = <&tegra_car TEGRA30_CLK_USB3>;
resets = <&tegra_car 59>;
reset-names = "usb";
nvidia,phy = <&phy3>;
status = "disabled";
};
phy3: usb-phy@7d008000 {
compatible = "nvidia,tegra30-usb-phy";
reg = <0x7d008000 0x4000 0x7d000000 0x4000>;
phy_type = "utmi";
clocks = <&tegra_car TEGRA30_CLK_USB3>,
<&tegra_car TEGRA30_CLK_PLL_U>,
<&tegra_car TEGRA30_CLK_USBD>;
clock-names = "reg", "pll_u", "utmi-pads";
nvidia,hssync-start-delay = <0>;
nvidia,idle-wait-delay = <17>;
nvidia,elastic-limit = <16>;
nvidia,term-range-adj = <6>;
nvidia,xcvr-setup = <51>;
nvidia.xcvr-setup-use-fuses;
nvidia,xcvr-lsfslew = <2>;
nvidia,xcvr-lsrslew = <2>;
nvidia,xcvr-hsslew = <32>;
nvidia,hssquelch-level = <2>;
nvidia,hsdiscon-level = <5>;
status = "disabled";
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
};
cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
};
cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <2>;
};
cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <3>;
};
};
pmu {
compatible = "arm,cortex-a9-pmu";
interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
};
};

View File

@ -7,39 +7,6 @@ config ARCH_TEXT_BASE
config BOARDINFO
default ""
choice
prompt "Tegra debug UART"
help
This is the first serial console that gets activated by barebox.
Normally each board vendor should program a valid debug UART into
the ODMdata section of the boot configuration table, so it's a
reasonably good bet to use that.
If you know your ODMdata is broken, or you don't wish to activate
any serial console at all you can override the default here.
config TEGRA_UART_ODMDATA
bool "ODMdata defined UART"
config TEGRA_UART_A
bool "UART A"
config TEGRA_UART_B
bool "UART B"
config TEGRA_UART_C
bool "UART C"
config TEGRA_UART_D
bool "UART D"
config TEGRA_UART_E
bool "UART E"
config TEGRA_UART_NONE
bool "None"
endchoice
# ---------------------------------------------------------
config ARCH_TEGRA_2x_SOC
@ -70,6 +37,8 @@ config MACH_NVIDIA_BEAVER
config MACH_NVIDIA_JETSON
bool "NVIDIA Jetson TK1"
select ARCH_TEGRA_124_SOC
select I2C
select I2C_TEGRA
endmenu

View File

@ -176,37 +176,6 @@ uint32_t tegra30_get_ramsize(void)
}
}
static long uart_id_to_base[] = {
TEGRA_UARTA_BASE,
TEGRA_UARTB_BASE,
TEGRA_UARTC_BASE,
TEGRA_UARTD_BASE,
TEGRA_UARTE_BASE,
};
static __always_inline
long tegra20_get_debuguart_base(void)
{
u32 odmdata;
int id;
odmdata = tegra_get_odmdata();
/*
* Get type, we accept both "2" and "3", as they both demark a UART,
* depending on the board type.
*/
if (!(((odmdata & T20_ODMDATA_UARTTYPE_MASK) >>
T20_ODMDATA_UARTTYPE_SHIFT) & 0x2))
return 0;
id = (odmdata & T20_ODMDATA_UARTID_MASK) >> T20_ODMDATA_UARTID_SHIFT;
if (id > ARRAY_SIZE(uart_id_to_base))
return 0;
return uart_id_to_base[id];
}
#define CRC_OSC_CTRL 0x050
#define CRC_OSC_CTRL_OSC_FREQ_SHIFT 30
#define CRC_OSC_CTRL_OSC_FREQ_MASK (0x3 << CRC_OSC_CTRL_OSC_FREQ_SHIFT)
@ -231,20 +200,6 @@ int tegra_get_osc_clock(void)
}
}
static __always_inline
int tegra_get_pllp_rate(void)
{
switch (tegra_get_chiptype()) {
case TEGRA20:
return 216000000;
case TEGRA30:
case TEGRA124:
return 408000000;
default:
return 0;
}
}
#define TIMER_CNTR_1US 0x00
#define TIMER_USEC_CFG 0x04

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2010 Google, Inc
*
* Author:
* Colin Cross <ccross@google.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _MACH_TEGRA_POWERGATE_H_
#define _MACH_TEGRA_POWERGATE_H_
struct clk;
struct reset_control;
#define TEGRA_POWERGATE_CPU 0
#define TEGRA_POWERGATE_3D 1
#define TEGRA_POWERGATE_VENC 2
#define TEGRA_POWERGATE_PCIE 3
#define TEGRA_POWERGATE_VDEC 4
#define TEGRA_POWERGATE_L2 5
#define TEGRA_POWERGATE_MPE 6
#define TEGRA_POWERGATE_HEG 7
#define TEGRA_POWERGATE_SATA 8
#define TEGRA_POWERGATE_CPU1 9
#define TEGRA_POWERGATE_CPU2 10
#define TEGRA_POWERGATE_CPU3 11
#define TEGRA_POWERGATE_CELP 12
#define TEGRA_POWERGATE_3D1 13
#define TEGRA_POWERGATE_CPU0 14
#define TEGRA_POWERGATE_C0NC 15
#define TEGRA_POWERGATE_C1NC 16
#define TEGRA_POWERGATE_SOR 17
#define TEGRA_POWERGATE_DIS 18
#define TEGRA_POWERGATE_DISB 19
#define TEGRA_POWERGATE_XUSBA 20
#define TEGRA_POWERGATE_XUSBB 21
#define TEGRA_POWERGATE_XUSBC 22
#define TEGRA_POWERGATE_VIC 23
#define TEGRA_POWERGATE_IRAM 24
#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D
#define TEGRA_IO_RAIL_CSIA 0
#define TEGRA_IO_RAIL_CSIB 1
#define TEGRA_IO_RAIL_DSI 2
#define TEGRA_IO_RAIL_MIPI_BIAS 3
#define TEGRA_IO_RAIL_PEX_BIAS 4
#define TEGRA_IO_RAIL_PEX_CLK1 5
#define TEGRA_IO_RAIL_PEX_CLK2 6
#define TEGRA_IO_RAIL_USB0 9
#define TEGRA_IO_RAIL_USB1 10
#define TEGRA_IO_RAIL_USB2 11
#define TEGRA_IO_RAIL_USB_BIAS 12
#define TEGRA_IO_RAIL_NAND 13
#define TEGRA_IO_RAIL_UART 14
#define TEGRA_IO_RAIL_BB 15
#define TEGRA_IO_RAIL_AUDIO 17
#define TEGRA_IO_RAIL_HSIC 19
#define TEGRA_IO_RAIL_COMP 22
#define TEGRA_IO_RAIL_HDMI 28
#define TEGRA_IO_RAIL_PEX_CNTRL 32
#define TEGRA_IO_RAIL_SDMMC1 33
#define TEGRA_IO_RAIL_SDMMC3 34
#define TEGRA_IO_RAIL_SDMMC4 35
#define TEGRA_IO_RAIL_CAM 36
#define TEGRA_IO_RAIL_RES 37
#define TEGRA_IO_RAIL_HV 38
#define TEGRA_IO_RAIL_DSIB 39
#define TEGRA_IO_RAIL_DSIC 40
#define TEGRA_IO_RAIL_DSID 41
#define TEGRA_IO_RAIL_CSIE 44
#define TEGRA_IO_RAIL_LVDS 57
#define TEGRA_IO_RAIL_SYS_DDC 58
int tegra_powergate_is_powered(int id);
int tegra_powergate_power_on(int id);
int tegra_powergate_power_off(int id);
int tegra_powergate_remove_clamping(int id);
/* Must be called with clk disabled, and returns with clk enabled */
int tegra_powergate_sequence_power_up(int id, struct clk *clk,
struct reset_control *rst);
#endif /* _MACH_TEGRA_POWERGATE_H_ */

View File

@ -49,6 +49,8 @@
#define CRC_CLK_OUT_ENB_H 0x014
#define CRC_CLK_OUT_ENB_H_DVC (1 << 15)
#define CRC_CLK_OUT_ENB_U 0x018
#define CRC_CCLK_BURST_POLICY 0x020
#define CRC_CCLK_BURST_POLICY_SYS_STATE_SHIFT 28
#define CRC_CCLK_BURST_POLICY_SYS_STATE_FIQ 8

View File

@ -71,3 +71,12 @@
#define PMC_PARTID_C0NC 15
#define PMC_SCRATCH(i) (0x050 + 0x4*i)
#define PMC_RST_STATUS 0x1b4
#define PMC_RST_STATUS_RST_SRC_SHIFT 0
#define PMC_RST_STATUS_RST_SRC_MASK (0x7 << PMC_RST_STATUS_RST_SRC_SHIFT)
#define PMC_RST_STATUS_RST_SRC_POR 0
#define PMC_RST_STATUS_RST_SRC_WATCHDOG 1
#define PMC_RST_STATUS_RST_SRC_SENSOR 2
#define PMC_RST_STATUS_RST_SRC_SW_MAIN 3
#define PMC_RST_STATUS_RST_SRC_LP0 4

View File

@ -33,3 +33,5 @@
#define CRC_RST_DEV_V_CLR 0x434
#define CRC_CLK_OUT_ENB_V_SET 0x440
#define CRC_PLLE_AUX 0x48c

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Lucas Stach <l.stach@pengutronix.de>
* Copyright (C) 2013-2014 Lucas Stach <l.stach@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -19,15 +19,21 @@
* @brief Device driver for the Tegra 20 power management controller.
*/
#include <common.h>
#include <command.h>
#include <common.h>
#include <init.h>
#include <io.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <mach/lowlevel.h>
#include <mach/tegra-powergate.h>
#include <reset_source.h>
#include <mach/tegra20-pmc.h>
static void __iomem *pmc_base;
static int tegra_num_powerdomains;
/* main SoC reset trigger */
void __noreturn reset_cpu(ulong addr)
@ -38,6 +44,162 @@ void __noreturn reset_cpu(ulong addr)
}
EXPORT_SYMBOL(reset_cpu);
static int tegra_powergate_set(int id, bool new_state)
{
bool status;
status = readl(pmc_base + PMC_PWRGATE_STATUS) & (1 << id);
if (status == new_state) {
return 0;
}
writel(PMC_PWRGATE_TOGGLE_START | id, pmc_base + PMC_PWRGATE_TOGGLE);
/* I don't know exactly why this is needed, seems to flush the write */
readl(pmc_base + PMC_PWRGATE_TOGGLE);
return 0;
}
int tegra_powergate_power_on(int id)
{
if (id < 0 || id >= tegra_num_powerdomains)
return -EINVAL;
return tegra_powergate_set(id, true);
}
int tegra_powergate_power_off(int id)
{
if (id < 0 || id >= tegra_num_powerdomains)
return -EINVAL;
return tegra_powergate_set(id, false);
}
EXPORT_SYMBOL(tegra_powergate_power_off);
int tegra_powergate_is_powered(int id)
{
u32 status;
if (id < 0 || id >= tegra_num_powerdomains)
return -EINVAL;
status = readl(pmc_base + PMC_PWRGATE_STATUS) & (1 << id);
return !!status;
}
int tegra_powergate_remove_clamping(int id)
{
u32 mask;
if (id < 0 || id >= tegra_num_powerdomains)
return -EINVAL;
/*
* Tegra 2 has a bug where PCIE and VDE clamping masks are
* swapped relatively to the partition ids
*/
if (id == TEGRA_POWERGATE_VDEC)
mask = (1 << TEGRA_POWERGATE_PCIE);
else if (id == TEGRA_POWERGATE_PCIE)
mask = (1 << TEGRA_POWERGATE_VDEC);
else
mask = (1 << id);
writel(mask, pmc_base + PMC_REMOVE_CLAMPING_CMD);
return 0;
}
EXPORT_SYMBOL(tegra_powergate_remove_clamping);
/* Must be called with clk disabled, and returns with clk enabled */
int tegra_powergate_sequence_power_up(int id, struct clk *clk,
struct reset_control *rst)
{
int ret;
reset_control_assert(rst);
ret = tegra_powergate_power_on(id);
if (ret)
goto err_power;
ret = clk_enable(clk);
if (ret)
goto err_clk;
udelay(10);
ret = tegra_powergate_remove_clamping(id);
if (ret)
goto err_clamp;
udelay(10);
reset_control_deassert(rst);
return 0;
err_clamp:
clk_disable(clk);
err_clk:
tegra_powergate_power_off(id);
err_power:
return ret;
}
EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
static int tegra_powergate_init(void)
{
switch (tegra_get_chiptype()) {
case TEGRA20:
tegra_num_powerdomains = 7;
break;
case TEGRA30:
tegra_num_powerdomains = 14;
break;
case TEGRA114:
tegra_num_powerdomains = 23;
break;
case TEGRA124:
tegra_num_powerdomains = 25;
break;
default:
/* Unknown Tegra variant. Disable powergating */
tegra_num_powerdomains = 0;
break;
}
return 0;
}
static void tegra20_pmc_detect_reset_cause(void)
{
u32 reg = readl(pmc_base + PMC_RST_STATUS);
switch ((reg & PMC_RST_STATUS_RST_SRC_MASK) >>
PMC_RST_STATUS_RST_SRC_SHIFT) {
case PMC_RST_STATUS_RST_SRC_POR:
reset_source_set(RESET_POR);
break;
case PMC_RST_STATUS_RST_SRC_WATCHDOG:
reset_source_set(RESET_WDG);
break;
case PMC_RST_STATUS_RST_SRC_LP0:
reset_source_set(RESET_WKE);
break;
case PMC_RST_STATUS_RST_SRC_SW_MAIN:
reset_source_set(RESET_RST);
break;
case PMC_RST_STATUS_RST_SRC_SENSOR:
reset_source_set(RESET_THERM);
break;
default:
reset_source_set(RESET_UKWN);
break;
}
}
static int tegra20_pmc_probe(struct device_d *dev)
{
pmc_base = dev_request_mem_region(dev, 0);
@ -46,6 +208,11 @@ static int tegra20_pmc_probe(struct device_d *dev)
return PTR_ERR(pmc_base);
}
tegra_powergate_init();
if (IS_ENABLED(CONFIG_RESET_SOURCE))
tegra20_pmc_detect_reset_cause();
return 0;
}

View File

@ -22,47 +22,6 @@
#include <mach/lowlevel.h>
#include <mach/tegra114-sysctr.h>
static struct NS16550_plat debug_uart = {
.shift = 2,
};
static int tegra_add_debug_console(void)
{
unsigned long base = 0;
if (!of_machine_is_compatible("nvidia,tegra20") &&
!of_machine_is_compatible("nvidia,tegra30") &&
!of_machine_is_compatible("nvidia,tegra124"))
return 0;
/* figure out which UART to use */
if (IS_ENABLED(CONFIG_TEGRA_UART_NONE))
return 0;
if (IS_ENABLED(CONFIG_TEGRA_UART_ODMDATA))
base = tegra20_get_debuguart_base();
if (IS_ENABLED(CONFIG_TEGRA_UART_A))
base = TEGRA_UARTA_BASE;
if (IS_ENABLED(CONFIG_TEGRA_UART_B))
base = TEGRA_UARTB_BASE;
if (IS_ENABLED(CONFIG_TEGRA_UART_C))
base = TEGRA_UARTC_BASE;
if (IS_ENABLED(CONFIG_TEGRA_UART_D))
base = TEGRA_UARTD_BASE;
if (IS_ENABLED(CONFIG_TEGRA_UART_E))
base = TEGRA_UARTE_BASE;
if (!base)
return -ENODEV;
debug_uart.clock = tegra_get_pllp_rate();
add_ns16550_device(DEVICE_ID_DYNAMIC, base, 8 << debug_uart.shift,
IORESOURCE_MEM | IORESOURCE_MEM_8BIT, &debug_uart);
return 0;
}
console_initcall(tegra_add_debug_console);
static int tegra20_mem_init(void)
{
if (!of_machine_is_compatible("nvidia,tegra20"))

View File

@ -151,7 +151,7 @@ static struct pci_controller gt64120_controller = {
static int pcibios_init(void)
{
resource_size_t start, end, map, start1, end1, map1, mask, res_end;
resource_size_t start, end, map, start1, end1, map1, mask;
/*
* Due to a bug in the Galileo system controller, we need
@ -207,7 +207,7 @@ static int pcibios_init(void)
BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
mask != ~((mask & -mask) - 1));
gt64120_io_resource.start = map & mask;
res_end = (map & mask) | ~mask;
gt64120_io_resource.end = (map & mask) | ~mask;
gt64120_controller.io_offset = 0;
/* Addresses are 36-bit, so do shifts in the destinations. */
gt64120_io_resource.start <<= GT_PCI_DCRM_SHF;

View File

@ -20,10 +20,24 @@
#include <complete.h>
#include <linux/pci.h>
static void traverse_bus(struct pci_bus *bus)
{
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
printf("%02x:%02x.%1x %04x: %04x:%04x (rev %02x)\n",
dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), (dev->class >> 8) & 0xffff,
dev->vendor, dev->device, dev->revision);
if (dev->subordinate)
traverse_bus(dev->subordinate);
}
}
static int do_lspci(int argc, char *argv[])
{
struct pci_bus *root_bus;
struct pci_dev *dev;
if (list_empty(&pci_root_buses)) {
printf("No PCI bus detected\n");
@ -31,14 +45,7 @@ static int do_lspci(int argc, char *argv[])
}
list_for_each_entry(root_bus, &pci_root_buses, node) {
list_for_each_entry(dev, &root_bus->devices, bus_list) {
printf("%02x: %04x: %04x:%04x (rev %02x)\n",
dev->devfn,
(dev->class >> 8) & 0xffff,
dev->vendor,
dev->device,
dev->revision);
}
traverse_bus(root_bus);
}
return 0;

View File

@ -25,6 +25,7 @@ static const char * const reset_src_names[] = {
[RESET_WDG] = "WDG",
[RESET_WKE] = "WKE",
[RESET_JTAG] = "JTAG",
[RESET_THERM] = "THERM",
};
static enum reset_src_type reset_source;

View File

@ -30,5 +30,6 @@ source "drivers/reset/Kconfig"
source "drivers/pci/Kconfig"
source "drivers/rtc/Kconfig"
source "drivers/firmware/Kconfig"
source "drivers/phy/Kconfig"
endmenu

View File

@ -29,3 +29,4 @@ obj-$(CONFIG_RESET_CONTROLLER) += reset/
obj-$(CONFIG_PCI) += pci/
obj-y += rtc/
obj-$(CONFIG_FIRMWARE) += firmware/
obj-$(CONFIG_GENERIC_PHY) += phy/

View File

@ -17,12 +17,15 @@
*/
#include <common.h>
#include <clock.h>
#include <io.h>
#include <malloc.h>
#include <asm-generic/div64.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <mach/iomap.h>
#include "clk.h"
#define PLL_BASE_BYPASS BIT(31)
@ -60,6 +63,7 @@
#define PLLDU_LFCON_SET_DIVN 600
#define PLLE_BASE_DIVCML_SHIFT 24
#define PLLE_BASE_DIVCML_MASK 0xf
#define PLLE_BASE_DIVCML_WIDTH 4
#define PLLE_BASE_DIVP_SHIFT 16
#define PLLE_BASE_DIVP_WIDTH 7
@ -78,8 +82,45 @@
PLLE_MISC_SETUP_EX_MASK)
#define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT)
#define PLLE_SS_CTRL 0x68
#define PLLE_SS_DISABLE (7 << 10)
#define XUSBIO_PLL_CFG0 0x51c
#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL (1 << 0)
#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL (1 << 2)
#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET (1 << 6)
#define XUSBIO_PLL_CFG0_SEQ_ENABLE (1 << 24)
#define XUSBIO_PLL_CFG0_SEQ_START_STATE (1 << 25)
#define PLLE_SS_CTRL 0x68
#define PLLE_SS_CNTL_BYPASS_SS (7 << 10)
#define PLLE_SS_CNTL_INTERP_RESET (1 << 11)
#define PLLE_SS_CNTL_SSC_BYP (1 << 12)
#define PLLE_SS_CNTL_CENTER (1 << 14)
#define PLLE_SS_CNTL_INVERT (1 << 15)
#define PLLE_SS_MAX_MASK 0x1ff
#define PLLE_SS_MAX_VAL 0x25
#define PLLE_SS_INC_MASK (0xff << 16)
#define PLLE_SS_INC_VAL (0x1 << 16)
#define PLLE_SS_INCINTRV_MASK (0x3f << 24)
#define PLLE_SS_INCINTRV_VAL (0x20 << 24)
#define PLLE_SS_COEFFICIENTS_MASK \
(PLLE_SS_MAX_MASK | PLLE_SS_INC_MASK | PLLE_SS_INCINTRV_MASK)
#define PLLE_SS_COEFFICIENTS_VAL \
(PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL)
#define PLLE_MISC_VREG_CTRL_SHIFT 2
#define PLLE_MISC_VREG_CTRL_MASK (2 << PLLE_MISC_VREG_CTRL_SHIFT)
#define PLLE_MISC_VREG_BG_CTRL_SHIFT 4
#define PLLE_MISC_VREG_BG_CTRL_MASK (3 << PLLE_MISC_VREG_BG_CTRL_SHIFT)
#define PLLE_MISC_PLLE_PTS (1 << 8)
#define PLLE_MISC_IDDQ_SW_VALUE (1 << 13)
#define PLLE_MISC_IDDQ_SW_CTRL (1 << 14)
#define PLLE_AUX_PLLP_SEL (1 << 2)
#define PLLE_AUX_USE_LOCKDET (1 << 3)
#define PLLE_AUX_ENABLE_SWCTL (1 << 4)
#define PLLE_AUX_SS_SWCTL (1 << 6)
#define PLLE_AUX_SEQ_ENABLE (1 << 24)
#define PLLE_AUX_SEQ_START_STATE (1 << 25)
#define PLLE_AUX_PLLRE_SEL (1 << 28)
#define PMC_SATA_PWRGT 0x1ac
#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
@ -99,10 +140,19 @@
#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \
mask(p->divp_width))
#define divm_shift(p) (p)->divm_shift
#define divn_shift(p) (p)->divn_shift
#define divp_shift(p) (p)->divp_shift
#define divm_mask_shifted(p) (divm_mask(p) << divm_shift(p))
#define divn_mask_shifted(p) (divn_mask(p) << divn_shift(p))
#define divp_mask_shifted(p) (divp_mask(p) << divp_shift(p))
#define divm_max(p) (divm_mask(p))
#define divn_max(p) (divn_mask(p))
#define divp_max(p) (1 << (divp_mask(p)))
#define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
static int clk_pll_is_enabled(struct clk *hw)
@ -393,6 +443,217 @@ const struct clk_ops tegra_clk_pll_ops = {
.set_rate = clk_pll_set_rate,
};
static unsigned long clk_plle_recalc_rate(struct clk *hw,
unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
u32 val = pll_readl_base(pll);
u32 divn = 0, divm = 0, divp = 0;
u64 rate = parent_rate;
divp = (val >> 16) & 0x3f;
divn = (val >> 8) & (0xff);
divm = (val >> 0) & (0xff);
divm *= divp;
rate *= divn;
do_div(rate, divm);
return rate;
}
static int clk_plle_training(struct tegra_clk_pll *pll)
{
u32 val;
/*
* PLLE is already disabled, and setup cleared;
* create falling edge on PLLE IDDQ input.
*/
val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT);
val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT);
val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT);
val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT);
val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT);
val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT);
return wait_on_timeout(100 * MSECOND,
(pll_readl_misc(pll) & PLLE_MISC_READY));
}
static int clk_plle_enable(struct clk *hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned long input_rate = clk_get_rate(clk_get_parent(hw));
struct tegra_clk_pll_freq_table sel;
u32 val;
int err;
if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate))
return -EINVAL;
clk_pll_disable(hw);
val = pll_readl_misc(pll);
val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
pll_writel_misc(val, pll);
val = pll_readl_misc(pll);
if (!(val & PLLE_MISC_READY)) {
err = clk_plle_training(pll);
if (err)
return err;
}
/* configure dividers */
val = pll_readl_base(pll);
val &= ~(0x3fffff);
val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
val |= sel.m << 0;
val |= sel.n << 8;
val |= sel.p << 16;
val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
pll_writel_base(val, pll);
val = pll_readl_misc(pll);
val |= PLLE_MISC_SETUP_VALUE;
val |= PLLE_MISC_LOCK_ENABLE;
pll_writel_misc(val, pll);
val = readl(pll->clk_base + PLLE_SS_CTRL);
val |= PLLE_SS_CNTL_BYPASS_SS;
writel(val, pll->clk_base + PLLE_SS_CTRL);
val = pll_readl_base(pll);
val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE);
pll_writel_base(val, pll);
clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg,
pll->params->lock_bit_idx);
return 0;
}
const struct clk_ops tegra_clk_plle_ops = {
.recalc_rate = clk_plle_recalc_rate,
.is_enabled = clk_pll_is_enabled,
.disable = clk_pll_disable,
.enable = clk_plle_enable,
};
static int clk_plle_tegra114_enable(struct clk *hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned long input_rate = clk_get_rate(clk_get_parent(hw));
struct tegra_clk_pll_freq_table sel;
u32 val;
int ret;
if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate))
return -EINVAL;
val = pll_readl_base(pll);
val &= ~BIT(29); /* Disable lock override */
pll_writel_base(val, pll);
val = pll_readl(pll->params->aux_reg, pll);
val |= PLLE_AUX_ENABLE_SWCTL;
val &= ~PLLE_AUX_SEQ_ENABLE;
pll_writel(val, pll->params->aux_reg, pll);
udelay(1);
val = pll_readl_misc(pll);
val |= PLLE_MISC_LOCK_ENABLE;
val |= PLLE_MISC_IDDQ_SW_CTRL;
val &= ~PLLE_MISC_IDDQ_SW_VALUE;
val |= PLLE_MISC_PLLE_PTS;
val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
pll_writel_misc(val, pll);
udelay(5);
val = pll_readl(PLLE_SS_CTRL, pll);
val |= PLLE_SS_CNTL_BYPASS_SS;
pll_writel(val, PLLE_SS_CTRL, pll);
val = pll_readl_base(pll);
val &= ~(divp_mask_shifted(pll) | divn_mask_shifted(pll) |
divm_mask_shifted(pll));
val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT);
val |= sel.m << divm_shift(pll);
val |= sel.n << divn_shift(pll);
val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
pll_writel_base(val, pll);
udelay(1);
clk_pll_enable(hw);
ret = clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg,
pll->params->lock_bit_idx);
if (ret < 0)
return ret;
val = pll_readl(PLLE_SS_CTRL, pll);
val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT);
val &= ~PLLE_SS_COEFFICIENTS_MASK;
val |= PLLE_SS_COEFFICIENTS_VAL;
pll_writel(val, PLLE_SS_CTRL, pll);
val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS);
pll_writel(val, PLLE_SS_CTRL, pll);
udelay(1);
val &= ~PLLE_SS_CNTL_INTERP_RESET;
pll_writel(val, PLLE_SS_CTRL, pll);
udelay(1);
/* Enable hw control of xusb brick pll */
val = pll_readl_misc(pll);
val &= ~PLLE_MISC_IDDQ_SW_CTRL;
pll_writel_misc(val, pll);
val = pll_readl(pll->params->aux_reg, pll);
val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SEQ_START_STATE);
val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
pll_writel(val, pll->params->aux_reg, pll);
udelay(1);
val |= PLLE_AUX_SEQ_ENABLE;
pll_writel(val, pll->params->aux_reg, pll);
val = pll_readl(XUSBIO_PLL_CFG0, pll);
val |= (XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET |
XUSBIO_PLL_CFG0_SEQ_START_STATE);
val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL |
XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL);
pll_writel(val, XUSBIO_PLL_CFG0, pll);
udelay(1);
val |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
pll_writel(val, XUSBIO_PLL_CFG0, pll);
return ret;
}
static void clk_plle_tegra114_disable(struct clk *hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
u32 val;
clk_pll_disable(hw);
val = pll_readl_misc(pll);
val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE;
pll_writel_misc(val, pll);
udelay(1);
}
const struct clk_ops tegra_clk_plle_tegra114_ops = {
.recalc_rate = clk_pll_recalc_rate,
.is_enabled = clk_pll_is_enabled,
.disable = clk_plle_tegra114_disable,
.enable = clk_plle_tegra114_enable,
};
static struct clk *_tegra_clk_register_pll(const char *name,
const char *parent_name, void __iomem *clk_base,
unsigned long flags, unsigned long fixed_rate,
@ -447,3 +708,25 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
flags, fixed_rate, pll_params, pll_flags, freq_table,
&tegra_clk_pll_ops);
}
struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
void __iomem *clk_base,
unsigned long flags, unsigned long fixed_rate,
struct tegra_clk_pll_params *pll_params, u8 pll_flags,
struct tegra_clk_pll_freq_table *freq_table)
{
return _tegra_clk_register_pll(name, parent_name, clk_base,
flags, fixed_rate, pll_params, pll_flags, freq_table,
&tegra_clk_plle_ops);
}
struct clk *tegra_clk_register_plle_tegra114(const char *name,
const char *parent_name, void __iomem *clk_base,
unsigned long flags, unsigned long fixed_rate,
struct tegra_clk_pll_params *pll_params, u8 pll_flags,
struct tegra_clk_pll_freq_table *freq_table)
{
return _tegra_clk_register_pll(name, parent_name, clk_base,
flags, fixed_rate, pll_params, pll_flags, freq_table,
&tegra_clk_plle_tegra114_ops);
}

View File

@ -62,6 +62,15 @@ static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
{336000000, 100000000, 100, 21, 16, 11},
{312000000, 100000000, 200, 26, 24, 13},
{13000000, 100000000, 200, 1, 26, 13},
{12000000, 100000000, 200, 1, 24, 13},
{0, 0, 0, 0, 0, 0},
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
{12000000, 408000000, 408, 12, 0, 8},
{13000000, 408000000, 408, 13, 0, 8},
@ -114,6 +123,21 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_delay = 300,
};
static struct tegra_clk_pll_params pll_e_params = {
.input_min = 12000000,
.input_max = 1000000000,
.cf_min = 12000000,
.cf_max = 75000000,
.vco_min = 1600000000,
.vco_max = 2400000000U,
.base_reg = CRC_PLLE_BASE,
.misc_reg = CRC_PLLE_MISC,
.aux_reg = CRC_PLLE_AUX,
.lock_bit_idx = CRC_PLLE_MISC_LOCK,
.lock_enable_bit_idx = CRC_PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
static struct tegra_clk_pll_params pll_p_params = {
.input_min = 2000000,
.input_max = 31000000,
@ -220,6 +244,11 @@ static void tegra124_pll_init(void)
clks[TEGRA124_CLK_PLL_U] = tegra_clk_register_pll("pll_u", "pll_ref",
car_base, 0, 0, &pll_u_params, TEGRA_PLLU |
TEGRA_PLL_HAS_CPCON, pll_u_freq_table);
/* PLLE */
clks[TEGRA124_CLK_PLL_E] = tegra_clk_register_plle_tegra114("pll_e",
"pll_ref", car_base, 0, 100000000, &pll_e_params,
TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, pll_e_freq_table);
}
static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c2", "pll_c", "pll_c3",
@ -244,6 +273,12 @@ static void tegra124_periph_init(void)
mux_pllpcm_clkm, ARRAY_SIZE(mux_pllpcm_clkm), car_base,
CRC_CLK_SOURCE_UARTD, TEGRA124_CLK_UARTD,
TEGRA_PERIPH_ON_APB);
clks[TEGRA124_CLK_PCIE] = clk_gate("pcie", "clk_m",
car_base + CRC_CLK_OUT_ENB_U, 6, 0, 0);
clks[TEGRA124_CLK_AFI] = clk_gate("afi", "clk_m",
car_base + CRC_CLK_OUT_ENB_U, 8, 0, 0);
clks[TEGRA124_CLK_CML0] = clk_gate("cml0", "pll_e",
car_base + CRC_PLLE_AUX, 0, 0, 0);
/* peripheral clocks with a divider */
clks[TEGRA124_CLK_MSELECT] = tegra_clk_register_periph("mselect",
@ -286,11 +321,11 @@ static struct tegra_clk_init_table init_table[] = {
{TEGRA124_CLK_PLL_P_OUT2, TEGRA124_CLK_CLK_MAX, 48000000, 1},
{TEGRA124_CLK_PLL_P_OUT3, TEGRA124_CLK_CLK_MAX, 102000000, 1},
{TEGRA124_CLK_PLL_P_OUT4, TEGRA124_CLK_CLK_MAX, 204000000, 1},
{TEGRA124_CLK_MSELECT, TEGRA124_CLK_PLL_P, 204000000, 1},
{TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 0, 1},
{TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 0, 1},
{TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 0, 1},
{TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 0, 1},
{TEGRA124_CLK_MSELECT, TEGRA124_CLK_PLL_P, 102000000, 1},
{TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 0, 0},
{TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 0, 0},
{TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 0, 0},
{TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 0, 0},
{TEGRA124_CLK_SDMMC1, TEGRA124_CLK_PLL_P, 48000000, 0},
{TEGRA124_CLK_SDMMC2, TEGRA124_CLK_PLL_P, 48000000, 0},
{TEGRA124_CLK_SDMMC3, TEGRA124_CLK_PLL_P, 48000000, 0},

View File

@ -324,11 +324,11 @@ static struct tegra_clk_init_table init_table[] = {
{TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1},
{TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1},
{TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1},
{TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 1},
{TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 1},
{TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 1},
{TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 1},
{TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 1},
{TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0},
{TEGRA20_CLK_SDMMC2, TEGRA20_CLK_PLL_P, 48000000, 0},
{TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0},

View File

@ -130,6 +130,13 @@ static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
{ 12000000, 100000000, 150, 1, 18, 11},
{ 216000000, 100000000, 200, 18, 24, 13},
{ 0, 0, 0, 0, 0, 0 },
};
/* PLL parameters */
static struct tegra_clk_pll_params pll_c_params = {
.input_min = 2000000,
@ -201,6 +208,19 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_delay = 1000,
};
static struct tegra_clk_pll_params pll_e_params = {
.input_min = 12000000,
.input_max = 216000000,
.cf_min = 12000000,
.cf_max = 12000000,
.vco_min = 1200000000,
.vco_max = 2400000000U,
.base_reg = CRC_PLLE_BASE,
.misc_reg = CRC_PLLE_MISC,
.lock_enable_bit_idx = CRC_PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
static void tegra30_pll_init(void)
{
/* PLLC */
@ -251,6 +271,11 @@ static void tegra30_pll_init(void)
clks[TEGRA30_CLK_PLL_U] = tegra_clk_register_pll("pll_u", "pll_ref",
car_base, 0, 0, &pll_u_params, TEGRA_PLLU |
TEGRA_PLL_HAS_CPCON, pll_u_freq_table);
/* PLLE */
clks[TEGRA30_CLK_PLL_E] = tegra_clk_register_plle("pll_e", "pll_ref",
car_base, 0, 100000000, &pll_e_params,
TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, pll_e_freq_table);
}
static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"};
@ -278,6 +303,12 @@ static void tegra30_periph_init(void)
mux_pllpcm_clkm, ARRAY_SIZE(mux_pllpcm_clkm), car_base,
CRC_CLK_SOURCE_UARTE, TEGRA30_CLK_UARTE,
TEGRA_PERIPH_ON_APB);
clks[TEGRA30_CLK_PCIE] = clk_gate("pcie", "clk_m",
car_base + CRC_CLK_OUT_ENB_U, 6, 0, 0);
clks[TEGRA30_CLK_AFI] = clk_gate("afi", "clk_m",
car_base + CRC_CLK_OUT_ENB_U, 8, 0, 0);
clks[TEGRA30_CLK_CML0] = clk_gate("cml0", "pll_e",
car_base + CRC_PLLE_AUX, 0, 0, 0);
/* peripheral clocks with a divider */
clks[TEGRA30_CLK_MSELECT] = tegra_clk_register_periph("mselect",
@ -320,12 +351,12 @@ static struct tegra_clk_init_table init_table[] = {
{TEGRA30_CLK_PLL_P_OUT2, TEGRA30_CLK_CLK_MAX, 48000000, 1},
{TEGRA30_CLK_PLL_P_OUT3, TEGRA30_CLK_CLK_MAX, 102000000, 1},
{TEGRA30_CLK_PLL_P_OUT4, TEGRA30_CLK_CLK_MAX, 204000000, 1},
{TEGRA30_CLK_MSELECT, TEGRA30_CLK_PLL_P, 204000000, 1},
{TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 0, 1},
{TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 0, 1},
{TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 0, 1},
{TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 0, 1},
{TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 0, 1},
{TEGRA30_CLK_MSELECT, TEGRA30_CLK_PLL_P, 102000000, 1},
{TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 0, 0},
{TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 0, 0},
{TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 0, 0},
{TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 0, 0},
{TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 0, 0},
{TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0},
{TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0},
{TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0},

View File

@ -63,6 +63,7 @@ struct tegra_clk_pll_params {
u32 base_reg;
u32 misc_reg;
u32 aux_reg;
u32 lock_reg;
u8 lock_bit_idx;
u8 lock_enable_bit_idx;
@ -101,6 +102,18 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
struct tegra_clk_pll_params *pll_params, u8 pll_flags,
struct tegra_clk_pll_freq_table *freq_table);
struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
void __iomem *clk_base,
unsigned long flags, unsigned long fixed_rate,
struct tegra_clk_pll_params *pll_params, u8 pll_flags,
struct tegra_clk_pll_freq_table *freq_table);
struct clk *tegra_clk_register_plle_tegra114(const char *name,
const char *parent_name, void __iomem *clk_base,
unsigned long flags, unsigned long fixed_rate,
struct tegra_clk_pll_params *pll_params, u8 pll_flags,
struct tegra_clk_pll_freq_table *freq_table);
/* struct tegra_clk_pll_out - PLL output divider */
struct tegra_clk_pll_out {
struct clk hw;

View File

@ -696,4 +696,4 @@ static struct driver_d tegra_i2c_driver = {
.probe = tegra_i2c_probe,
.of_compatible = DRV_OF_COMPAT(tegra_i2c_compatible),
};
device_platform_driver(tegra_i2c_driver);
register_driver_macro(fs, platform, tegra_i2c_driver);

View File

@ -156,6 +156,14 @@ config DRIVER_NET_RTL8139
This is a driver for the Fast Ethernet PCI network cards based on
the RTL 8139 chips.
config DRIVER_NET_RTL8169
bool "RealTek RTL-8169 PCI Ethernet driver"
depends on PCI
select PHYLIB
help
This is a driver for the Fast Ethernet PCI network cards based on
the RTL 8169 chips.
config DRIVER_NET_SMC911X
bool "smc911x ethernet driver"
select PHYLIB

View File

@ -22,6 +22,7 @@ obj-$(CONFIG_DRIVER_NET_MPC5200) += fec_mpc5200.o
obj-$(CONFIG_DRIVER_NET_NETX) += netx_eth.o
obj-$(CONFIG_DRIVER_NET_ORION) += orion-gbe.o
obj-$(CONFIG_DRIVER_NET_RTL8139) += rtl8139.o
obj-$(CONFIG_DRIVER_NET_RTL8169) += rtl8169.o
obj-$(CONFIG_DRIVER_NET_SMC911X) += smc911x.o
obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o

578
drivers/net/rtl8169.c Normal file
View File

@ -0,0 +1,578 @@
/*
* Copyright (C) 2014 Lucas Stach <l.stach@pengutronix.de>
*
* 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 <asm/mmu.h>
#include <common.h>
#include <init.h>
#include <net.h>
#include <malloc.h>
#include <linux/pci.h>
#define NUM_TX_DESC 1
#define NUM_RX_DESC 4
#define PKT_BUF_SIZE 1536
#define ETH_ZLEN 60
struct rtl8169_chip_info {
const char *name;
u8 version;
u32 RxConfigMask;
};
#define BD_STAT_OWN 0x80000000
#define BD_STAT_EOR 0x40000000
#define BD_STAT_FS 0x20000000
#define BD_STAT_LS 0x10000000
#define BD_STAT_RX_RES 0x00200000
struct bufdesc {
u32 status;
u32 vlan_tag;
u32 buf_addr;
u32 buf_Haddr;
};
struct rtl8169_priv {
struct eth_device edev;
void __iomem *base;
struct pci_dev *pci_dev;
int chipset;
struct bufdesc *tx_desc;
void *tx_buf;
unsigned int cur_tx;
struct bufdesc *rx_desc;
void *rx_buf;
unsigned int cur_rx;
struct mii_bus miibus;
};
#define MAC0 0x00
#define MAR0 0x08
#define TxDescStartAddrLow 0x20
#define TxDescStartAddrHigh 0x24
#define TxHDescStartAddrLow 0x28
#define TxHDescStartAddrHigh 0x2c
#define FLASH 0x30
#define ERSR 0x36
#define ChipCmd 0x37
#define CmdReset 0x10
#define CmdRxEnb 0x08
#define CmdTxEnb 0x04
#define RxBufEmpty 0x01
#define TxPoll 0x38
#define IntrMask 0x3c
#define IntrStatus 0x3e
#define SYSErr 0x8000
#define PCSTimeout 0x4000
#define SWInt 0x0100
#define TxDescUnavail 0x80
#define RxFIFOOver 0x40
#define RxUnderrun 0x20
#define RxOverflow 0x10
#define TxErr 0x08
#define TxOK 0x04
#define RxErr 0x02
#define RxOK 0x01
#define TxConfig 0x40
#define TxInterFrameGapShift 24
#define TxDMAShift 8
#define RxConfig 0x44
#define AcceptErr 0x20
#define AcceptRunt 0x10
#define AcceptBroadcast 0x08
#define AcceptMulticast 0x04
#define AcceptMyPhys 0x02
#define AcceptAllPhys 0x01
#define RxCfgFIFOShift 13
#define RxCfgDMAShift 8
#define RxMissed 0x4c
#define Cfg9346 0x50
#define Cfg9346_Lock 0x00
#define Cfg9346_Unlock 0xc0
#define Config0 0x51
#define Config1 0x52
#define Config2 0x53
#define Config3 0x54
#define Config4 0x55
#define Config5 0x56
#define MultiIntr 0x5c
#define PHYAR 0x60
#define TBICSR 0x64
#define TBI_ANAR 0x68
#define TBI_LPAR 0x6a
#define PHYstatus 0x6c
#define RxMaxSize 0xda
#define CPlusCmd 0xe0
#define RxDescStartAddrLow 0xe4
#define RxDescStartAddrHigh 0xe8
#define EarlyTxThres 0xec
#define FuncEvent 0xf0
#define FuncEventMask 0xf4
#define FuncPresetState 0xf8
#define FuncForceEvent 0xfc
/* write MMIO register */
#define RTL_W8(priv, reg, val) writeb(val, ((char *)(priv->base) + reg))
#define RTL_W16(priv, reg, val) writew(val, ((char *)(priv->base) + reg))
#define RTL_W32(priv, reg, val) writel(val, ((char *)(priv->base) + reg))
/* read MMIO register */
#define RTL_R8(priv, reg) readb(((char *)(priv->base) + reg))
#define RTL_R16(priv, reg) readw(((char *)(priv->base) + reg))
#define RTL_R32(priv, reg) readl(((char *)(priv->base) + reg))
static const u32 rtl8169_rx_config =
(7 << RxCfgFIFOShift) | (6 << RxCfgDMAShift);
static void rtl8169_chip_reset(struct rtl8169_priv *priv)
{
int i;
/* Soft reset the chip. */
RTL_W8(priv, ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--) {
if ((RTL_R8(priv, ChipCmd) & CmdReset) == 0)
break;
udelay(10);
}
}
static struct rtl8169_chip_info chip_info[] = {
{"RTL-8169", 0x00, 0xff7e1880},
{"RTL-8169", 0x04, 0xff7e1880},
{"RTL-8169", 0x00, 0xff7e1880},
{"RTL-8169s/8110s", 0x02, 0xff7e1880},
{"RTL-8169s/8110s", 0x04, 0xff7e1880},
{"RTL-8169sb/8110sb", 0x10, 0xff7e1880},
{"RTL-8169sc/8110sc", 0x18, 0xff7e1880},
{"RTL-8168b/8111sb", 0x30, 0xff7e1880},
{"RTL-8168b/8111sb", 0x38, 0xff7e1880},
{"RTL-8168d/8111d", 0x28, 0xff7e1880},
{"RTL-8168evl/8111evl", 0x2e, 0xff7e1880},
{"RTL-8168/8111g", 0x4c, 0xff7e1880,},
{"RTL-8101e", 0x34, 0xff7e1880},
{"RTL-8100e", 0x32, 0xff7e1880},
};
static void rtl8169_chip_identify(struct rtl8169_priv *priv)
{
u32 val;
int i;
val = RTL_R32(priv, TxConfig);
val = ((val & 0x7c000000) + ((val & 0x00800000) << 2)) >> 24;
for (i = ARRAY_SIZE(chip_info) - 1; i >= 0; i--){
if (val == chip_info[i].version) {
priv->chipset = i;
dev_dbg(&priv->pci_dev->dev, "found %s chipset\n",
chip_info[i].name);
return;
}
}
dev_dbg(&priv->pci_dev->dev,
"no matching chip version found, assuming RTL-8169\n");
priv->chipset = 0;
}
static int rtl8169_init_dev(struct eth_device *edev)
{
struct rtl8169_priv *priv = edev->priv;
rtl8169_chip_reset(priv);
rtl8169_chip_identify(priv);
pci_set_master(priv->pci_dev);
return 0;
}
static void __set_rx_mode(struct rtl8169_priv *priv)
{
u32 mc_filter[2], val;
/* IFF_ALLMULTI */
/* Too many to filter perfectly -- accept all multicasts. */
mc_filter[1] = mc_filter[0] = 0xffffffff;
val = AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
rtl8169_rx_config | (RTL_R32(priv, RxConfig) &
chip_info[priv->chipset].RxConfigMask);
RTL_W32(priv, RxConfig, val);
RTL_W32(priv, MAR0 + 0, mc_filter[0]);
RTL_W32(priv, MAR0 + 4, mc_filter[1]);
}
static void rtl8169_init_ring(struct rtl8169_priv *priv)
{
int i;
priv->cur_rx = priv->cur_tx = 0;
priv->tx_desc = dma_alloc_coherent(NUM_TX_DESC *
sizeof(struct bufdesc));
priv->tx_buf = malloc(NUM_TX_DESC * PKT_BUF_SIZE);
priv->rx_desc = dma_alloc_coherent(NUM_RX_DESC *
sizeof(struct bufdesc));
priv->rx_buf = malloc(NUM_RX_DESC * PKT_BUF_SIZE);
dma_clean_range((unsigned long)priv->rx_buf,
(unsigned long)priv->rx_buf + NUM_RX_DESC * PKT_BUF_SIZE);
memset(priv->tx_desc, 0, NUM_TX_DESC * sizeof(struct bufdesc));
memset(priv->rx_desc, 0, NUM_RX_DESC * sizeof(struct bufdesc));
for (i = 0; i < NUM_RX_DESC; i++) {
if (i == (NUM_RX_DESC - 1))
priv->rx_desc[i].status =
BD_STAT_OWN | BD_STAT_EOR | PKT_BUF_SIZE;
else
priv->rx_desc[i].status =
BD_STAT_OWN | PKT_BUF_SIZE;
priv->rx_desc[i].buf_addr =
virt_to_phys(priv->rx_buf + i * PKT_BUF_SIZE);
}
dma_flush_range((unsigned long)priv->rx_desc,
(unsigned long)priv->rx_desc +
NUM_RX_DESC * sizeof(struct bufdesc));
}
static void rtl8169_hw_start(struct rtl8169_priv *priv)
{
u32 val;
RTL_W8(priv, Cfg9346, Cfg9346_Unlock);
/* RTL-8169sb/8110sb or previous version */
if (priv->chipset <= 5)
RTL_W8(priv, ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8(priv, EarlyTxThres, 0x3f);
/* For gigabit rtl8169 */
RTL_W16(priv, RxMaxSize, 0x800);
/* Set Rx Config register */
val = rtl8169_rx_config | (RTL_R32(priv, RxConfig) &
chip_info[priv->chipset].RxConfigMask);
RTL_W32(priv, RxConfig, val);
/* Set DMA burst size and Interframe Gap Time */
RTL_W32(priv, TxConfig, (6 << TxDMAShift) | (3 << TxInterFrameGapShift));
RTL_W32(priv, TxDescStartAddrLow, virt_to_phys(priv->tx_desc));
RTL_W32(priv, TxDescStartAddrHigh, 0);
RTL_W32(priv, RxDescStartAddrLow, virt_to_phys(priv->rx_desc));
RTL_W32(priv, RxDescStartAddrHigh, 0);
/* RTL-8169sc/8110sc or later version */
if (priv->chipset > 5)
RTL_W8(priv, ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8(priv, Cfg9346, Cfg9346_Lock);
udelay(10);
RTL_W32(priv, RxMissed, 0);
__set_rx_mode(priv);
/* no early-rx interrupts */
RTL_W16(priv, MultiIntr, RTL_R16(priv, MultiIntr) & 0xf000);
}
static int rtl8169_eth_open(struct eth_device *edev)
{
struct rtl8169_priv *priv = edev->priv;
int ret;
rtl8169_init_ring(priv);
rtl8169_hw_start(priv);
ret = phy_device_connect(edev, &priv->miibus, 0, NULL, 0,
PHY_INTERFACE_MODE_NA);
return ret;
}
static int rtl8169_phy_write(struct mii_bus *bus, int phy_addr,
int reg, u16 val)
{
struct rtl8169_priv *priv = bus->priv;
int i;
if (phy_addr != 0)
return -1;
RTL_W32(priv, PHYAR, 0x80000000 | (reg & 0xff) << 16 | val);
mdelay(1);
for (i = 2000; i > 0; i--) {
if (!(RTL_R32(priv, PHYAR) & 0x80000000)) {
return 0;
} else {
udelay(100);
}
}
return -1;
}
static int rtl8169_phy_read(struct mii_bus *bus, int phy_addr, int reg)
{
struct rtl8169_priv *priv = bus->priv;
int i, val = 0xffff;
RTL_W32(priv, PHYAR, 0x0 | (reg & 0xff) << 16);
mdelay(10);
if (phy_addr != 0)
return val;
for (i = 2000; i > 0; i--) {
if (RTL_R32(priv, PHYAR) & 0x80000000) {
val = (int) (RTL_R32(priv, PHYAR) & 0xffff);
break;
} else {
udelay(100);
}
}
return val;
}
static int rtl8169_eth_send(struct eth_device *edev, void *packet,
int packet_length)
{
struct rtl8169_priv *priv = edev->priv;
unsigned int entry;
entry = priv->cur_tx % NUM_TX_DESC;
if (packet_length < ETH_ZLEN)
memset(priv->tx_buf + entry * PKT_BUF_SIZE, 0, ETH_ZLEN);
memcpy(priv->tx_buf + entry * PKT_BUF_SIZE, packet, packet_length);
dma_flush_range((unsigned long)priv->tx_buf + entry * PKT_BUF_SIZE,
(unsigned long)priv->tx_buf + (entry + 1) * PKT_BUF_SIZE);
priv->tx_desc[entry].buf_Haddr = 0;
priv->tx_desc[entry].buf_addr =
virt_to_phys(priv->tx_buf + entry * PKT_BUF_SIZE);
if (entry != (NUM_TX_DESC - 1)) {
priv->tx_desc[entry].status =
BD_STAT_OWN | BD_STAT_FS | BD_STAT_LS |
((packet_length > ETH_ZLEN) ? packet_length : ETH_ZLEN);
} else {
priv->tx_desc[entry].status =
BD_STAT_OWN | BD_STAT_EOR | BD_STAT_FS | BD_STAT_LS |
((packet_length > ETH_ZLEN) ? packet_length : ETH_ZLEN);
}
dma_flush_range((unsigned long)&priv->tx_desc[entry],
(unsigned long)&priv->tx_desc[entry + 1]);
RTL_W8(priv, TxPoll, 0x40);
do {
dma_inv_range((unsigned long)&priv->tx_desc[entry],
(unsigned long)&priv->tx_desc[entry + 1]);
} while (priv->tx_desc[entry].status & BD_STAT_OWN);
priv->cur_tx++;
return 0;
}
static int rtl8169_eth_rx(struct eth_device *edev)
{
struct rtl8169_priv *priv = edev->priv;
unsigned int entry, pkt_size = 0;
u8 status;
entry = priv->cur_rx % NUM_RX_DESC;
dma_inv_range((unsigned long)&priv->rx_desc[entry],
(unsigned long)&priv->rx_desc[entry + 1]);
if ((priv->rx_desc[entry].status & BD_STAT_OWN) == 0) {
if (!(priv->rx_desc[entry].status & BD_STAT_RX_RES)) {
pkt_size = (priv->rx_desc[entry].status & 0x1fff) - 4;
dma_inv_range((unsigned long)priv->rx_buf
+ entry * PKT_BUF_SIZE,
(unsigned long)priv->rx_buf
+ entry * PKT_BUF_SIZE + pkt_size);
net_receive(edev, priv->rx_buf + entry * PKT_BUF_SIZE,
pkt_size);
/*
* the buffer is going to be reused by HW, make sure to
* clean out any potentially modified data
*/
dma_clean_range((unsigned long)priv->rx_buf
+ entry * PKT_BUF_SIZE,
(unsigned long)priv->rx_buf
+ entry * PKT_BUF_SIZE + pkt_size);
if (entry == NUM_RX_DESC - 1)
priv->rx_desc[entry].status = BD_STAT_OWN |
BD_STAT_EOR | PKT_BUF_SIZE;
else
priv->rx_desc[entry].status =
BD_STAT_OWN | PKT_BUF_SIZE;
priv->rx_desc[entry].buf_addr =
virt_to_phys(priv->rx_buf +
entry * PKT_BUF_SIZE);
dma_flush_range((unsigned long)&priv->rx_desc[entry],
(unsigned long)&priv->rx_desc[entry + 1]);
} else {
dev_err(&edev->dev, "rx error\n");
}
priv->cur_rx++;
return pkt_size;
} else {
status = RTL_R8(priv, IntrStatus);
RTL_W8(priv, IntrStatus, status & ~(TxErr | RxErr | SYSErr));
udelay(100); /* wait */
}
return 0;
}
static int rtl8169_get_ethaddr(struct eth_device *edev, unsigned char *m)
{
struct rtl8169_priv *priv = edev->priv;
int i;
for (i = 0; i < 6; i++) {
m[i] = RTL_R8(priv, MAC0 + i);
}
return 0;
}
static int rtl8169_set_ethaddr(struct eth_device *edev, unsigned char *mac_addr)
{
struct rtl8169_priv *priv = edev->priv;
int i;
RTL_W8(priv, Cfg9346, Cfg9346_Unlock);
for (i = 0; i < 6; i++) {
RTL_W8(priv, (MAC0 + i), mac_addr[i]);
RTL_R8(priv, mac_addr[i]);
}
RTL_W8(priv, Cfg9346, Cfg9346_Lock);
return 0;
}
static void rtl8169_eth_halt(struct eth_device *edev)
{
struct rtl8169_priv *priv = edev->priv;
/* Stop the chip's Tx and Rx DMA processes. */
RTL_W8(priv, ChipCmd, 0x00);
/* Disable interrupts by clearing the interrupt mask. */
RTL_W16(priv, IntrMask, 0x0000);
RTL_W32(priv, RxMissed, 0);
pci_clear_master(priv->pci_dev);
}
static int rtl8169_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct device_d *dev = &pdev->dev;
struct eth_device *edev;
struct rtl8169_priv *priv;
int ret;
/* enable pci device */
pci_enable_device(pdev);
priv = xzalloc(sizeof(struct rtl8169_priv));
edev = &priv->edev;
dev->type_data = edev;
edev->priv = priv;
priv->pci_dev = pdev;
priv->miibus.read = rtl8169_phy_read;
priv->miibus.write = rtl8169_phy_write;
priv->miibus.priv = priv;
priv->miibus.parent = &edev->dev;
priv->base = pci_iomap(pdev, pdev->device == 0x8168 ? 2 : 1);
dev_dbg(dev, "rtl%04x (rev %02x) (base=%p)\n",
pdev->device, pdev->revision, priv->base);
edev->init = rtl8169_init_dev;
edev->open = rtl8169_eth_open;
edev->send = rtl8169_eth_send;
edev->recv = rtl8169_eth_rx;
edev->get_ethaddr = rtl8169_get_ethaddr;
edev->set_ethaddr = rtl8169_set_ethaddr;
edev->halt = rtl8169_eth_halt;
edev->parent = dev;
ret = eth_register(edev);
if (ret)
goto eth_err;
ret = mdiobus_register(&priv->miibus);
if (ret)
goto mdio_err;
return 0;
mdio_err:
eth_unregister(edev);
eth_err:
free(priv);
return ret;
}
static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },
{ /* sentinel */ }
};
static struct pci_driver rtl8169_eth_driver = {
.name = "rtl8169_eth",
.id_table = rtl8169_pci_tbl,
.probe = rtl8169_probe,
};
static int rtl8169_init(void)
{
return pci_register_driver(&rtl8169_eth_driver);
}
device_initcall(rtl8169_init);

View File

@ -30,6 +30,7 @@ config OF_GPIO
config OF_PCI
bool
depends on PCI
select OF_ADDRESS_PCI
help
OpenFirmware PCI bus accessors

View File

@ -179,6 +179,74 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na)
}
#endif /* CONFIG_OF_ADDRESS_PCI */
#ifdef CONFIG_OF_PCI
int of_pci_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node)
{
const int na = 3, ns = 2;
int rlen;
parser->node = node;
parser->pna = of_n_addr_cells(node);
parser->np = parser->pna + na + ns;
parser->range = of_get_property(node, "ranges", &rlen);
if (parser->range == NULL)
return -ENOENT;
parser->end = parser->range + rlen / sizeof(__be32);
return 0;
}
EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
struct of_pci_range *range)
{
const int na = 3, ns = 2;
if (!range)
return NULL;
if (!parser->range || parser->range + parser->np > parser->end)
return NULL;
range->pci_space = parser->range[0];
range->flags = of_bus_pci_get_flags(parser->range);
range->pci_addr = of_read_number(parser->range + 1, ns);
range->cpu_addr = of_translate_address(parser->node,
parser->range + na);
range->size = of_read_number(parser->range + parser->pna + na, ns);
parser->range += parser->np;
/* Now consume following elements while they are contiguous */
while (parser->range + parser->np <= parser->end) {
u32 flags, pci_space;
u64 pci_addr, cpu_addr, size;
pci_space = be32_to_cpup(parser->range);
flags = of_bus_pci_get_flags(parser->range);
pci_addr = of_read_number(parser->range + 1, ns);
cpu_addr = of_translate_address(parser->node,
parser->range + na);
size = of_read_number(parser->range + parser->pna + na, ns);
if (flags != range->flags)
break;
if (pci_addr != range->pci_addr + range->size ||
cpu_addr != range->cpu_addr + range->size)
break;
range->size += size;
parser->range += parser->np;
}
return range;
}
EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
#endif /* CONFIG_OF_PCI */
/*
* Array of bus specific translators
*/

View File

@ -30,6 +30,13 @@ config PCI_MVEBU
select OF_PCI
select PCI
config PCI_TEGRA
bool "NVDIA Tegra PCIe driver"
depends on ARCH_TEGRA
select OF_ADDRESS_PCI
select OF_PCI
select PCI
endmenu
endif

View File

@ -8,3 +8,4 @@ ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
CPPFLAGS += $(ccflags-y)
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o pci-mvebu-phy.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o

View File

@ -86,7 +86,8 @@ int pci_register_device(struct pci_dev *pdev)
struct device_d *dev = &pdev->dev;
int ret;
strcpy(dev->name, "pci");
snprintf(dev->name, MAX_DRIVER_NAME, "pci-%04x:%04x.",
pdev->vendor, pdev->device);
dev->bus = &pci_bus;
dev->id = DEVICE_ID_DYNAMIC;

1305
drivers/pci/pci-tegra.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,9 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head;
LIST_HEAD(pci_root_buses);
EXPORT_SYMBOL(pci_root_buses);
static u8 bus_index;
static resource_size_t last_mem;
static resource_size_t last_mem_pref;
static resource_size_t last_io;
static struct pci_bus *pci_alloc_bus(void)
{
@ -37,14 +40,32 @@ void register_pci_controller(struct pci_controller *hose)
bus = pci_alloc_bus();
hose->bus = bus;
bus->parent = hose->parent;
bus->host = hose;
bus->ops = hose->pci_ops;
bus->resource[0] = hose->mem_resource;
bus->resource[1] = hose->io_resource;
bus->resource[PCI_BUS_RESOURCE_MEM] = hose->mem_resource;
bus->resource[PCI_BUS_RESOURCE_MEM_PREF] = hose->mem_pref_resource;
bus->resource[PCI_BUS_RESOURCE_IO] = hose->io_resource;
bus->number = bus_index++;
if (hose->set_busno)
hose->set_busno(hose, bus->number);
if (bus->resource[PCI_BUS_RESOURCE_MEM])
last_mem = bus->resource[PCI_BUS_RESOURCE_MEM]->start;
else
last_mem = 0;
if (bus->resource[PCI_BUS_RESOURCE_MEM])
last_mem_pref = bus->resource[PCI_BUS_RESOURCE_MEM_PREF]->start;
else
last_mem_pref = 0;
if (bus->resource[PCI_BUS_RESOURCE_IO])
last_io = bus->resource[PCI_BUS_RESOURCE_IO]->start;
else
last_io = 0;
pci_scan_bus(bus);
list_add_tail(&bus->node, &pci_root_buses);
@ -111,27 +132,162 @@ static struct pci_dev *alloc_pci_dev(void)
return dev;
}
static void setup_device(struct pci_dev *dev, int max_bar)
{
int bar, size;
u32 mask;
u8 cmd;
pci_read_config_byte(dev, PCI_COMMAND, &cmd);
pci_write_config_byte(dev, PCI_COMMAND,
cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
for (bar = 0; bar < max_bar; bar++) {
resource_size_t last_addr;
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, 0xfffffffe);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &mask);
if (mask == 0 || mask == 0xffffffff) {
DBG(" PCI: pbar%d set bad mask\n", bar);
continue;
}
if (mask & 0x01) { /* IO */
size = -(mask & 0xfffffffe);
DBG(" PCI: pbar%d: mask=%08x io %d bytes\n", bar, mask, size);
if (last_io + size >
dev->bus->resource[PCI_BUS_RESOURCE_IO]->end) {
DBG("BAR does not fit within bus IO res\n");
return;
}
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_io);
dev->resource[bar].flags = IORESOURCE_IO;
last_addr = last_io;
last_io += size;
} else if ((mask & PCI_BASE_ADDRESS_MEM_PREFETCH) &&
last_mem_pref) /* prefetchable MEM */ {
size = -(mask & 0xfffffff0);
DBG(" PCI: pbar%d: mask=%08x P memory %d bytes\n",
bar, mask, size);
if (last_mem_pref + size >
dev->bus->resource[PCI_BUS_RESOURCE_MEM_PREF]->end) {
DBG("BAR does not fit within bus p-mem res\n");
return;
}
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem_pref);
dev->resource[bar].flags = IORESOURCE_MEM |
IORESOURCE_PREFETCH;
last_addr = last_mem_pref;
last_mem_pref += size;
} else { /* non-prefetch MEM */
size = -(mask & 0xfffffff0);
DBG(" PCI: pbar%d: mask=%08x NP memory %d bytes\n",
bar, mask, size);
if (last_mem + size >
dev->bus->resource[PCI_BUS_RESOURCE_MEM]->end) {
DBG("BAR does not fit within bus np-mem res\n");
return;
}
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem);
dev->resource[bar].flags = IORESOURCE_MEM;
last_addr = last_mem;
last_mem += size;
}
dev->resource[bar].start = last_addr;
dev->resource[bar].end = last_addr + size - 1;
if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
PCI_BASE_ADDRESS_MEM_TYPE_64) {
dev->resource[bar].flags |= IORESOURCE_MEM_64;
pci_write_config_dword(dev,
PCI_BASE_ADDRESS_1 + bar * 4, 0);
bar++;
}
}
pci_write_config_byte(dev, PCI_COMMAND, cmd);
list_add_tail(&dev->bus_list, &dev->bus->devices);
}
static void prescan_setup_bridge(struct pci_dev *dev)
{
u16 cmdstat;
pci_read_config_word(dev, PCI_COMMAND, &cmdstat);
/* Configure bus number registers */
pci_write_config_byte(dev, PCI_PRIMARY_BUS, dev->bus->number);
pci_write_config_byte(dev, PCI_SECONDARY_BUS, dev->subordinate->number);
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, 0xff);
if (last_mem) {
/* Set up memory and I/O filter limits, assume 32-bit I/O space */
pci_write_config_word(dev, PCI_MEMORY_BASE,
(last_mem & 0xfff00000) >> 16);
cmdstat |= PCI_COMMAND_MEMORY;
}
if (last_mem_pref) {
/* Set up memory and I/O filter limits, assume 32-bit I/O space */
pci_write_config_word(dev, PCI_PREF_MEMORY_BASE,
(last_mem_pref & 0xfff00000) >> 16);
cmdstat |= PCI_COMMAND_MEMORY;
} else {
/* We don't support prefetchable memory for now, so disable */
pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, 0x1000);
pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, 0x0);
}
if (last_io) {
pci_write_config_byte(dev, PCI_IO_BASE,
(last_io & 0x0000f000) >> 8);
pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
(last_io & 0xffff0000) >> 16);
cmdstat |= PCI_COMMAND_IO;
}
/* Enable memory and I/O accesses, enable bus master */
pci_write_config_word(dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER);
}
static void postscan_setup_bridge(struct pci_dev *dev)
{
/* limit subordinate to last used bus number */
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, bus_index - 1);
if (last_mem)
pci_write_config_word(dev, PCI_MEMORY_LIMIT,
((last_mem - 1) & 0xfff00000) >> 16);
if (last_mem_pref)
pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT,
((last_mem_pref - 1) & 0xfff00000) >> 16);
if (last_io) {
pci_write_config_byte(dev, PCI_IO_LIMIT,
((last_io - 1) & 0x0000f000) >> 8);
pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
((last_io - 1) & 0xffff0000) >> 16);
}
}
unsigned int pci_scan_bus(struct pci_bus *bus)
{
struct pci_dev *dev;
struct pci_bus *child_bus;
unsigned int devfn, l, max, class;
unsigned char cmd, tmp, hdr_type, is_multi = 0;
struct pci_dev *dev;
resource_size_t last_mem;
resource_size_t last_io;
/* FIXME: use res_start() */
last_mem = bus->resource[0]->start;
last_io = bus->resource[1]->start;
DBG("pci_scan_bus for bus %d\n", bus->number);
DBG(" last_io = 0x%08x, last_mem = 0x%08x\n", last_io, last_mem);
DBG(" last_io = 0x%08x, last_mem = 0x%08x, last_mem_pref = 0x%08x\n",
last_io, last_mem, last_mem_pref);
max = bus->secondary;
for (devfn = 0; devfn < 0xff; ++devfn) {
int bar;
u32 old_bar, mask;
int size;
if (PCI_FUNC(devfn) && !is_multi) {
/* not a multi-function device */
continue;
@ -154,6 +310,7 @@ unsigned int pci_scan_bus(struct pci_bus *bus)
dev->devfn = devfn;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
dev->dev.parent = bus->parent;
/* non-destructively determine if device can be a master: */
pci_read_config_byte(dev, PCI_COMMAND, &cmd);
@ -169,9 +326,11 @@ unsigned int pci_scan_bus(struct pci_bus *bus)
dev->hdr_type = hdr_type;
DBG("PCI: class = %08x, hdr_type = %08x\n", class, hdr_type);
DBG("PCI: %02x:%02x [%04x:%04x]\n", bus->number, dev->devfn,
dev->vendor, dev->device);
switch (hdr_type & 0x7f) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
switch (hdr_type & 0x7f) {
case PCI_HEADER_TYPE_NORMAL:
if (class == PCI_CLASS_BRIDGE_PCI)
goto bad;
@ -181,70 +340,48 @@ unsigned int pci_scan_bus(struct pci_bus *bus)
*/
pci_read_config_dword(dev, PCI_ROM_ADDRESS, &l);
dev->rom_address = (l == 0xffffffff) ? 0 : l;
setup_device(dev, 6);
break;
default: /* unknown header */
case PCI_HEADER_TYPE_BRIDGE:
setup_device(dev, 2);
child_bus = pci_alloc_bus();
/* inherit parent properties */
child_bus->host = bus->host;
child_bus->ops = bus->host->pci_ops;
child_bus->resource[PCI_BUS_RESOURCE_MEM] =
bus->resource[PCI_BUS_RESOURCE_MEM];
child_bus->resource[PCI_BUS_RESOURCE_MEM_PREF] =
bus->resource[PCI_BUS_RESOURCE_MEM_PREF];
child_bus->resource[PCI_BUS_RESOURCE_IO] =
bus->resource[PCI_BUS_RESOURCE_IO];
child_bus->parent = &dev->dev;
child_bus->number = bus_index++;
list_add_tail(&child_bus->node, &bus->children);
dev->subordinate = child_bus;
prescan_setup_bridge(dev);
pci_scan_bus(child_bus);
postscan_setup_bridge(dev);
/* first activate bridge then all devices on it's bus */
pci_register_device(dev);
list_for_each_entry(dev, &child_bus->devices, bus_list)
if (!dev->subordinate)
pci_register_device(dev);
break;
default:
bad:
printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
continue;
}
DBG("PCI: %02x:%02x [%04x/%04x]\n", bus->number, dev->devfn, dev->vendor, dev->device);
if (class == PCI_CLASS_BRIDGE_HOST) {
DBG("PCI: skip pci host bridge\n");
continue;
}
pci_read_config_byte(dev, PCI_COMMAND, &cmd);
pci_write_config_byte(dev, PCI_COMMAND,
cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
for (bar = 0; bar < 6; bar++) {
resource_size_t last_addr;
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &old_bar);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, 0xfffffffe);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &mask);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, old_bar);
if (mask == 0 || mask == 0xffffffff) {
DBG(" PCI: pbar%d set bad mask\n", bar);
continue;
}
if (mask & 0x01) { /* IO */
size = -(mask & 0xfffffffe);
DBG(" PCI: pbar%d: mask=%08x io %d bytes\n", bar, mask, size);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_io);
dev->resource[bar].flags = IORESOURCE_IO;
last_addr = last_io;
last_io += size;
} else { /* MEM */
size = -(mask & 0xfffffff0);
DBG(" PCI: pbar%d: mask=%08x memory %d bytes\n", bar, mask, size);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem);
dev->resource[bar].flags = IORESOURCE_MEM;
last_addr = last_mem;
last_mem += size;
if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
PCI_BASE_ADDRESS_MEM_TYPE_64) {
dev->resource[bar].flags |= IORESOURCE_MEM_64;
pci_write_config_dword(dev,
PCI_BASE_ADDRESS_1 + bar * 4, 0);
}
}
dev->resource[bar].start = last_addr;
dev->resource[bar].end = last_addr + size - 1;
if (dev->resource[bar].flags & IORESOURCE_MEM_64)
bar++;
}
pci_write_config_byte(dev, PCI_COMMAND, cmd);
list_add_tail(&dev->bus_list, &bus->devices);
pci_register_device(dev);
}
/*
@ -254,6 +391,7 @@ unsigned int pci_scan_bus(struct pci_bus *bus)
*
* Return how far we've got finding sub-buses.
*/
max = bus_index;
DBG("PCI: pci_scan_bus returning with max=%02x\n", max);
return max;

18
drivers/phy/Kconfig Normal file
View File

@ -0,0 +1,18 @@
#
# PHY
#
menu "PHY Subsystem"
config GENERIC_PHY
bool "PHY Core"
help
Generic PHY support.
This framework is designed to provide a generic interface for PHY
devices present in the kernel. This layer will have the generic
API by which phy drivers can create PHY using the phy framework and
phy users can obtain reference to the PHY. All the users of this
framework should select this config.
endmenu

5
drivers/phy/Makefile Normal file
View File

@ -0,0 +1,5 @@
#
# Makefile for the phy drivers.
#
obj-$(CONFIG_GENERIC_PHY) += phy-core.o

318
drivers/phy/phy-core.c Normal file
View File

@ -0,0 +1,318 @@
/*
* phy-core.c -- Generic Phy framework.
*
* Copyright (C) 2014 Lucas Stach <l.stach@pengutronix.de>
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Kishon Vijay Abraham I <kishon@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <common.h>
#include <malloc.h>
#include <linux/phy/phy.h>
static LIST_HEAD(phy_provider_list);
static int phy_ida;
/**
* phy_create() - create a new phy
* @dev: device that is creating the new phy
* @node: device node of the phy
* @ops: function pointers for performing phy operations
* @init_data: contains the list of PHY consumers or NULL
*
* Called to create a phy using phy framework.
*/
struct phy *phy_create(struct device_d *dev, struct device_node *node,
const struct phy_ops *ops,
struct phy_init_data *init_data)
{
int ret;
int id;
struct phy *phy;
if (WARN_ON(!dev))
return ERR_PTR(-EINVAL);
phy = kzalloc(sizeof(*phy), GFP_KERNEL);
if (!phy)
return ERR_PTR(-ENOMEM);
id = phy_ida++;
snprintf(phy->dev.name, MAX_DRIVER_NAME, "phy");
phy->dev.id = id;
phy->dev.parent = dev;
phy->dev.device_node = node ?: dev->device_node;
phy->id = id;
phy->ops = ops;
phy->init_data = init_data;
ret = register_device(&phy->dev);
if (ret)
goto free_ida;
return phy;
free_ida:
phy_ida--;
kfree(phy);
return ERR_PTR(ret);
}
/**
* __of_phy_provider_register() - create/register phy provider with the framework
* @dev: struct device of the phy provider
* @owner: the module owner containing of_xlate
* @of_xlate: function pointer to obtain phy instance from phy provider
*
* Creates struct phy_provider from dev and of_xlate function pointer.
* This is used in the case of dt boot for finding the phy instance from
* phy provider.
*/
struct phy_provider *__of_phy_provider_register(struct device_d *dev,
struct phy * (*of_xlate)(struct device_d *dev,
struct of_phandle_args *args))
{
struct phy_provider *phy_provider;
phy_provider = kzalloc(sizeof(*phy_provider), GFP_KERNEL);
if (!phy_provider)
return ERR_PTR(-ENOMEM);
phy_provider->dev = dev;
phy_provider->of_xlate = of_xlate;
list_add_tail(&phy_provider->list, &phy_provider_list);
return phy_provider;
}
/**
* of_phy_provider_unregister() - unregister phy provider from the framework
* @phy_provider: phy provider returned by of_phy_provider_register()
*
* Removes the phy_provider created using of_phy_provider_register().
*/
void of_phy_provider_unregister(struct phy_provider *phy_provider)
{
if (IS_ERR(phy_provider))
return;
list_del(&phy_provider->list);
kfree(phy_provider);
}
int phy_init(struct phy *phy)
{
int ret;
if (!phy)
return 0;
if (phy->init_count == 0 && phy->ops->init) {
ret = phy->ops->init(phy);
if (ret < 0) {
dev_err(&phy->dev, "phy init failed --> %d\n", ret);
return ret;
}
}
++phy->init_count;
return 0;
}
int phy_exit(struct phy *phy)
{
int ret;
if (!phy)
return 0;
if (phy->init_count == 1 && phy->ops->exit) {
ret = phy->ops->exit(phy);
if (ret < 0) {
dev_err(&phy->dev, "phy exit failed --> %d\n", ret);
return ret;
}
}
--phy->init_count;
return 0;
}
int phy_power_on(struct phy *phy)
{
int ret;
if (!phy)
return 0;
if (phy->pwr) {
ret = regulator_enable(phy->pwr);
if (ret)
return ret;
}
if (phy->power_count == 0 && phy->ops->power_on) {
ret = phy->ops->power_on(phy);
if (ret < 0) {
dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
goto out;
}
} else {
ret = 0; /* Override possible ret == -ENOTSUPP */
}
++phy->power_count;
return 0;
out:
if (phy->pwr)
regulator_disable(phy->pwr);
return ret;
}
int phy_power_off(struct phy *phy)
{
int ret;
if (!phy)
return 0;
if (phy->power_count == 1 && phy->ops->power_off) {
ret = phy->ops->power_off(phy);
if (ret < 0) {
dev_err(&phy->dev, "phy poweroff failed --> %d\n", ret);
return ret;
}
}
--phy->power_count;
if (phy->pwr)
regulator_disable(phy->pwr);
return 0;
}
static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
{
struct phy_provider *phy_provider;
struct device_node *child;
list_for_each_entry(phy_provider, &phy_provider_list, list) {
if (phy_provider->dev->device_node == node)
return phy_provider;
for_each_child_of_node(phy_provider->dev->device_node, child)
if (child == node)
return phy_provider;
}
return ERR_PTR(-ENODEV);
}
/**
* _of_phy_get() - lookup and obtain a reference to a phy by phandle
* @np: device_node for which to get the phy
* @index: the index of the phy
*
* Returns the phy associated with the given phandle value,
* after getting a refcount to it or -ENODEV if there is no such phy or
* -EPROBE_DEFER if there is a phandle to the phy, but the device is
* not yet loaded. This function uses of_xlate call back function provided
* while registering the phy_provider to find the phy instance.
*/
static struct phy *_of_phy_get(struct device_node *np, int index)
{
int ret;
struct phy_provider *phy_provider;
struct of_phandle_args args;
ret = of_parse_phandle_with_args(np, "phys", "#phy-cells",
index, &args);
if (ret)
return ERR_PTR(-ENODEV);
phy_provider = of_phy_provider_lookup(args.np);
if (IS_ERR(phy_provider)) {
return ERR_PTR(-ENODEV);
}
return phy_provider->of_xlate(phy_provider->dev, &args);
}
/**
* of_phy_get() - lookup and obtain a reference to a phy using a device_node.
* @np: device_node for which to get the phy
* @con_id: name of the phy from device's point of view
*
* Returns the phy driver, after getting a refcount to it; or
* -ENODEV if there is no such phy. The caller is responsible for
* calling phy_put() to release that count.
*/
struct phy *of_phy_get(struct device_node *np, const char *con_id)
{
int index = 0;
if (con_id)
index = of_property_match_string(np, "phy-names", con_id);
return _of_phy_get(np, index);
}
/**
* phy_get() - lookup and obtain a reference to a phy.
* @dev: device that requests this phy
* @string: the phy name as given in the dt data or the name of the controller
* port for non-dt case
*
* Returns the phy driver, after getting a refcount to it; or
* -ENODEV if there is no such phy. The caller is responsible for
* calling phy_put() to release that count.
*/
struct phy *phy_get(struct device_d *dev, const char *string)
{
int index = 0;
struct phy *phy = ERR_PTR(-ENODEV);
if (string == NULL) {
dev_warn(dev, "missing string\n");
return ERR_PTR(-EINVAL);
}
if (dev->device_node) {
index = of_property_match_string(dev->device_node, "phy-names",
string);
phy = _of_phy_get(dev->device_node, index);
}
return phy;
}
/**
* phy_optional_get() - lookup and obtain a reference to an optional phy.
* @dev: device that requests this phy
* @string: the phy name as given in the dt data or the name of the controller
* port for non-dt case
*
* Returns the phy driver, after getting a refcount to it; or
* NULL if there is no such phy. The caller is responsible for
* calling phy_put() to release that count.
*/
struct phy *phy_optional_get(struct device_d *dev, const char *string)
{
struct phy *phy = phy_get(dev, string);
if (PTR_ERR(phy) == -ENODEV)
phy = NULL;
return phy;
}

View File

@ -60,6 +60,14 @@ config PINCTRL_TEGRA30
help
The pinmux controller found on the Tegra 30+ line of SoCs.
config PINCTRL_TEGRA_XUSB
bool
default y if ARCH_TEGRA_124_SOC
select GENERIC_PHY
help
The pinmux controller found on the Tegra 124 line of SoCs used for
the SerDes lanes.
source drivers/pinctrl/mvebu/Kconfig
endif

View File

@ -7,5 +7,6 @@ obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o
obj-$(CONFIG_ARCH_MVEBU) += mvebu/

View File

@ -0,0 +1,519 @@
/*
* Copyright (C) 2014 Lucas Stach <l.stach@pengutronix.de>
*
* Partly based on code
* Copyright (C) 2014, NVIDIA CORPORATION.
*
* 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 <common.h>
#include <clock.h>
#include <init.h>
#include <io.h>
#include <malloc.h>
#include <pinctrl.h>
#include <linux/err.h>
#include <linux/reset.h>
#include <linux/phy/phy.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
#define XUSB_PADCTL_ELPG_PROGRAM 0x01c
#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12)
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1)
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6)
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3)
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1)
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0)
#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148
#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
struct tegra_xusb_padctl_soc {
const struct tegra_xusb_padctl_lane *lanes;
unsigned int num_lanes;
};
struct tegra_xusb_padctl_lane {
const char *name;
unsigned int offset;
unsigned int shift;
unsigned int mask;
unsigned int iddq;
const char **funcs;
unsigned int num_funcs;
};
struct tegra_xusb_padctl {
struct device_d *dev;
void __iomem *regs;
struct reset_control *rst;
const struct tegra_xusb_padctl_soc *soc;
struct pinctrl_device pinctrl;
struct phy_provider *provider;
struct phy *phys[2];
unsigned int enable;
};
static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value,
unsigned long offset)
{
writel(value, padctl->regs + offset);
}
static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
unsigned long offset)
{
return readl(padctl->regs + offset);
}
static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
{
u32 value;
if (padctl->enable++ > 0)
return 0;
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
udelay(100);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
udelay(100);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
return 0;
}
static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
{
u32 value;
if (WARN_ON(padctl->enable == 0))
return 0;
if (--padctl->enable > 0)
return 0;
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
udelay(100);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
udelay(100);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
return 0;
}
static int tegra_xusb_phy_init(struct phy *phy)
{
struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
return tegra_xusb_padctl_enable(padctl);
}
static int tegra_xusb_phy_exit(struct phy *phy)
{
struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
return tegra_xusb_padctl_disable(padctl);
}
static int pcie_phy_power_on(struct phy *phy)
{
struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
int err;
u32 value;
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN |
XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN |
XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
err = wait_on_timeout(50 * MSECOND,
padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1) &
XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET);
return err;
}
static int pcie_phy_power_off(struct phy *phy)
{
struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
u32 value;
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
return 0;
}
static const struct phy_ops pcie_phy_ops = {
.init = tegra_xusb_phy_init,
.exit = tegra_xusb_phy_exit,
.power_on = pcie_phy_power_on,
.power_off = pcie_phy_power_off,
};
static int sata_phy_power_on(struct phy *phy)
{
struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
int err;
u32 value;
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
err = wait_on_timeout(50 * MSECOND,
padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1) &
XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET);
return err;
}
static int sata_phy_power_off(struct phy *phy)
{
struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
u32 value;
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
return 0;
}
static const struct phy_ops sata_phy_ops = {
.init = tegra_xusb_phy_init,
.exit = tegra_xusb_phy_exit,
.power_on = sata_phy_power_on,
.power_off = sata_phy_power_off,
};
static struct phy *tegra_xusb_padctl_xlate(struct device_d *dev,
struct of_phandle_args *args)
{
struct tegra_xusb_padctl *padctl = dev->priv;
unsigned int index = args->args[0];
if (args->args_count <= 0)
return ERR_PTR(-EINVAL);
if (index >= ARRAY_SIZE(padctl->phys))
return ERR_PTR(-EINVAL);
return padctl->phys[index];
}
static int pinctrl_tegra_xusb_set_state(struct pinctrl_device *pdev,
struct device_node *np)
{
struct tegra_xusb_padctl *padctl =
container_of(pdev, struct tegra_xusb_padctl, pinctrl);
struct device_node *childnode;
int iddq = -1, i, j, k;
const char *lanes, *func = NULL;
const struct tegra_xusb_padctl_lane *lane = NULL;
u32 val;
/*
* At first look if the node we are pointed at has children,
* which we may want to visit.
*/
list_for_each_entry(childnode, &np->children, parent_list)
pinctrl_tegra_xusb_set_state(pdev, childnode);
/* read relevant state from devicetree */
of_property_read_string(np, "nvidia,function", &func);
of_property_read_u32_array(np, "nvidia,iddq", &iddq, 1);
/* iterate over all lanes referenced in the dt node */
for (i = 0; ; i++) {
if (of_property_read_string_index(np, "nvidia,lanes", i, &lanes))
break;
for (j = 0; j < padctl->soc->num_lanes; j++) {
if (!strcmp(lanes, padctl->soc->lanes[j].name)) {
lane = &padctl->soc->lanes[j];
break;
}
}
/* if no matching lane is found */
if (j == padctl->soc->num_lanes) {
/* nothing matching found, warn and bail out */
dev_warn(padctl->pinctrl.dev,
"invalid lane %s referenced in node %s\n",
lanes, np->name);
continue;
}
if (func) {
for (k = 0; k < lane->num_funcs; k++) {
if (!strcmp(func, lane->funcs[k]))
break;
}
if (k < lane->num_funcs) {
val = padctl_readl(padctl, lane->offset);
val &= ~(lane->mask << lane->shift);
val |= k << lane->shift;
padctl_writel(padctl, val, lane->offset);
} else {
dev_warn(padctl->pinctrl.dev,
"invalid function %s for lane %s in node %s\n",
func, lane->name, np->name);
}
}
if (iddq >= 0) {
if (lane->iddq) {
val = padctl_readl(padctl, lane->offset);
if (iddq)
val &= ~BIT(lane->iddq);
else
val |= BIT(lane->iddq);
padctl_writel(padctl, val, lane->offset);
} else {
dev_warn(padctl->pinctrl.dev,
"invalid iddq setting for lane %s in node %s\n",
lane->name, np->name);
}
}
}
return 0;
}
static struct pinctrl_ops pinctrl_tegra_xusb_ops = {
.set_state = pinctrl_tegra_xusb_set_state,
};
static int pinctrl_tegra_xusb_probe(struct device_d *dev)
{
struct tegra_xusb_padctl *padctl;
struct phy *phy;
int err;
padctl = xzalloc(sizeof(*padctl));
dev->priv = padctl;
padctl->dev = dev;
dev_get_drvdata(dev, (unsigned long *)&padctl->soc);
padctl->regs = dev_request_mem_region(dev, 0);
if (IS_ERR(padctl->regs)) {
dev_err(dev, "Could not get iomem region\n");
return PTR_ERR(padctl->regs);
}
padctl->rst = reset_control_get(dev, NULL);
if (IS_ERR(padctl->rst))
return PTR_ERR(padctl->rst);
err = reset_control_deassert(padctl->rst);
if (err < 0)
return err;
padctl->pinctrl.dev = dev;
padctl->pinctrl.ops = &pinctrl_tegra_xusb_ops;
err = pinctrl_register(&padctl->pinctrl);
if (err) {
dev_err(dev, "failed to register pincontrol\n");
err = -ENODEV;
goto reset;
}
phy = phy_create(dev, NULL, &pcie_phy_ops, NULL);
if (IS_ERR(phy)) {
err = PTR_ERR(phy);
goto unregister;
}
padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
phy_set_drvdata(phy, padctl);
phy = phy_create(dev, NULL, &sata_phy_ops, NULL);
if (IS_ERR(phy)) {
err = PTR_ERR(phy);
goto unregister;
}
padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy;
phy_set_drvdata(phy, padctl);
padctl->provider = of_phy_provider_register(dev, tegra_xusb_padctl_xlate);
if (IS_ERR(padctl->provider)) {
err = PTR_ERR(padctl->provider);
dev_err(dev, "failed to register PHYs: %d\n", err);
goto unregister;
}
return 0;
unregister:
pinctrl_unregister(&padctl->pinctrl);
reset:
reset_control_assert(padctl->rst);
return err;
}
static const char *tegra124_otg_functions[] = {
"snps",
"xusb",
"uart",
"rsvd",
};
static const char *tegra124_usb_functions[] = {
"snps",
"xusb",
};
static const char *tegra124_pci_functions[] = {
"pcie",
"usb3",
"sata",
"rsvd",
};
#define TEGRA124_LANE(_name, _offs, _shift, _mask, _iddq, _funcs, _num) \
{ \
.name = _name, \
.offset = _offs, \
.shift = _shift, \
.mask = _mask, \
.iddq = _iddq, \
.num_funcs = _num, \
.funcs = tegra124_##_funcs##_functions, \
}
static const struct tegra_xusb_padctl_lane tegra124_lanes[] = {
TEGRA124_LANE("otg-0", 0x004, 0, 0x3, 0, otg, 4),
TEGRA124_LANE("otg-1", 0x004, 2, 0x3, 0, otg, 4),
TEGRA124_LANE("otg-2", 0x004, 4, 0x3, 0, otg, 4),
TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb, 2),
TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb, 2),
TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb, 2),
TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci, 4),
TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci, 4),
TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci, 4),
TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci, 4),
TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci, 4),
TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci, 4),
};
static const struct tegra_xusb_padctl_soc tegra124_soc = {
.num_lanes = ARRAY_SIZE(tegra124_lanes),
.lanes = tegra124_lanes,
};
static __maybe_unused struct of_device_id pinctrl_tegra_xusb_dt_ids[] = {
{
.compatible = "nvidia,tegra124-xusb-padctl",
.data = (unsigned long)&tegra124_soc,
}, {
/* sentinel */
}
};
static struct driver_d pinctrl_tegra_xusb_driver = {
.name = "pinctrl-tegra-xusb",
.probe = pinctrl_tegra_xusb_probe,
.of_compatible = DRV_OF_COMPAT(pinctrl_tegra_xusb_dt_ids),
};
static int pinctrl_tegra_xusb_init(void)
{
return platform_driver_register(&pinctrl_tegra_xusb_driver);
}
postcore_initcall(pinctrl_tegra_xusb_init);

View File

@ -320,10 +320,14 @@ static int pinctrl_tegra20_probe(struct device_d *dev)
ctrl->pinctrl.ops = &pinctrl_tegra20_ops;
ret = pinctrl_register(&ctrl->pinctrl);
if (ret)
if (ret) {
free(ctrl);
return ret;
}
return ret;
of_pinctrl_select_state(dev->device_node, "boot");
return 0;
}
static __maybe_unused struct of_device_id pinctrl_tegra20_dt_ids[] = {

View File

@ -897,10 +897,14 @@ static int pinctrl_tegra30_probe(struct device_d *dev)
ctrl->pinctrl.ops = &pinctrl_tegra30_ops;
ret = pinctrl_register(&ctrl->pinctrl);
if (ret)
if (ret) {
free(ctrl);
return ret;
}
return ret;
of_pinctrl_select_state(dev->device_node, "boot");
return 0;
}
static __maybe_unused struct of_device_id pinctrl_tegra30_dt_ids[] = {

View File

@ -311,6 +311,11 @@ static __maybe_unused struct ns16550_drvdata jz_drvdata = {
.init_port = ns16550_jz_init_port,
};
static __maybe_unused struct ns16550_drvdata tegra_drvdata = {
.init_port = ns16550_serial_init_port,
.linux_console_name = "ttyS",
};
static int ns16550_init_iomem(struct device_d *dev, struct ns16550_priv *priv)
{
struct resource *res;
@ -418,6 +423,7 @@ static int ns16550_probe(struct device_d *dev)
ret = PTR_ERR(priv->clk);
goto err;
}
clk_enable(priv->clk);
priv->plat.clock = clk_get_rate(priv->clk);
}
@ -476,6 +482,12 @@ static struct of_device_id ns16550_serial_dt_ids[] = {
.data = (unsigned long)&omap_drvdata,
},
#endif
#if IS_ENABLED(CONFIG_ARCH_TEGRA)
{
.compatible = "nvidia,tegra20-uart",
.data = (unsigned long)&tegra_drvdata,
},
#endif
#if IS_ENABLED(CONFIG_MACH_MIPS_XBURST)
{
.compatible = "ingenic,jz4740-uart",

View File

@ -114,8 +114,15 @@ struct pci_dev {
};
#define to_pci_dev(dev) container_of(dev, struct pci_dev, dev)
enum {
PCI_BUS_RESOURCE_IO = 0,
PCI_BUS_RESOURCE_MEM = 1,
PCI_BUS_RESOURCE_MEM_PREF = 2,
PCI_BUS_RESOURCE_BUSN = 3,
};
struct pci_bus {
struct pci_controller *host; /* associated host controller */
struct device_d *parent;
struct list_head node; /* node in list of buses */
struct list_head children; /* list of child buses */
struct list_head devices; /* list of devices on this bus */
@ -152,10 +159,12 @@ extern struct pci_ops *pci_ops;
*/
struct pci_controller {
struct pci_controller *next;
struct device_d *parent;
struct pci_bus *bus;
struct pci_ops *pci_ops;
struct resource *mem_resource;
struct resource *mem_pref_resource;
unsigned long mem_offset;
struct resource *io_resource;
unsigned long io_offset;

View File

@ -107,4 +107,32 @@
#define PCI_ROM_ADDRESS_ENABLE 0x01
#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
/* Header type 1 (PCI-to-PCI bridges) */
#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
#define PCI_IO_LIMIT 0x1d
#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */
#define PCI_IO_RANGE_TYPE_16 0x00
#define PCI_IO_RANGE_TYPE_32 0x01
#define PCI_IO_RANGE_MASK (~0x0fUL) /* Standard 4K I/O windows */
#define PCI_IO_1K_RANGE_MASK (~0x03UL) /* Intel 1K I/O windows */
#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */
#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
#define PCI_MEMORY_LIMIT 0x22
#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
#define PCI_MEMORY_RANGE_MASK (~0x0fUL)
#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
#define PCI_PREF_MEMORY_LIMIT 0x26
#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL
#define PCI_PREF_RANGE_TYPE_32 0x00
#define PCI_PREF_RANGE_TYPE_64 0x01
#define PCI_PREF_RANGE_MASK (~0x0fUL)
#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */
#define PCI_PREF_LIMIT_UPPER32 0x2c
#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
#define PCI_IO_LIMIT_UPPER16 0x32
#endif /* LINUX_PCI_REGS_H */

240
include/linux/phy/phy.h Normal file
View File

@ -0,0 +1,240 @@
/*
* phy.h -- generic phy header file
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Kishon Vijay Abraham I <kishon@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __DRIVERS_PHY_H
#define __DRIVERS_PHY_H
#include <linux/err.h>
#include <of.h>
#include <regulator.h>
struct phy;
/**
* struct phy_ops - set of function pointers for performing phy operations
* @init: operation to be performed for initializing phy
* @exit: operation to be performed while exiting
* @power_on: powering on the phy
* @power_off: powering off the phy
* @owner: the module owner containing the ops
*/
struct phy_ops {
int (*init)(struct phy *phy);
int (*exit)(struct phy *phy);
int (*power_on)(struct phy *phy);
int (*power_off)(struct phy *phy);
};
/**
* struct phy_attrs - represents phy attributes
* @bus_width: Data path width implemented by PHY
*/
struct phy_attrs {
u32 bus_width;
};
/**
* struct phy - represents the phy device
* @dev: phy device
* @id: id of the phy device
* @ops: function pointers for performing phy operations
* @init_data: list of PHY consumers (non-dt only)
* @mutex: mutex to protect phy_ops
* @init_count: used to protect when the PHY is used by multiple consumers
* @power_count: used to protect when the PHY is used by multiple consumers
* @phy_attrs: used to specify PHY specific attributes
*/
struct phy {
struct device_d dev;
int id;
const struct phy_ops *ops;
struct phy_init_data *init_data;
int init_count;
int power_count;
struct phy_attrs attrs;
struct regulator *pwr;
};
/**
* struct phy_provider - represents the phy provider
* @dev: phy provider device
* @owner: the module owner having of_xlate
* @of_xlate: function pointer to obtain phy instance from phy pointer
* @list: to maintain a linked list of PHY providers
*/
struct phy_provider {
struct device_d *dev;
struct list_head list;
struct phy * (*of_xlate)(struct device_d *dev,
struct of_phandle_args *args);
};
/**
* struct phy_consumer - represents the phy consumer
* @dev_name: the device name of the controller that will use this PHY device
* @port: name given to the consumer port
*/
struct phy_consumer {
const char *dev_name;
const char *port;
};
/**
* struct phy_init_data - contains the list of PHY consumers
* @num_consumers: number of consumers for this PHY device
* @consumers: list of PHY consumers
*/
struct phy_init_data {
unsigned int num_consumers;
struct phy_consumer *consumers;
};
#define PHY_CONSUMER(_dev_name, _port) \
{ \
.dev_name = _dev_name, \
.port = _port, \
}
#define to_phy(dev) (container_of((dev), struct phy, dev))
#define of_phy_provider_register(dev, xlate) \
__of_phy_provider_register((dev), (xlate))
static inline void phy_set_drvdata(struct phy *phy, void *data)
{
phy->dev.priv = data;
}
static inline void *phy_get_drvdata(struct phy *phy)
{
return phy->dev.priv;
}
#if IS_ENABLED(CONFIG_GENERIC_PHY)
int phy_init(struct phy *phy);
int phy_exit(struct phy *phy);
int phy_power_on(struct phy *phy);
int phy_power_off(struct phy *phy);
static inline int phy_get_bus_width(struct phy *phy)
{
return phy->attrs.bus_width;
}
static inline void phy_set_bus_width(struct phy *phy, int bus_width)
{
phy->attrs.bus_width = bus_width;
}
struct phy *phy_get(struct device_d *dev, const char *string);
struct phy *phy_optional_get(struct device_d *dev, const char *string);
void phy_put(struct phy *phy);
struct phy *of_phy_get(struct device_node *np, const char *con_id);
struct phy *of_phy_simple_xlate(struct device_d *dev,
struct of_phandle_args *args);
struct phy *phy_create(struct device_d *dev, struct device_node *node,
const struct phy_ops *ops,
struct phy_init_data *init_data);
void phy_destroy(struct phy *phy);
struct phy_provider *__of_phy_provider_register(struct device_d *dev,
struct phy * (*of_xlate)(struct device_d *dev,
struct of_phandle_args *args));
void of_phy_provider_unregister(struct phy_provider *phy_provider);
#else
static inline int phy_init(struct phy *phy)
{
if (!phy)
return 0;
return -ENOSYS;
}
static inline int phy_exit(struct phy *phy)
{
if (!phy)
return 0;
return -ENOSYS;
}
static inline int phy_power_on(struct phy *phy)
{
if (!phy)
return 0;
return -ENOSYS;
}
static inline int phy_power_off(struct phy *phy)
{
if (!phy)
return 0;
return -ENOSYS;
}
static inline int phy_get_bus_width(struct phy *phy)
{
return -ENOSYS;
}
static inline void phy_set_bus_width(struct phy *phy, int bus_width)
{
return;
}
static inline struct phy *phy_get(struct device_d *dev, const char *string)
{
return ERR_PTR(-ENOSYS);
}
static inline struct phy *phy_optional_get(struct device_d *dev,
const char *string)
{
return ERR_PTR(-ENOSYS);
}
static inline void phy_put(struct phy *phy)
{
}
static inline struct phy *of_phy_get(struct device_node *np, const char *con_id)
{
return ERR_PTR(-ENOSYS);
}
static inline struct phy *of_phy_simple_xlate(struct device_d *dev,
struct of_phandle_args *args)
{
return ERR_PTR(-ENOSYS);
}
static inline struct phy *phy_create(struct device_d *dev,
struct device_node *node,
const struct phy_ops *ops,
struct phy_init_data *init_data)
{
return ERR_PTR(-ENOSYS);
}
static inline void phy_destroy(struct phy *phy)
{
}
static inline struct phy_provider *__of_phy_provider_register(
struct device_d *dev, struct phy * (*of_xlate)(
struct device_d *dev, struct of_phandle_args *args))
{
return ERR_PTR(-ENOSYS);
}
static inline void of_phy_provider_unregister(struct phy_provider *phy_provider)
{
}
#endif
#endif /* __DRIVERS_PHY_H */

View File

@ -4,6 +4,38 @@
#include <common.h>
#include <of.h>
struct of_pci_range_parser {
struct device_node *node;
const __be32 *range;
const __be32 *end;
int np;
int pna;
};
struct of_pci_range {
u32 pci_space;
u64 pci_addr;
u64 cpu_addr;
u64 size;
u32 flags;
};
#define for_each_of_pci_range(parser, range) \
for (; of_pci_range_parser_one(parser, range);)
static inline void of_pci_range_to_resource(struct of_pci_range *range,
struct device_node *np,
struct resource *res)
{
res->flags = range->flags;
res->start = range->cpu_addr;
res->end = range->cpu_addr + range->size - 1;
res->parent = NULL;
INIT_LIST_HEAD(&res->children);
INIT_LIST_HEAD(&res->sibling);
res->name = np->full_name;
}
#ifndef pci_address_to_pio
static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
#endif
@ -69,4 +101,29 @@ static inline void __iomem *of_iomap(struct device_node *np, int index)
#endif /* CONFIG_OFTREE */
#ifdef CONFIG_OF_PCI
extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node);
extern struct of_pci_range *of_pci_range_parser_one(
struct of_pci_range_parser *parser,
struct of_pci_range *range);
#else
static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node)
{
return -1;
}
static inline struct of_pci_range *of_pci_range_parser_one(
struct of_pci_range_parser *parser,
struct of_pci_range *range)
{
return NULL;
}
#endif /* CONFIG_OF_PCI */
#endif /* __OF_ADDRESS_H */

View File

@ -20,6 +20,7 @@ enum reset_src_type {
RESET_WDG, /* watchdog */
RESET_WKE, /* wake-up (some SoCs can handle this) */
RESET_JTAG, /* JTAG reset */
RESET_THERM, /* SoC shut down because of overtemperature */
};
#ifdef CONFIG_RESET_SOURCE