Merge branch 'for-next/marvell'
Conflicts: arch/arm/dts/Makefile
This commit is contained in:
commit
2331b1d8e8
|
@ -87,6 +87,7 @@ config ARCH_MVEBU
|
|||
select CLKDEV_LOOKUP
|
||||
select GPIOLIB
|
||||
select HAS_DEBUG_LL
|
||||
select MVEBU_MBUS
|
||||
select OFTREE
|
||||
|
||||
config ARCH_MXS
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <asm/barebox-arm-head.h>
|
||||
#include <mach/lowlevel.h>
|
||||
|
||||
extern char __dtb_dove_cubox_start[];
|
||||
extern char __dtb_dove_cubox_bb_start[];
|
||||
|
||||
ENTRY_FUNCTION(start_solidrun_cubox, r0, r1, r2)
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ ENTRY_FUNCTION(start_solidrun_cubox, r0, r1, r2)
|
|||
|
||||
arm_cpu_lowlevel_init();
|
||||
|
||||
fdt = (uint32_t)__dtb_dove_cubox_start - get_runtime_offset();
|
||||
fdt = (uint32_t)__dtb_dove_cubox_bb_start - get_runtime_offset();
|
||||
|
||||
mvebu_barebox_entry(fdt);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ dtb-$(CONFIG_ARCH_IMX6) += imx6q-gk802.dtb \
|
|||
imx6q-nitrogen6x.dtb \
|
||||
imx6dl-nitrogen6x.dtb \
|
||||
imx6q-udoo.dtb
|
||||
dtb-$(CONFIG_ARCH_MVEBU) += dove-cubox.dtb
|
||||
dtb-$(CONFIG_ARCH_MVEBU) += dove-cubox-bb.dtb
|
||||
dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_cyclone5_sockit.dtb \
|
||||
socfpga_cyclone5_socrates.dtb
|
||||
dtb-$(CONFIG_ARCH_TEGRA) += \
|
||||
|
@ -45,7 +45,7 @@ pbl-$(CONFIG_MACH_DFI_FS700_M60) += imx6q-dfi-fs700-m60-6q.dtb.o imx6dl-dfi-fs70
|
|||
pbl-$(CONFIG_MACH_PCM051) += am335x-phytec-phycore.dtb.o
|
||||
pbl-$(CONFIG_MACH_PHYTEC_PFLA02) += imx6q-phytec-pbab01.dtb.o
|
||||
pbl-$(CONFIG_MACH_REALQ7) += imx6q-dmo-edmqmx6.dtb.o
|
||||
pbl-$(CONFIG_MACH_SOLIDRUN_CUBOX) += dove-cubox.dtb.o
|
||||
pbl-$(CONFIG_MACH_SOLIDRUN_CUBOX) += dove-cubox-bb.dtb.o
|
||||
pbl-$(CONFIG_MACH_GK802) += imx6q-gk802.dtb.o
|
||||
pbl-$(CONFIG_MACH_TORADEX_COLIBRI_T20_IRIS) += tegra20-colibri-iris.dtb.o
|
||||
pbl-$(CONFIG_MACH_TOSHIBA_AC100) += tegra20-paz00.dtb.o
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Barebox specific DT overlay for SolidRun CuBox
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*/
|
||||
|
||||
#include "dove-cubox.dts"
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
linux,stdout-path = &uart0;
|
||||
};
|
||||
|
||||
leds {
|
||||
power {
|
||||
barebox,default-trigger = "heartbeat";
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,19 +1,18 @@
|
|||
/dts-v1/;
|
||||
|
||||
/include/ "dove.dtsi"
|
||||
#include "dove.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "solidrun,cubox", "marvell,dove";
|
||||
model = "SolidRun CuBox";
|
||||
compatible = "solidrun,cubox", "marvell,dove";
|
||||
|
||||
memory {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x3f000000>;
|
||||
reg = <0x00000000 0x40000000>;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200n8 earlyprintk";
|
||||
linux,stdout-path = &uart0;
|
||||
};
|
||||
|
||||
leds {
|
||||
|
@ -24,7 +23,7 @@
|
|||
power {
|
||||
label = "Power";
|
||||
gpios = <&gpio0 18 1>;
|
||||
linux,default-trigger = "default-on";
|
||||
default-state = "keep";
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -43,6 +42,8 @@
|
|||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
gpio = <&gpio0 1 0>;
|
||||
pinctrl-0 = <&pmx_gpio_1>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -55,24 +56,27 @@
|
|||
};
|
||||
};
|
||||
|
||||
video-card {
|
||||
compatible = "marvell,dove-video-card";
|
||||
reg = <0x3f000000 0x1000000>;
|
||||
marvell,external-encoder = <&tda19988>;
|
||||
ir_recv: ir-receiver {
|
||||
compatible = "gpio-ir-receiver";
|
||||
gpios = <&gpio0 19 1>;
|
||||
pinctrl-0 = <&pmx_gpio_19>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 { status = "okay"; };
|
||||
&sata0 { status = "okay"; };
|
||||
&mdio { status = "okay"; };
|
||||
ð { status = "okay"; };
|
||||
|
||||
&lcd0 {
|
||||
status = "okay";
|
||||
clocks = <&si5351 0>;
|
||||
ðphy {
|
||||
compatible = "marvell,88e1310";
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
clock-frequency = <400000>;
|
||||
clock-frequency = <100000>;
|
||||
|
||||
si5351: clock-generator {
|
||||
compatible = "silabs,si5351a-msop";
|
||||
|
@ -95,32 +99,21 @@
|
|||
silabs,pll-master;
|
||||
};
|
||||
|
||||
clkout1 {
|
||||
reg = <1>;
|
||||
clkout2 {
|
||||
reg = <2>;
|
||||
silabs,drive-strength = <8>;
|
||||
silabs,multisynth-source = <1>;
|
||||
silabs,clock-source = <0>;
|
||||
silabs,pll-master;
|
||||
};
|
||||
|
||||
clkout2 {
|
||||
reg = <2>;
|
||||
silabs,multisynth-source = <1>;
|
||||
silabs,clock-source = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
tda19988: hdmi-encoder@70 {
|
||||
compatible = "nxp,tda1998x";
|
||||
reg = <0x70>;
|
||||
};
|
||||
};
|
||||
|
||||
&sdio0 {
|
||||
status = "okay";
|
||||
bus-width = <4>;
|
||||
/* sdio0 card detect is connected to wrong pin on CuBox */
|
||||
cd-gpios = <&gpio0 12 1>;
|
||||
pinctrl-0 = <&pmx_sdio0 &pmx_gpio_12>;
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
|
@ -128,28 +121,16 @@
|
|||
|
||||
/* spi0.0: 4M Flash Winbond W25Q32BV */
|
||||
spi-flash@0 {
|
||||
compatible = "winbond,w25q32", "m25p80";
|
||||
compatible = "st,w25q32";
|
||||
spi-max-frequency = <20000000>;
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
pinctrl-0 = <&pmx_gpio_1 &pmx_gpio_12>;
|
||||
&audio1 {
|
||||
status = "okay";
|
||||
clocks = <&gate_clk 13>, <&si5351 2>;
|
||||
clock-names = "internal", "extclk";
|
||||
pinctrl-0 = <&pmx_audio1_i2s1_spdifo &pmx_audio1_extclk>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
pmx_gpio_1: pmx-gpio-1 {
|
||||
marvell,pins = "mpp1";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_12: pmx-gpio-12 {
|
||||
marvell,pins = "mpp12";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_18: pmx-gpio-18 {
|
||||
marvell,pins = "mpp18";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/include/ "skeleton.dtsi"
|
||||
|
||||
#define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16))
|
||||
|
||||
/ {
|
||||
compatible = "marvell,dove";
|
||||
model = "Marvell Armada 88AP510 SoC";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
aliases {
|
||||
gpio0 = &gpio0;
|
||||
|
@ -12,275 +13,614 @@
|
|||
gpio2 = &gpio2;
|
||||
};
|
||||
|
||||
soc@f1000000 {
|
||||
compatible = "simple-bus";
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu0: cpu@0 {
|
||||
compatible = "marvell,pj4a", "marvell,sheeva-v7";
|
||||
device_type = "cpu";
|
||||
next-level-cache = <&l2>;
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
l2: l2-cache {
|
||||
compatible = "marvell,tauros2-cache";
|
||||
marvell,tauros2-cache-features = <0>;
|
||||
};
|
||||
|
||||
mbus {
|
||||
compatible = "marvell,dove-mbus", "marvell,mbus", "simple-bus";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
interrupt-parent = <&intc>;
|
||||
controller = <&mbusc>;
|
||||
pcie-mem-aperture = <0xe0000000 0x10000000>; /* 256M MEM space */
|
||||
pcie-io-aperture = <0xf2000000 0x00200000>; /* 2M I/O space */
|
||||
|
||||
ranges = <0xc8000000 0xc8000000 0x0100000 /* CESA SRAM 1M */
|
||||
0xe0000000 0xe0000000 0x8000000 /* PCIe0 Mem 128M */
|
||||
0xe8000000 0xe8000000 0x8000000 /* PCIe1 Mem 128M */
|
||||
0xf0000000 0xf0000000 0x0100000 /* ScratchPad 1M */
|
||||
0x00000000 0xf1000000 0x1000000 /* SB/NB regs 16M */
|
||||
0xf2000000 0xf2000000 0x0100000 /* PCIe0 I/O 1M */
|
||||
0xf2100000 0xf2100000 0x0100000 /* PCIe0 I/O 1M */
|
||||
0xf8000000 0xf8000000 0x8000000>; /* BootROM 128M */
|
||||
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x0100000 /* MBUS regs 1M */
|
||||
MBUS_ID(0xf0, 0x02) 0 0xf1800000 0x1000000 /* AXI regs 16M */
|
||||
MBUS_ID(0x01, 0xfd) 0 0xf8000000 0x8000000 /* BootROM 128M */
|
||||
MBUS_ID(0x03, 0x01) 0 0xc8000000 0x0100000 /* CESA SRAM 1M */
|
||||
MBUS_ID(0x0d, 0x00) 0 0xf0000000 0x0100000>; /* PMU SRAM 1M */
|
||||
|
||||
l2: l2-cache {
|
||||
compatible = "marvell,tauros2-cache";
|
||||
marvell,tauros2-cache-features = <0>;
|
||||
};
|
||||
|
||||
timer: timer@20300 {
|
||||
compatible = "marvell,orion-timer";
|
||||
reg = <0x20300 0x30>;
|
||||
clocks = <&core_clk 0>;
|
||||
};
|
||||
|
||||
intc: interrupt-controller@20204 {
|
||||
compatible = "marvell,orion-intc";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
reg = <0x20204 0x04>, <0x20214 0x04>;
|
||||
};
|
||||
|
||||
core_clk: core-clocks@d0214 {
|
||||
compatible = "marvell,dove-core-clock";
|
||||
reg = <0xd0214 0x4>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
gate_clk: clock-gating-control@d0038 {
|
||||
compatible = "marvell,dove-gating-clock";
|
||||
reg = <0xd0038 0x4>;
|
||||
clocks = <&core_clk 0>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
thermal: thermal@d001c {
|
||||
compatible = "marvell,dove-thermal";
|
||||
reg = <0xd001c 0x0c>, <0xd005c 0x08>;
|
||||
};
|
||||
|
||||
uart0: serial@12000 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12000 0x20>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <7>;
|
||||
clocks = <&core_clk 0>;
|
||||
pcie: pcie-controller {
|
||||
compatible = "marvell,dove-pcie";
|
||||
status = "disabled";
|
||||
device_type = "pci";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
|
||||
msi-parent = <&intc>;
|
||||
bus-range = <0x00 0xff>;
|
||||
|
||||
ranges = <0x82000000 0x0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x2000
|
||||
0x82000000 0x0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x2000
|
||||
0x82000000 0x1 0x0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 Mem */
|
||||
0x81000000 0x1 0x0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 I/O */
|
||||
0x82000000 0x2 0x0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 Mem */
|
||||
0x81000000 0x2 0x0 MBUS_ID(0x08, 0xe0) 0 1 0>; /* Port 1.0 I/O */
|
||||
|
||||
pcie-port@0 {
|
||||
device_type = "pci";
|
||||
status = "disabled";
|
||||
assigned-addresses = <0x82000800 0 0x40000 0 0x2000>;
|
||||
reg = <0x0800 0 0 0 0>;
|
||||
clocks = <&gate_clk 4>;
|
||||
marvell,pcie-port = <0>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
ranges = <0x82000000 0 0 0x82000000 0x1 0 1 0
|
||||
0x81000000 0 0 0x81000000 0x1 0 1 0>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &intc 16>;
|
||||
};
|
||||
|
||||
pcie-port@1 {
|
||||
device_type = "pci";
|
||||
status = "disabled";
|
||||
assigned-addresses = <0x82002800 0 0x80000 0 0x2000>;
|
||||
reg = <0x1000 0 0 0 0>;
|
||||
clocks = <&gate_clk 5>;
|
||||
marvell,pcie-port = <1>;
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0
|
||||
0x81000000 0 0 0x81000000 0x2 0 1 0>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &intc 18>;
|
||||
};
|
||||
};
|
||||
|
||||
uart1: serial@12100 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12100 0x20>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <8>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart2: serial@12200 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12000 0x20>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <9>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart3: serial@12300 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12100 0x20>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <10>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gpio0: gpio@d0400 {
|
||||
compatible = "marvell,orion-gpio";
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
reg = <0xd0400 0x20>;
|
||||
ngpios = <32>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <12>, <13>, <14>, <60>;
|
||||
};
|
||||
|
||||
gpio1: gpio@d0420 {
|
||||
compatible = "marvell,orion-gpio";
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
reg = <0xd0420 0x20>;
|
||||
ngpios = <32>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <61>;
|
||||
};
|
||||
|
||||
gpio2: gpio@e8400 {
|
||||
compatible = "marvell,orion-gpio";
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
reg = <0xe8400 0x0c>;
|
||||
ngpios = <8>;
|
||||
};
|
||||
|
||||
pinctrl: pinctrl@d0200 {
|
||||
compatible = "marvell,dove-pinctrl";
|
||||
reg = <0xd0200 0x10>;
|
||||
clocks = <&gate_clk 22>;
|
||||
};
|
||||
|
||||
spi0: spi@10600 {
|
||||
compatible = "marvell,orion-spi";
|
||||
internal-regs {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cell-index = <0>;
|
||||
interrupts = <6>;
|
||||
reg = <0x10600 0x28>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
#size-cells = <1>;
|
||||
ranges = <0x00000000 MBUS_ID(0xf0, 0x01) 0 0x0100000 /* MBUS regs 1M */
|
||||
0x00800000 MBUS_ID(0xf0, 0x02) 0 0x1000000 /* AXI regs 16M */
|
||||
0xffffe000 MBUS_ID(0x03, 0x01) 0 0x0000800 /* CESA SRAM 2k */
|
||||
0xfffff000 MBUS_ID(0x0d, 0x00) 0 0x0000800>; /* PMU SRAM 2k */
|
||||
|
||||
spi1: spi@14600 {
|
||||
compatible = "marvell,dove-spi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cell-index = <1>;
|
||||
interrupts = <5>;
|
||||
reg = <0x14600 0x28>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2c0: i2c@11000 {
|
||||
compatible = "marvell,mv64xxx-i2c";
|
||||
reg = <0x11000 0x20>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <11>;
|
||||
clock-frequency = <400000>;
|
||||
timeout-ms = <1000>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
ehci0: usb-host@50000 {
|
||||
compatible = "marvell,orion-ehci";
|
||||
reg = <0x50000 0x1000>;
|
||||
interrupts = <24>;
|
||||
clocks = <&gate_clk 0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ehci1: usb-host@51000 {
|
||||
compatible = "marvell,orion-ehci";
|
||||
reg = <0x51000 0x1000>;
|
||||
interrupts = <25>;
|
||||
clocks = <&gate_clk 1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sdio0: sdio@92000 {
|
||||
compatible = "marvell,dove-sdhci";
|
||||
reg = <0x92000 0x100>;
|
||||
interrupts = <35>, <37>;
|
||||
clocks = <&gate_clk 8>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sdio1: sdio@90000 {
|
||||
compatible = "marvell,dove-sdhci";
|
||||
reg = <0x90000 0x100>;
|
||||
interrupts = <36>, <38>;
|
||||
clocks = <&gate_clk 9>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sata0: sata@a0000 {
|
||||
compatible = "marvell,orion-sata";
|
||||
reg = <0xa0000 0x2400>;
|
||||
interrupts = <62>;
|
||||
clocks = <&gate_clk 3>;
|
||||
nr-ports = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
rtc@d8500 {
|
||||
compatible = "marvell,orion-rtc";
|
||||
reg = <0xd8500 0x20>;
|
||||
};
|
||||
|
||||
crypto: crypto@30000 {
|
||||
compatible = "marvell,orion-crypto";
|
||||
reg = <0x30000 0x10000>,
|
||||
<0xc8000000 0x800>;
|
||||
reg-names = "regs", "sram";
|
||||
interrupts = <31>;
|
||||
clocks = <&gate_clk 15>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
xor0: dma-engine@60800 {
|
||||
compatible = "marvell,orion-xor";
|
||||
reg = <0x60800 0x100
|
||||
0x60a00 0x100>;
|
||||
clocks = <&gate_clk 23>;
|
||||
status = "okay";
|
||||
|
||||
channel0 {
|
||||
interrupts = <39>;
|
||||
dmacap,memcpy;
|
||||
dmacap,xor;
|
||||
spi0: spi-ctrl@10600 {
|
||||
compatible = "marvell,orion-spi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cell-index = <0>;
|
||||
interrupts = <6>;
|
||||
reg = <0x10600 0x28>;
|
||||
clocks = <&core_clk 0>;
|
||||
pinctrl-0 = <&pmx_spi0>;
|
||||
pinctrl-names = "default";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
channel1 {
|
||||
interrupts = <40>;
|
||||
dmacap,memset;
|
||||
dmacap,memcpy;
|
||||
dmacap,xor;
|
||||
};
|
||||
};
|
||||
|
||||
xor1: dma-engine@60900 {
|
||||
compatible = "marvell,orion-xor";
|
||||
reg = <0x60900 0x100
|
||||
0x60b00 0x100>;
|
||||
clocks = <&gate_clk 24>;
|
||||
status = "okay";
|
||||
|
||||
channel0 {
|
||||
interrupts = <42>;
|
||||
dmacap,memcpy;
|
||||
dmacap,xor;
|
||||
i2c0: i2c-ctrl@11000 {
|
||||
compatible = "marvell,mv64xxx-i2c";
|
||||
reg = <0x11000 0x20>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <11>;
|
||||
clock-frequency = <400000>;
|
||||
timeout-ms = <1000>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
channel1 {
|
||||
interrupts = <43>;
|
||||
dmacap,memset;
|
||||
dmacap,memcpy;
|
||||
dmacap,xor;
|
||||
uart0: serial@12000 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12000 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <7>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
lcd0: lcd-controller@820000 {
|
||||
compatible = "marvell,dove-lcd";
|
||||
reg = <0x820000 0x200>;
|
||||
interrupts = <47>;
|
||||
clocks = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
uart1: serial@12100 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12100 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <8>;
|
||||
clocks = <&core_clk 0>;
|
||||
pinctrl-0 = <&pmx_uart1>;
|
||||
pinctrl-names = "default";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
lcd1: lcd-controller@810000 {
|
||||
compatible = "marvell,dove-lcd";
|
||||
reg = <0x810000 0x200>;
|
||||
interrupts = <46>;
|
||||
clocks = <0>;
|
||||
status = "disabled";
|
||||
uart2: serial@12200 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12000 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <9>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart3: serial@12300 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12100 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <10>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spi1: spi-ctrl@14600 {
|
||||
compatible = "marvell,orion-spi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cell-index = <1>;
|
||||
interrupts = <5>;
|
||||
reg = <0x14600 0x28>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mbusc: mbus-ctrl@20000 {
|
||||
compatible = "marvell,mbus-controller";
|
||||
reg = <0x20000 0x80>, <0x800100 0x8>;
|
||||
};
|
||||
|
||||
bridge_intc: bridge-interrupt-ctrl@20110 {
|
||||
compatible = "marvell,orion-bridge-intc";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
reg = <0x20110 0x8>;
|
||||
interrupts = <0>;
|
||||
marvell,#interrupts = <5>;
|
||||
};
|
||||
|
||||
intc: main-interrupt-ctrl@20200 {
|
||||
compatible = "marvell,orion-intc";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
reg = <0x20200 0x10>, <0x20210 0x10>;
|
||||
};
|
||||
|
||||
timer: timer@20300 {
|
||||
compatible = "marvell,orion-timer";
|
||||
reg = <0x20300 0x20>;
|
||||
interrupt-parent = <&bridge_intc>;
|
||||
interrupts = <1>, <2>;
|
||||
clocks = <&core_clk 0>;
|
||||
};
|
||||
|
||||
crypto: crypto-engine@30000 {
|
||||
compatible = "marvell,orion-crypto";
|
||||
reg = <0x30000 0x10000>,
|
||||
<0xffffe000 0x800>;
|
||||
reg-names = "regs", "sram";
|
||||
interrupts = <31>;
|
||||
clocks = <&gate_clk 15>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ehci0: usb-host@50000 {
|
||||
compatible = "marvell,orion-ehci";
|
||||
reg = <0x50000 0x1000>;
|
||||
interrupts = <24>;
|
||||
clocks = <&gate_clk 0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ehci1: usb-host@51000 {
|
||||
compatible = "marvell,orion-ehci";
|
||||
reg = <0x51000 0x1000>;
|
||||
interrupts = <25>;
|
||||
clocks = <&gate_clk 1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
xor0: dma-engine@60800 {
|
||||
compatible = "marvell,orion-xor";
|
||||
reg = <0x60800 0x100
|
||||
0x60a00 0x100>;
|
||||
clocks = <&gate_clk 23>;
|
||||
status = "okay";
|
||||
|
||||
channel0 {
|
||||
interrupts = <39>;
|
||||
dmacap,memcpy;
|
||||
dmacap,xor;
|
||||
};
|
||||
|
||||
channel1 {
|
||||
interrupts = <40>;
|
||||
dmacap,memcpy;
|
||||
dmacap,xor;
|
||||
};
|
||||
};
|
||||
|
||||
xor1: dma-engine@60900 {
|
||||
compatible = "marvell,orion-xor";
|
||||
reg = <0x60900 0x100
|
||||
0x60b00 0x100>;
|
||||
clocks = <&gate_clk 24>;
|
||||
status = "okay";
|
||||
|
||||
channel0 {
|
||||
interrupts = <42>;
|
||||
dmacap,memcpy;
|
||||
dmacap,xor;
|
||||
};
|
||||
|
||||
channel1 {
|
||||
interrupts = <43>;
|
||||
dmacap,memcpy;
|
||||
dmacap,xor;
|
||||
};
|
||||
};
|
||||
|
||||
sdio1: sdio-host@90000 {
|
||||
compatible = "marvell,dove-sdhci";
|
||||
reg = <0x90000 0x100>;
|
||||
interrupts = <36>, <38>;
|
||||
clocks = <&gate_clk 9>;
|
||||
pinctrl-0 = <&pmx_sdio1>;
|
||||
pinctrl-names = "default";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
eth: ethernet-ctrl@72000 {
|
||||
compatible = "marvell,orion-eth";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x72000 0x4000>;
|
||||
clocks = <&gate_clk 2>;
|
||||
marvell,tx-checksum-limit = <1600>;
|
||||
status = "disabled";
|
||||
|
||||
ethernet-port@0 {
|
||||
compatible = "marvell,orion-eth-port";
|
||||
reg = <0>;
|
||||
interrupts = <29>;
|
||||
/* overwrite MAC address in bootloader */
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
phy-handle = <ðphy>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio: mdio-bus@72004 {
|
||||
compatible = "marvell,orion-mdio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x72004 0x84>;
|
||||
interrupts = <30>;
|
||||
clocks = <&gate_clk 2>;
|
||||
status = "disabled";
|
||||
|
||||
ethphy: ethernet-phy {
|
||||
/* set phy address in board file */
|
||||
};
|
||||
};
|
||||
|
||||
sdio0: sdio-host@92000 {
|
||||
compatible = "marvell,dove-sdhci";
|
||||
reg = <0x92000 0x100>;
|
||||
interrupts = <35>, <37>;
|
||||
clocks = <&gate_clk 8>;
|
||||
pinctrl-0 = <&pmx_sdio0>;
|
||||
pinctrl-names = "default";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sata0: sata-host@a0000 {
|
||||
compatible = "marvell,orion-sata";
|
||||
reg = <0xa0000 0x2400>;
|
||||
interrupts = <62>;
|
||||
clocks = <&gate_clk 3>;
|
||||
phys = <&sata_phy0>;
|
||||
phy-names = "port0";
|
||||
nr-ports = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sata_phy0: sata-phy@a2000 {
|
||||
compatible = "marvell,mvebu-sata-phy";
|
||||
reg = <0xa2000 0x0334>;
|
||||
clocks = <&gate_clk 3>;
|
||||
clock-names = "sata";
|
||||
#phy-cells = <0>;
|
||||
status = "ok";
|
||||
};
|
||||
|
||||
audio0: audio-controller@b0000 {
|
||||
compatible = "marvell,dove-audio";
|
||||
reg = <0xb0000 0x2210>;
|
||||
interrupts = <19>, <20>;
|
||||
clocks = <&gate_clk 12>;
|
||||
clock-names = "internal";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
audio1: audio-controller@b4000 {
|
||||
compatible = "marvell,dove-audio";
|
||||
reg = <0xb4000 0x2210>;
|
||||
interrupts = <21>, <22>;
|
||||
clocks = <&gate_clk 13>;
|
||||
clock-names = "internal";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
thermal: thermal-diode@d001c {
|
||||
compatible = "marvell,dove-thermal";
|
||||
reg = <0xd001c 0x0c>, <0xd005c 0x08>;
|
||||
};
|
||||
|
||||
gate_clk: clock-gating-ctrl@d0038 {
|
||||
compatible = "marvell,dove-gating-clock";
|
||||
reg = <0xd0038 0x4>;
|
||||
clocks = <&core_clk 0>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
pmu_intc: pmu-interrupt-ctrl@d0050 {
|
||||
compatible = "marvell,dove-pmu-intc";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
reg = <0xd0050 0x8>;
|
||||
interrupts = <33>;
|
||||
marvell,#interrupts = <7>;
|
||||
};
|
||||
|
||||
pinctrl: pin-ctrl@d0200 {
|
||||
compatible = "marvell,dove-pinctrl";
|
||||
reg = <0xd0200 0x10>;
|
||||
clocks = <&gate_clk 22>;
|
||||
|
||||
pmx_gpio_0: pmx-gpio-0 {
|
||||
marvell,pins = "mpp0";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_1: pmx-gpio-1 {
|
||||
marvell,pins = "mpp1";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_2: pmx-gpio-2 {
|
||||
marvell,pins = "mpp2";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_3: pmx-gpio-3 {
|
||||
marvell,pins = "mpp3";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_4: pmx-gpio-4 {
|
||||
marvell,pins = "mpp4";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_5: pmx-gpio-5 {
|
||||
marvell,pins = "mpp5";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_6: pmx-gpio-6 {
|
||||
marvell,pins = "mpp6";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_7: pmx-gpio-7 {
|
||||
marvell,pins = "mpp7";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_8: pmx-gpio-8 {
|
||||
marvell,pins = "mpp8";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_9: pmx-gpio-9 {
|
||||
marvell,pins = "mpp9";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_10: pmx-gpio-10 {
|
||||
marvell,pins = "mpp10";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_11: pmx-gpio-11 {
|
||||
marvell,pins = "mpp11";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_12: pmx-gpio-12 {
|
||||
marvell,pins = "mpp12";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_13: pmx-gpio-13 {
|
||||
marvell,pins = "mpp13";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_audio1_extclk: pmx-audio1-extclk {
|
||||
marvell,pins = "mpp13";
|
||||
marvell,function = "audio1";
|
||||
};
|
||||
|
||||
pmx_gpio_14: pmx-gpio-14 {
|
||||
marvell,pins = "mpp14";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_15: pmx-gpio-15 {
|
||||
marvell,pins = "mpp15";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_16: pmx-gpio-16 {
|
||||
marvell,pins = "mpp16";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_17: pmx-gpio-17 {
|
||||
marvell,pins = "mpp17";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_18: pmx-gpio-18 {
|
||||
marvell,pins = "mpp18";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_19: pmx-gpio-19 {
|
||||
marvell,pins = "mpp19";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_20: pmx-gpio-20 {
|
||||
marvell,pins = "mpp20";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_gpio_21: pmx-gpio-21 {
|
||||
marvell,pins = "mpp21";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_camera: pmx-camera {
|
||||
marvell,pins = "mpp_camera";
|
||||
marvell,function = "camera";
|
||||
};
|
||||
|
||||
pmx_camera_gpio: pmx-camera-gpio {
|
||||
marvell,pins = "mpp_camera";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_sdio0: pmx-sdio0 {
|
||||
marvell,pins = "mpp_sdio0";
|
||||
marvell,function = "sdio0";
|
||||
};
|
||||
|
||||
pmx_sdio0_gpio: pmx-sdio0-gpio {
|
||||
marvell,pins = "mpp_sdio0";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_sdio1: pmx-sdio1 {
|
||||
marvell,pins = "mpp_sdio1";
|
||||
marvell,function = "sdio1";
|
||||
};
|
||||
|
||||
pmx_sdio1_gpio: pmx-sdio1-gpio {
|
||||
marvell,pins = "mpp_sdio1";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_audio1_gpio: pmx-audio1-gpio {
|
||||
marvell,pins = "mpp_audio1";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_audio1_i2s1_spdifo: pmx-audio1-i2s1-spdifo {
|
||||
marvell,pins = "mpp_audio1";
|
||||
marvell,function = "i2s1/spdifo";
|
||||
};
|
||||
|
||||
pmx_spi0: pmx-spi0 {
|
||||
marvell,pins = "mpp_spi0";
|
||||
marvell,function = "spi0";
|
||||
};
|
||||
|
||||
pmx_spi0_gpio: pmx-spi0-gpio {
|
||||
marvell,pins = "mpp_spi0";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_uart1: pmx-uart1 {
|
||||
marvell,pins = "mpp_uart1";
|
||||
marvell,function = "uart1";
|
||||
};
|
||||
|
||||
pmx_uart1_gpio: pmx-uart1-gpio {
|
||||
marvell,pins = "mpp_uart1";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
|
||||
pmx_nand: pmx-nand {
|
||||
marvell,pins = "mpp_nand";
|
||||
marvell,function = "nand";
|
||||
};
|
||||
|
||||
pmx_nand_gpo: pmx-nand-gpo {
|
||||
marvell,pins = "mpp_nand";
|
||||
marvell,function = "gpo";
|
||||
};
|
||||
};
|
||||
|
||||
core_clk: core-clocks@d0214 {
|
||||
compatible = "marvell,dove-core-clock";
|
||||
reg = <0xd0214 0x4>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
gpio0: gpio-ctrl@d0400 {
|
||||
compatible = "marvell,orion-gpio";
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
reg = <0xd0400 0x20>;
|
||||
ngpios = <32>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <12>, <13>, <14>, <60>;
|
||||
};
|
||||
|
||||
gpio1: gpio-ctrl@d0420 {
|
||||
compatible = "marvell,orion-gpio";
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
reg = <0xd0420 0x20>;
|
||||
ngpios = <32>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <61>;
|
||||
};
|
||||
|
||||
rtc: real-time-clock@d8500 {
|
||||
compatible = "marvell,orion-rtc";
|
||||
reg = <0xd8500 0x20>;
|
||||
interrupt-parent = <&pmu_intc>;
|
||||
interrupts = <5>;
|
||||
};
|
||||
|
||||
gpio2: gpio-ctrl@e8400 {
|
||||
compatible = "marvell,orion-gpio";
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
reg = <0xe8400 0x0c>;
|
||||
ngpios = <8>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
menu "Bus devices"
|
||||
|
||||
config IMX_WEIM
|
||||
depends on ARCH_IMX
|
||||
bool "i.MX WEIM driver"
|
||||
|
||||
config BUS_OMAP_GPMC
|
||||
depends on ARCH_OMAP
|
||||
depends on OFDEVICE
|
||||
depends on OMAP_GPMC
|
||||
bool "TI OMAP/AM33xx GPMC support"
|
||||
|
||||
config IMX_WEIM
|
||||
depends on ARCH_IMX
|
||||
bool "i.MX WEIM driver"
|
||||
|
||||
config MVEBU_MBUS
|
||||
bool
|
||||
depends on ARCH_MVEBU
|
||||
help
|
||||
Driver needed for the MBus configuration on Marvell EBU SoCs
|
||||
(Kirkwood, Dove, Orion5x, MV78XX0 and Armada 370/XP).
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
obj-$(CONFIG_IMX_WEIM) += imx-weim.o
|
||||
obj-$(CONFIG_BUS_OMAP_GPMC) += omap-gpmc.o
|
||||
obj-$(CONFIG_BUS_OMAP_GPMC) += omap-gpmc.o
|
||||
obj-$(CONFIG_IMX_WEIM) += imx-weim.o
|
||||
obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
|
||||
|
|
|
@ -0,0 +1,743 @@
|
|||
/*
|
||||
* Address map functions for Marvell EBU SoCs (Kirkwood, Armada
|
||||
* 370/XP, Dove, Orion5x and MV78xx0)
|
||||
*
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* based on mbus driver from Linux
|
||||
* (C) Copyright 2008 Marvell Semiconductor
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*
|
||||
* The Marvell EBU SoCs have a configurable physical address space:
|
||||
* the physical address at which certain devices (PCIe, NOR, NAND,
|
||||
* etc.) sit can be configured. The configuration takes place through
|
||||
* two sets of registers:
|
||||
*
|
||||
* - One to configure the access of the CPU to the devices. Depending
|
||||
* on the families, there are between 8 and 20 configurable windows,
|
||||
* each can be use to create a physical memory window that maps to a
|
||||
* specific device. Devices are identified by a tuple (target,
|
||||
* attribute).
|
||||
*
|
||||
* - One to configure the access to the CPU to the SDRAM. There are
|
||||
* either 2 (for Dove) or 4 (for other families) windows to map the
|
||||
* SDRAM into the physical address space.
|
||||
*
|
||||
* This driver:
|
||||
*
|
||||
* - Reads out the SDRAM address decoding windows at initialization
|
||||
* time, and fills the mbus_dram_info structure with these
|
||||
* informations. The exported function mv_mbus_dram_info() allow
|
||||
* device drivers to get those informations related to the SDRAM
|
||||
* address decoding windows. This is because devices also have their
|
||||
* own windows (configured through registers that are part of each
|
||||
* device register space), and therefore the drivers for Marvell
|
||||
* devices have to configure those device -> SDRAM windows to ensure
|
||||
* that DMA works properly.
|
||||
*
|
||||
* - Provides an API for platform code or device drivers to
|
||||
* dynamically add or remove address decoding windows for the CPU ->
|
||||
* device accesses. This API is mvebu_mbus_add_window_by_id(),
|
||||
* mvebu_mbus_add_window_remap_by_id() and
|
||||
* mvebu_mbus_del_window().
|
||||
*
|
||||
* - Provides a debugfs interface in /sys/kernel/debug/mvebu-mbus/ to
|
||||
* see the list of CPU -> SDRAM windows and their configuration
|
||||
* (file 'sdram') and the list of CPU -> devices windows and their
|
||||
* configuration (file 'devices').
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <init.h>
|
||||
#include <io.h>
|
||||
#include <of.h>
|
||||
#include <of_address.h>
|
||||
#include <linux/mbus.h>
|
||||
|
||||
/* DDR target is the same on all platforms */
|
||||
#define TARGET_DDR 0
|
||||
|
||||
/* CPU Address Decode Windows registers */
|
||||
#define WIN_CTRL_OFF 0x0000
|
||||
#define WIN_CTRL_ENABLE BIT(0)
|
||||
#define WIN_CTRL_TGT_MASK 0xf0
|
||||
#define WIN_CTRL_TGT_SHIFT 4
|
||||
#define WIN_CTRL_ATTR_MASK 0xff00
|
||||
#define WIN_CTRL_ATTR_SHIFT 8
|
||||
#define WIN_CTRL_SIZE_MASK 0xffff0000
|
||||
#define WIN_CTRL_SIZE_SHIFT 16
|
||||
#define WIN_BASE_OFF 0x0004
|
||||
#define WIN_BASE_LOW 0xffff0000
|
||||
#define WIN_BASE_HIGH 0xf
|
||||
#define WIN_REMAP_LO_OFF 0x0008
|
||||
#define WIN_REMAP_LOW 0xffff0000
|
||||
#define WIN_REMAP_HI_OFF 0x000c
|
||||
|
||||
#define ATTR_HW_COHERENCY (0x1 << 4)
|
||||
|
||||
#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3))
|
||||
#define DDR_BASE_CS_HIGH_MASK 0xf
|
||||
#define DDR_BASE_CS_LOW_MASK 0xff000000
|
||||
#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
|
||||
#define DDR_SIZE_ENABLED BIT(0)
|
||||
#define DDR_SIZE_CS_MASK 0x1c
|
||||
#define DDR_SIZE_CS_SHIFT 2
|
||||
#define DDR_SIZE_MASK 0xff000000
|
||||
|
||||
#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
|
||||
|
||||
struct mvebu_mbus_state;
|
||||
|
||||
struct mvebu_mbus_soc_data {
|
||||
unsigned int num_wins;
|
||||
unsigned int num_remappable_wins;
|
||||
unsigned int (*win_cfg_offset)(const int win);
|
||||
void (*setup_cpu_target)(struct mvebu_mbus_state *s);
|
||||
};
|
||||
|
||||
struct mvebu_mbus_state {
|
||||
struct device_d *dev;
|
||||
void __iomem *mbuswins_base;
|
||||
void __iomem *sdramwins_base;
|
||||
struct dentry *debugfs_root;
|
||||
struct dentry *debugfs_sdram;
|
||||
struct dentry *debugfs_devs;
|
||||
struct resource pcie_mem_aperture;
|
||||
struct resource pcie_io_aperture;
|
||||
const struct mvebu_mbus_soc_data *soc;
|
||||
int hw_io_coherency;
|
||||
};
|
||||
|
||||
static struct mvebu_mbus_state mbus_state;
|
||||
static struct mbus_dram_target_info mbus_dram_info;
|
||||
|
||||
/*
|
||||
* Functions to manipulate the address decoding windows
|
||||
*/
|
||||
|
||||
static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
|
||||
int win, int *enabled, u64 *base,
|
||||
u32 *size, u8 *target, u8 *attr,
|
||||
u64 *remap)
|
||||
{
|
||||
void __iomem *addr = mbus->mbuswins_base +
|
||||
mbus->soc->win_cfg_offset(win);
|
||||
u32 basereg = readl(addr + WIN_BASE_OFF);
|
||||
u32 ctrlreg = readl(addr + WIN_CTRL_OFF);
|
||||
|
||||
if (!(ctrlreg & WIN_CTRL_ENABLE)) {
|
||||
*enabled = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*enabled = 1;
|
||||
*base = ((u64)basereg & WIN_BASE_HIGH) << 32;
|
||||
*base |= (basereg & WIN_BASE_LOW);
|
||||
*size = (ctrlreg | ~WIN_CTRL_SIZE_MASK) + 1;
|
||||
|
||||
if (target)
|
||||
*target = (ctrlreg & WIN_CTRL_TGT_MASK) >> WIN_CTRL_TGT_SHIFT;
|
||||
|
||||
if (attr)
|
||||
*attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT;
|
||||
|
||||
if (remap) {
|
||||
if (win < mbus->soc->num_remappable_wins) {
|
||||
u32 remap_low = readl(addr + WIN_REMAP_LO_OFF);
|
||||
u32 remap_hi = readl(addr + WIN_REMAP_HI_OFF);
|
||||
*remap = ((u64)remap_hi << 32) | remap_low;
|
||||
} else
|
||||
*remap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus,
|
||||
int win)
|
||||
{
|
||||
void __iomem *addr;
|
||||
|
||||
addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win);
|
||||
|
||||
writel(0, addr + WIN_BASE_OFF);
|
||||
writel(0, addr + WIN_CTRL_OFF);
|
||||
if (win < mbus->soc->num_remappable_wins) {
|
||||
writel(0, addr + WIN_REMAP_LO_OFF);
|
||||
writel(0, addr + WIN_REMAP_HI_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Checks whether the given window number is available */
|
||||
static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
|
||||
const int win)
|
||||
{
|
||||
void __iomem *addr = mbus->mbuswins_base +
|
||||
mbus->soc->win_cfg_offset(win);
|
||||
u32 ctrl = readl(addr + WIN_CTRL_OFF);
|
||||
return !(ctrl & WIN_CTRL_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether the given (base, base+size) area doesn't overlap an
|
||||
* existing region
|
||||
*/
|
||||
static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
|
||||
phys_addr_t base, size_t size,
|
||||
u8 target, u8 attr)
|
||||
{
|
||||
u64 end = (u64)base + size;
|
||||
int win;
|
||||
|
||||
for (win = 0; win < mbus->soc->num_wins; win++) {
|
||||
u64 wbase, wend;
|
||||
u32 wsize;
|
||||
u8 wtarget, wattr;
|
||||
int enabled;
|
||||
|
||||
mvebu_mbus_read_window(mbus, win,
|
||||
&enabled, &wbase, &wsize,
|
||||
&wtarget, &wattr, NULL);
|
||||
|
||||
if (!enabled)
|
||||
continue;
|
||||
|
||||
wend = wbase + wsize;
|
||||
|
||||
/*
|
||||
* Check if the current window overlaps with the
|
||||
* proposed physical range
|
||||
*/
|
||||
if ((u64)base < wend && end > wbase)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Check if target/attribute conflicts
|
||||
*/
|
||||
if (target == wtarget && attr == wattr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mvebu_mbus_find_window(struct mvebu_mbus_state *mbus,
|
||||
phys_addr_t base, size_t size)
|
||||
{
|
||||
int win;
|
||||
|
||||
for (win = 0; win < mbus->soc->num_wins; win++) {
|
||||
u64 wbase;
|
||||
u32 wsize;
|
||||
int enabled;
|
||||
|
||||
mvebu_mbus_read_window(mbus, win,
|
||||
&enabled, &wbase, &wsize,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (!enabled)
|
||||
continue;
|
||||
|
||||
if (base == wbase && size == wsize)
|
||||
return win;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
|
||||
int win, phys_addr_t base, size_t size,
|
||||
phys_addr_t remap, u8 target,
|
||||
u8 attr)
|
||||
{
|
||||
void __iomem *addr = mbus->mbuswins_base +
|
||||
mbus->soc->win_cfg_offset(win);
|
||||
u32 ctrl, remap_addr;
|
||||
|
||||
ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
|
||||
(attr << WIN_CTRL_ATTR_SHIFT) |
|
||||
(target << WIN_CTRL_TGT_SHIFT) |
|
||||
WIN_CTRL_ENABLE;
|
||||
|
||||
writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF);
|
||||
writel(ctrl, addr + WIN_CTRL_OFF);
|
||||
if (win < mbus->soc->num_remappable_wins) {
|
||||
if (remap == MVEBU_MBUS_NO_REMAP)
|
||||
remap_addr = base;
|
||||
else
|
||||
remap_addr = remap;
|
||||
writel(remap_addr & WIN_REMAP_LOW, addr + WIN_REMAP_LO_OFF);
|
||||
writel(0, addr + WIN_REMAP_HI_OFF);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus,
|
||||
phys_addr_t base, size_t size,
|
||||
phys_addr_t remap, u8 target,
|
||||
u8 attr)
|
||||
{
|
||||
int win;
|
||||
|
||||
if (remap == MVEBU_MBUS_NO_REMAP) {
|
||||
for (win = mbus->soc->num_remappable_wins;
|
||||
win < mbus->soc->num_wins; win++)
|
||||
if (mvebu_mbus_window_is_free(mbus, win))
|
||||
return mvebu_mbus_setup_window(mbus, win, base,
|
||||
size, remap,
|
||||
target, attr);
|
||||
}
|
||||
|
||||
|
||||
for (win = 0; win < mbus->soc->num_wins; win++)
|
||||
if (mvebu_mbus_window_is_free(mbus, win))
|
||||
return mvebu_mbus_setup_window(mbus, win, base, size,
|
||||
remap, target, attr);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* SoC-specific functions and definitions
|
||||
*/
|
||||
|
||||
static unsigned int armada_370_xp_mbus_win_offset(int win)
|
||||
{
|
||||
/* The register layout is a bit annoying and the below code
|
||||
* tries to cope with it.
|
||||
* - At offset 0x0, there are the registers for the first 8
|
||||
* windows, with 4 registers of 32 bits per window (ctrl,
|
||||
* base, remap low, remap high)
|
||||
* - Then at offset 0x80, there is a hole of 0x10 bytes for
|
||||
* the internal registers base address and internal units
|
||||
* sync barrier register.
|
||||
* - Then at offset 0x90, there the registers for 12
|
||||
* windows, with only 2 registers of 32 bits per window
|
||||
* (ctrl, base).
|
||||
*/
|
||||
if (win < 8)
|
||||
return win << 4;
|
||||
else
|
||||
return 0x90 + ((win - 8) << 3);
|
||||
}
|
||||
|
||||
static unsigned int orion5x_mbus_win_offset(int win)
|
||||
{
|
||||
return win << 4;
|
||||
}
|
||||
|
||||
static unsigned int mv78xx0_mbus_win_offset(int win)
|
||||
{
|
||||
if (win < 8)
|
||||
return win << 4;
|
||||
else
|
||||
return 0x900 + ((win - 8) << 4);
|
||||
}
|
||||
|
||||
static void mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
|
||||
{
|
||||
int i;
|
||||
int cs;
|
||||
|
||||
mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
|
||||
|
||||
for (i = 0, cs = 0; i < 4; i++) {
|
||||
u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
|
||||
u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
|
||||
|
||||
/*
|
||||
* We only take care of entries for which the chip
|
||||
* select is enabled, and that don't have high base
|
||||
* address bits set (devices can only access the first
|
||||
* 32 bits of the memory).
|
||||
*/
|
||||
if ((size & DDR_SIZE_ENABLED) &&
|
||||
!(base & DDR_BASE_CS_HIGH_MASK)) {
|
||||
struct mbus_dram_window *w;
|
||||
|
||||
w = &mbus_dram_info.cs[cs++];
|
||||
w->cs_index = i;
|
||||
w->mbus_attr = 0xf & ~(1 << i);
|
||||
if (mbus->hw_io_coherency)
|
||||
w->mbus_attr |= ATTR_HW_COHERENCY;
|
||||
w->base = base & DDR_BASE_CS_LOW_MASK;
|
||||
w->size = (size | ~DDR_SIZE_MASK) + 1;
|
||||
}
|
||||
}
|
||||
mbus_dram_info.num_cs = cs;
|
||||
}
|
||||
|
||||
static void mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
|
||||
{
|
||||
int i;
|
||||
int cs;
|
||||
|
||||
mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
|
||||
|
||||
for (i = 0, cs = 0; i < 2; i++) {
|
||||
u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i));
|
||||
|
||||
/*
|
||||
* Chip select enabled?
|
||||
*/
|
||||
if (map & 1) {
|
||||
struct mbus_dram_window *w;
|
||||
|
||||
w = &mbus_dram_info.cs[cs++];
|
||||
w->cs_index = i;
|
||||
w->mbus_attr = 0; /* CS address decoding done inside */
|
||||
/* the DDR controller, no need to */
|
||||
/* provide attributes */
|
||||
w->base = map & 0xff800000;
|
||||
w->size = 0x100000 << (((map & 0x000f0000) >> 16) - 4);
|
||||
}
|
||||
}
|
||||
|
||||
mbus_dram_info.num_cs = cs;
|
||||
}
|
||||
|
||||
static const struct mvebu_mbus_soc_data
|
||||
armada_370_xp_mbus_data __maybe_unused = {
|
||||
.num_wins = 20,
|
||||
.num_remappable_wins = 8,
|
||||
.win_cfg_offset = armada_370_xp_mbus_win_offset,
|
||||
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
|
||||
};
|
||||
|
||||
static const struct mvebu_mbus_soc_data
|
||||
dove_mbus_data __maybe_unused = {
|
||||
.num_wins = 8,
|
||||
.num_remappable_wins = 4,
|
||||
.win_cfg_offset = orion5x_mbus_win_offset,
|
||||
.setup_cpu_target = mvebu_mbus_dove_setup_cpu_target,
|
||||
};
|
||||
|
||||
static const struct mvebu_mbus_soc_data
|
||||
kirkwood_mbus_data __maybe_unused = {
|
||||
.num_wins = 8,
|
||||
.num_remappable_wins = 4,
|
||||
.win_cfg_offset = orion5x_mbus_win_offset,
|
||||
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
|
||||
};
|
||||
|
||||
/*
|
||||
* Some variants of Orion5x have 4 remappable windows, some other have
|
||||
* only two of them.
|
||||
*/
|
||||
static const struct mvebu_mbus_soc_data
|
||||
orion5x_4win_mbus_data __maybe_unused = {
|
||||
.num_wins = 8,
|
||||
.num_remappable_wins = 4,
|
||||
.win_cfg_offset = orion5x_mbus_win_offset,
|
||||
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
|
||||
};
|
||||
|
||||
static const struct mvebu_mbus_soc_data
|
||||
orion5x_2win_mbus_data__maybe_unused = {
|
||||
.num_wins = 8,
|
||||
.num_remappable_wins = 2,
|
||||
.win_cfg_offset = orion5x_mbus_win_offset,
|
||||
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
|
||||
};
|
||||
|
||||
static const struct mvebu_mbus_soc_data
|
||||
mv78xx0_mbus_data __maybe_unused = {
|
||||
.num_wins = 14,
|
||||
.num_remappable_wins = 8,
|
||||
.win_cfg_offset = mv78xx0_mbus_win_offset,
|
||||
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
|
||||
};
|
||||
|
||||
static struct of_device_id mvebu_mbus_dt_ids[] = {
|
||||
#if defined(CONFIG_ARCH_ARMADA_370) || defined(CONFIG_ARCH_ARMADA_XP)
|
||||
{ .compatible = "marvell,armada370-mbus",
|
||||
.data = (u32)&armada_370_xp_mbus_data, },
|
||||
{ .compatible = "marvell,armadaxp-mbus",
|
||||
.data = (u32)&armada_370_xp_mbus_data, },
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_DOVE)
|
||||
{ .compatible = "marvell,dove-mbus",
|
||||
.data = (u32)&dove_mbus_data, },
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_KIRKWOOD)
|
||||
{ .compatible = "marvell,kirkwood-mbus",
|
||||
.data = (u32)&kirkwood_mbus_data, },
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_ORION5X)
|
||||
{ .compatible = "marvell,orion5x-88f5281-mbus",
|
||||
.data = (u32)&orion5x_4win_mbus_data, },
|
||||
{ .compatible = "marvell,orion5x-88f5182-mbus",
|
||||
.data = (u32)&orion5x_2win_mbus_data, },
|
||||
{ .compatible = "marvell,orion5x-88f5181-mbus",
|
||||
.data = (u32)&orion5x_2win_mbus_data, },
|
||||
{ .compatible = "marvell,orion5x-88f6183-mbus",
|
||||
.data = (u32)&orion5x_4win_mbus_data, },
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_MV78XX0)
|
||||
{ .compatible = "marvell,mv78xx0-mbus",
|
||||
.data = (u32)&mv78xx0_mbus_data, },
|
||||
#endif
|
||||
{ },
|
||||
};
|
||||
|
||||
/*
|
||||
* Public API of the driver
|
||||
*/
|
||||
const struct mbus_dram_target_info *mvebu_mbus_dram_info(void)
|
||||
{
|
||||
return &mbus_dram_info;
|
||||
}
|
||||
|
||||
int mvebu_mbus_add_window_remap_by_id(unsigned int target,
|
||||
unsigned int attribute,
|
||||
phys_addr_t base, size_t size,
|
||||
phys_addr_t remap)
|
||||
{
|
||||
struct mvebu_mbus_state *s = &mbus_state;
|
||||
|
||||
if (!mvebu_mbus_window_conflicts(s, base, size, target, attribute)) {
|
||||
dev_err(s->dev, "cannot add window '%x:%x', conflicts with another window\n",
|
||||
target, attribute);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mvebu_mbus_alloc_window(s, base, size, remap, target, attribute);
|
||||
}
|
||||
|
||||
int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute,
|
||||
phys_addr_t base, size_t size)
|
||||
{
|
||||
return mvebu_mbus_add_window_remap_by_id(target, attribute, base,
|
||||
size, MVEBU_MBUS_NO_REMAP);
|
||||
}
|
||||
|
||||
int mvebu_mbus_del_window(phys_addr_t base, size_t size)
|
||||
{
|
||||
int win;
|
||||
|
||||
win = mvebu_mbus_find_window(&mbus_state, base, size);
|
||||
if (win < 0)
|
||||
return win;
|
||||
|
||||
mvebu_mbus_disable_window(&mbus_state, win);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mvebu_mbus_get_pcie_mem_aperture(struct resource *res)
|
||||
{
|
||||
if (!res)
|
||||
return;
|
||||
*res = mbus_state.pcie_mem_aperture;
|
||||
}
|
||||
|
||||
void mvebu_mbus_get_pcie_io_aperture(struct resource *res)
|
||||
{
|
||||
if (!res)
|
||||
return;
|
||||
*res = mbus_state.pcie_io_aperture;
|
||||
}
|
||||
|
||||
/*
|
||||
* The window IDs in the ranges DT property have the following format:
|
||||
* - bits 28 to 31: MBus custom field
|
||||
* - bits 24 to 27: window target ID
|
||||
* - bits 16 to 23: window attribute ID
|
||||
* - bits 0 to 15: unused
|
||||
*/
|
||||
#define CUSTOM(id) (((id) & 0xF0000000) >> 24)
|
||||
#define TARGET(id) (((id) & 0x0F000000) >> 24)
|
||||
#define ATTR(id) (((id) & 0x00FF0000) >> 16)
|
||||
|
||||
static int mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
|
||||
u32 base, u32 size, u8 target, u8 attr)
|
||||
{
|
||||
if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) {
|
||||
dev_err(mbus->dev, "cannot add window '%04x:%04x', conflicts with another window\n",
|
||||
target, attr);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (mvebu_mbus_alloc_window(mbus, base, size, MVEBU_MBUS_NO_REMAP,
|
||||
target, attr)) {
|
||||
dev_err(mbus->dev, "cannot add window '%04x:%04x', too many windows\n",
|
||||
target, attr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mbus_parse_ranges(struct mvebu_mbus_state *mbus, int *addr_cells,
|
||||
int *c_addr_cells, int *c_size_cells,
|
||||
int *cell_count, const __be32 **ranges_start,
|
||||
const __be32 **ranges_end)
|
||||
{
|
||||
struct device_node *node = mbus->dev->device_node;
|
||||
const __be32 *prop;
|
||||
int ranges_len, tuple_len;
|
||||
|
||||
/* Allow a node with no 'ranges' property */
|
||||
*ranges_start = of_get_property(node, "ranges", &ranges_len);
|
||||
if (*ranges_start == NULL) {
|
||||
*addr_cells = *c_addr_cells = *c_size_cells = *cell_count = 0;
|
||||
*ranges_start = *ranges_end = NULL;
|
||||
return 0;
|
||||
}
|
||||
*ranges_end = *ranges_start + ranges_len / sizeof(__be32);
|
||||
|
||||
*addr_cells = of_n_addr_cells(node);
|
||||
|
||||
prop = of_get_property(node, "#address-cells", NULL);
|
||||
*c_addr_cells = be32_to_cpup(prop);
|
||||
|
||||
prop = of_get_property(node, "#size-cells", NULL);
|
||||
*c_size_cells = be32_to_cpup(prop);
|
||||
|
||||
*cell_count = *addr_cells + *c_addr_cells + *c_size_cells;
|
||||
tuple_len = (*cell_count) * sizeof(__be32);
|
||||
|
||||
if (ranges_len % tuple_len) {
|
||||
dev_warn(mbus->dev, "malformed ranges entry '%s'\n",
|
||||
node->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mbus_dt_setup(struct mvebu_mbus_state *mbus)
|
||||
{
|
||||
int addr_cells, c_addr_cells, c_size_cells;
|
||||
int i, ret, cell_count;
|
||||
const __be32 *r, *ranges_start, *ranges_end;
|
||||
|
||||
ret = mbus_parse_ranges(mbus, &addr_cells, &c_addr_cells,
|
||||
&c_size_cells, &cell_count,
|
||||
&ranges_start, &ranges_end);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0, r = ranges_start; r < ranges_end; r += cell_count, i++) {
|
||||
u32 windowid, base, size;
|
||||
u8 target, attr;
|
||||
|
||||
/*
|
||||
* An entry with a non-zero custom field do not
|
||||
* correspond to a static window, so skip it.
|
||||
*/
|
||||
windowid = of_read_number(r, 1);
|
||||
if (CUSTOM(windowid))
|
||||
continue;
|
||||
|
||||
target = TARGET(windowid);
|
||||
attr = ATTR(windowid);
|
||||
|
||||
base = of_read_number(r + c_addr_cells, addr_cells);
|
||||
size = of_read_number(r + c_addr_cells + addr_cells,
|
||||
c_size_cells);
|
||||
ret = mbus_dt_setup_win(mbus, base, size, target, attr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mvebu_mbus_get_pcie_resources(struct device_node *np,
|
||||
struct resource *mem, struct resource *io)
|
||||
{
|
||||
u32 reg[2];
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* These are optional, so we make sure that resource_size(x) will
|
||||
* return 0.
|
||||
*/
|
||||
memset(mem, 0, sizeof(struct resource));
|
||||
mem->end = -1;
|
||||
memset(io, 0, sizeof(struct resource));
|
||||
io->end = -1;
|
||||
|
||||
ret = of_property_read_u32_array(np, "pcie-mem-aperture",
|
||||
reg, ARRAY_SIZE(reg));
|
||||
if (!ret) {
|
||||
mem->start = reg[0];
|
||||
mem->end = mem->start + reg[1];
|
||||
mem->flags = IORESOURCE_MEM;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(np, "pcie-io-aperture",
|
||||
reg, ARRAY_SIZE(reg));
|
||||
if (!ret) {
|
||||
io->start = reg[0];
|
||||
io->end = io->start + reg[1];
|
||||
io->flags = IORESOURCE_IO;
|
||||
}
|
||||
}
|
||||
|
||||
static int mvebu_mbus_probe(struct device_d *dev)
|
||||
{
|
||||
struct device_node *np, *controller;
|
||||
const struct of_device_id *match;
|
||||
const __be32 *prop;
|
||||
int win;
|
||||
|
||||
mbus_state.dev = dev;
|
||||
|
||||
np = of_find_matching_node_and_match(NULL, mvebu_mbus_dt_ids, &match);
|
||||
if (!np) {
|
||||
dev_err(dev, "could not find a matching SoC family\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
mbus_state.soc = (struct mvebu_mbus_soc_data *)match->data;
|
||||
|
||||
prop = of_get_property(np, "controller", NULL);
|
||||
if (!prop) {
|
||||
dev_err(dev, "required 'controller' property missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
controller = of_find_node_by_phandle(be32_to_cpup(prop));
|
||||
if (!controller) {
|
||||
dev_err(dev, "could not find an 'mbus-controller' node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mbus_state.mbuswins_base = of_iomap(controller, 0);
|
||||
if (!mbus_state.mbuswins_base) {
|
||||
dev_err(dev, "cannot get MBUS register address\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mbus_state.sdramwins_base = of_iomap(controller, 1);
|
||||
if (!mbus_state.sdramwins_base) {
|
||||
dev_err(dev, "cannot get SDRAM register address\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Get optional pcie-{mem,io}-aperture properties */
|
||||
mvebu_mbus_get_pcie_resources(np, &mbus_state.pcie_mem_aperture,
|
||||
&mbus_state.pcie_io_aperture);
|
||||
|
||||
if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"))
|
||||
mbus_state.hw_io_coherency = 1;
|
||||
|
||||
for (win = 0; win < mbus_state.soc->num_wins; win++)
|
||||
mvebu_mbus_disable_window(&mbus_state, win);
|
||||
|
||||
mbus_state.soc->setup_cpu_target(&mbus_state);
|
||||
|
||||
/* Setup statically declared windows in the DT */
|
||||
return mbus_dt_setup(&mbus_state);
|
||||
}
|
||||
|
||||
static struct driver_d mvebu_mbus_driver = {
|
||||
.probe = mvebu_mbus_probe,
|
||||
.name = "mvebu-mbus",
|
||||
.of_compatible = DRV_OF_COMPAT(mvebu_mbus_dt_ids),
|
||||
};
|
||||
|
||||
static int mvebu_mbus_init(void)
|
||||
{
|
||||
return platform_driver_register(&mvebu_mbus_driver);
|
||||
}
|
||||
postcore_initcall(mvebu_mbus_init);
|
|
@ -1,32 +1,30 @@
|
|||
config ARCH_HAS_FEC_IMX
|
||||
bool
|
||||
|
||||
config HAS_AT91_ETHER
|
||||
bool
|
||||
|
||||
config HAS_CS8900
|
||||
bool
|
||||
|
||||
config HAS_DESIGNWARE_ETH
|
||||
bool
|
||||
|
||||
config HAS_DM9000
|
||||
bool
|
||||
|
||||
config HAS_MACB
|
||||
bool
|
||||
|
||||
config HAS_AT91_ETHER
|
||||
bool
|
||||
|
||||
config HAS_NETX_ETHER
|
||||
bool
|
||||
|
||||
config HAS_DESIGNWARE_ETH
|
||||
bool
|
||||
|
||||
config ARCH_HAS_FEC_IMX
|
||||
bool
|
||||
|
||||
config PHYLIB
|
||||
bool
|
||||
|
||||
menu "Network drivers"
|
||||
depends on NET
|
||||
|
||||
source "drivers/net/phy/Kconfig"
|
||||
|
||||
config DRIVER_NET_AR231X
|
||||
bool "AR231X Ethernet support"
|
||||
depends on MACH_MIPS_AR231X
|
||||
|
@ -34,6 +32,11 @@ config DRIVER_NET_AR231X
|
|||
help
|
||||
Support for the AR231x/531x ethernet controller
|
||||
|
||||
config DRIVER_NET_AT91_ETHER
|
||||
bool "at91 ethernet driver"
|
||||
depends on HAS_AT91_ETHER
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_CALXEDA_XGMAC
|
||||
bool "Calxeda xgmac"
|
||||
|
||||
|
@ -46,6 +49,79 @@ config DRIVER_NET_CPSW
|
|||
depends on ARCH_OMAP
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_DAVINCI_EMAC
|
||||
bool "TI Davinci/OMAP EMAC ethernet driver"
|
||||
depends on ARCH_OMAP3
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_DESIGNWARE
|
||||
bool "Designware Universal MAC ethernet driver"
|
||||
select PHYLIB
|
||||
help
|
||||
This option enables support for the Synopsys
|
||||
Designware Core Univesal MAC 10M/100M/1G ethernet IP.
|
||||
|
||||
config DRIVER_NET_DM9K
|
||||
bool "Davicom dm9k[E|A|B] ethernet driver"
|
||||
depends on HAS_DM9000
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_EP93XX
|
||||
bool "EP93xx Ethernet driver"
|
||||
depends on ARCH_EP93XX
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_ETHOC
|
||||
bool "OpenCores ethernet MAC driver"
|
||||
help
|
||||
This option enables support for the OpenCores 10/100 Mbps
|
||||
Ethernet MAC core.
|
||||
|
||||
config DRIVER_NET_FEC_IMX
|
||||
bool "i.MX FEC Ethernet driver"
|
||||
depends on ARCH_HAS_FEC_IMX
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_GIANFAR
|
||||
bool "Gianfar Ethernet"
|
||||
depends on ARCH_MPC85XX
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_KS8851_MLL
|
||||
bool "ks8851 mll ethernet driver"
|
||||
select PHYLIB
|
||||
help
|
||||
This option enables support for the Micrel KS8851 MLL
|
||||
ethernet chip.
|
||||
|
||||
config DRIVER_NET_MACB
|
||||
bool "macb Ethernet driver"
|
||||
depends on HAS_MACB
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_MICREL
|
||||
depends on SPI
|
||||
bool "Micrel KSZ8864RMN Ethernet Switch driver"
|
||||
help
|
||||
This option enables support for enabling the Micrel
|
||||
KSZ8864RMN Ethernet Switch over SPI.
|
||||
|
||||
config DRIVER_NET_MPC5200
|
||||
bool "MPC5200 Ethernet driver"
|
||||
depends on ARCH_MPC5200
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_NETX
|
||||
bool "Hilscher Netx ethernet driver"
|
||||
depends on HAS_NETX_ETHER
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_ORION
|
||||
bool "Marvell Orion SoC Ethernet"
|
||||
depends on ARCH_MVEBU
|
||||
select PHYLIB
|
||||
select MDIO_MVEBU
|
||||
|
||||
config DRIVER_NET_SMC911X
|
||||
bool "smc911x ethernet driver"
|
||||
select PHYLIB
|
||||
|
@ -60,46 +136,6 @@ config DRIVER_NET_SMC91111
|
|||
This option enables support for the SMSC LAN91C111
|
||||
ethernet chip.
|
||||
|
||||
config DRIVER_NET_DAVINCI_EMAC
|
||||
bool "TI Davinci/OMAP EMAC ethernet driver"
|
||||
depends on ARCH_OMAP3
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_DM9K
|
||||
bool "Davicom dm9k[E|A|B] ethernet driver"
|
||||
depends on HAS_DM9000
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_NETX
|
||||
bool "Hilscher Netx ethernet driver"
|
||||
depends on HAS_NETX_ETHER
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_AT91_ETHER
|
||||
bool "at91 ethernet driver"
|
||||
depends on HAS_AT91_ETHER
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_MPC5200
|
||||
bool "MPC5200 Ethernet driver"
|
||||
depends on ARCH_MPC5200
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_FEC_IMX
|
||||
bool "i.MX FEC Ethernet driver"
|
||||
depends on ARCH_HAS_FEC_IMX
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_EP93XX
|
||||
bool "EP93xx Ethernet driver"
|
||||
depends on ARCH_EP93XX
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_MACB
|
||||
bool "macb Ethernet driver"
|
||||
depends on HAS_MACB
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_TAP
|
||||
bool "tap Ethernet driver"
|
||||
depends on LINUX
|
||||
|
@ -120,39 +156,8 @@ config TSE_USE_DEDICATED_DESC_MEM
|
|||
reserved with a malloc but directly mapped to the memory
|
||||
address (defined in config.h)
|
||||
|
||||
config DRIVER_NET_KS8851_MLL
|
||||
bool "ks8851 mll ethernet driver"
|
||||
select PHYLIB
|
||||
help
|
||||
This option enables support for the Micrel KS8851 MLL
|
||||
ethernet chip.
|
||||
|
||||
config DRIVER_NET_DESIGNWARE
|
||||
bool "Designware Universal MAC ethernet driver"
|
||||
select PHYLIB
|
||||
help
|
||||
This option enables support for the Synopsys
|
||||
Designware Core Univesal MAC 10M/100M/1G ethernet IP.
|
||||
|
||||
config DRIVER_NET_GIANFAR
|
||||
bool "Gianfar Ethernet"
|
||||
depends on ARCH_MPC85XX
|
||||
select PHYLIB
|
||||
|
||||
config DRIVER_NET_ETHOC
|
||||
bool "OpenCores ethernet MAC driver"
|
||||
help
|
||||
This option enables support for the OpenCores 10/100 Mbps
|
||||
Ethernet MAC core.
|
||||
|
||||
source "drivers/net/phy/Kconfig"
|
||||
source "drivers/net/usb/Kconfig"
|
||||
|
||||
config DRIVER_NET_MICREL
|
||||
depends on SPI
|
||||
bool "Micrel KSZ8864RMN Ethernet Switch driver"
|
||||
help
|
||||
This option enables support for enabling the Micrel
|
||||
KSZ8864RMN Ethernet Switch over SPI.
|
||||
|
||||
endmenu
|
||||
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
obj-$(CONFIG_PHYLIB) += phy/
|
||||
obj-$(CONFIG_NET_USB) += usb/
|
||||
|
||||
obj-$(CONFIG_DRIVER_NET_AR231X) += ar231x.o
|
||||
obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o
|
||||
obj-$(CONFIG_DRIVER_NET_CALXEDA_XGMAC) += xgmac.o
|
||||
obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o
|
||||
obj-$(CONFIG_DRIVER_NET_CPSW) += cpsw.o
|
||||
obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC) += davinci_emac.o
|
||||
obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
|
||||
obj-$(CONFIG_DRIVER_NET_DM9K) += dm9k.o
|
||||
obj-$(CONFIG_DRIVER_NET_EP93XX) += ep93xx.o
|
||||
obj-$(CONFIG_DRIVER_NET_ETHOC) += ethoc.o
|
||||
obj-$(CONFIG_DRIVER_NET_FEC_IMX) += fec_imx.o
|
||||
obj-$(CONFIG_DRIVER_NET_GIANFAR) += gianfar.o
|
||||
obj-$(CONFIG_DRIVER_NET_KS8851_MLL) += ks8851_mll.o
|
||||
obj-$(CONFIG_DRIVER_NET_MACB) += macb.o
|
||||
obj-$(CONFIG_DRIVER_NET_MICREL) += ksz8864rmn.o
|
||||
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_SMC911X) += smc911x.o
|
||||
obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o
|
||||
obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC) += davinci_emac.o
|
||||
obj-$(CONFIG_DRIVER_NET_DM9K) += dm9k.o
|
||||
obj-$(CONFIG_DRIVER_NET_NETX) += netx_eth.o
|
||||
obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o
|
||||
obj-$(CONFIG_DRIVER_NET_MPC5200) += fec_mpc5200.o
|
||||
obj-$(CONFIG_DRIVER_NET_FEC_IMX) += fec_imx.o
|
||||
obj-$(CONFIG_DRIVER_NET_EP93XX) += ep93xx.o
|
||||
obj-$(CONFIG_DRIVER_NET_MACB) += macb.o
|
||||
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
|
||||
obj-$(CONFIG_PHYLIB) += phy/
|
||||
obj-$(CONFIG_NET_USB) += usb/
|
||||
obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
|
||||
obj-$(CONFIG_DRIVER_NET_KS8851_MLL) += ks8851_mll.o
|
||||
obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
|
||||
obj-$(CONFIG_DRIVER_NET_GIANFAR) += gianfar.o
|
||||
obj-$(CONFIG_DRIVER_NET_MICREL) += ksz8864rmn.o
|
||||
obj-$(CONFIG_DRIVER_NET_ETHOC) += ethoc.o
|
||||
|
|
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
* (C) Copyright 2014
|
||||
* Pengutronix, Michael Grzeschik <mgr@pengutronix.de>
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* based on kirkwood_egiga driver from u-boot
|
||||
* (C) Copyright 2009
|
||||
* Marvell Semiconductor <www.marvell.com>
|
||||
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
|
||||
*
|
||||
* based on - Driver for MV64360X ethernet ports
|
||||
* Copyright (C) 2002 rabeeh@galileo.co.il
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <init.h>
|
||||
#include <io.h>
|
||||
#include <net.h>
|
||||
#include <of_net.h>
|
||||
#include <sizes.h>
|
||||
#include <asm/mmu.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mbus.h>
|
||||
|
||||
#include "orion-gbe.h"
|
||||
|
||||
struct rxdesc {
|
||||
u32 cmd_sts; /* Descriptor command status */
|
||||
u16 buf_size; /* Buffer size */
|
||||
u16 byte_cnt; /* Descriptor buffer byte count */
|
||||
void *buf_ptr; /* Descriptor buffer pointer */
|
||||
struct rxdesc *nxtdesc; /* Next descriptor pointer */
|
||||
};
|
||||
|
||||
struct txdesc {
|
||||
u32 cmd_sts; /* Descriptor command status */
|
||||
u16 l4i_chk; /* CPU provided TCP Checksum */
|
||||
u16 byte_cnt; /* Descriptor buffer byte count */
|
||||
void *buf_ptr; /* Descriptor buffer ptr */
|
||||
struct txdesc *nxtdesc; /* Next descriptor ptr */
|
||||
};
|
||||
|
||||
struct port_priv {
|
||||
struct eth_device edev;
|
||||
void __iomem *regs;
|
||||
struct device_node *np;
|
||||
int portno;
|
||||
struct txdesc *txdesc;
|
||||
struct rxdesc *rxdesc;
|
||||
struct rxdesc *current_rxdesc;
|
||||
u8 *rxbuf;
|
||||
};
|
||||
|
||||
struct orion_gbe {
|
||||
void __iomem *regs;
|
||||
struct clk *clk;
|
||||
struct port_priv *ports;
|
||||
int num_ports;
|
||||
};
|
||||
|
||||
#define UTXQ 0 /* Used Tx queue number */
|
||||
#define URXQ 0 /* Used Rx queue number */
|
||||
#define RX_RING_SIZE 4
|
||||
#define TRANSFER_TIMEOUT (10 * MSECOND)
|
||||
|
||||
#define NR_ADDR_WINS 6 /* number of address windows */
|
||||
#define NR_HIGH_ADDR_WINS 4 /* number of high address windows */
|
||||
|
||||
#define ACCEPT_MAC_ADDR 0
|
||||
#define REJECT_MAC_ADDR 1
|
||||
|
||||
/* setup DRAM access windows provided by mbus */
|
||||
static void eunit_set_dram_access(struct orion_gbe *gbe)
|
||||
{
|
||||
const struct mbus_dram_target_info *dram = mvebu_mbus_dram_info();
|
||||
u32 bare = ~0, epap = 0, reg;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < NR_ADDR_WINS; n++) {
|
||||
if (n >= dram->num_cs)
|
||||
continue;
|
||||
|
||||
/* enable BAR */
|
||||
bare &= ~BIT(n);
|
||||
/* set port access protect to R/W */
|
||||
epap |= ACCESS_FULL << (n * 2);
|
||||
|
||||
/* configure Base Address and Size */
|
||||
reg = ((dram->cs[n].size / SZ_64K) - 1) << 16;
|
||||
writel(reg, gbe->regs + EUNIT_S(n));
|
||||
|
||||
reg = dram->cs[n].base & 0xffff0000;
|
||||
reg |= dram->cs[n].mbus_attr << 8;
|
||||
reg |= dram->mbus_dram_target_id;
|
||||
writel(reg, gbe->regs + EUNIT_BA(n));
|
||||
if (n < NR_HIGH_ADDR_WINS)
|
||||
writel(0, gbe->regs + EUNIT_HA(n));
|
||||
}
|
||||
|
||||
writel(epap, gbe->regs + EUNIT_PAP);
|
||||
writel(bare, gbe->regs + EUNIT_BARE);
|
||||
}
|
||||
|
||||
/* clear entries in unicast, special multicast, and other multicast tables */
|
||||
static void port_clear_mac_tables(struct port_priv *port)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* clear unicast tables (DFUTn) */
|
||||
for (n = 0; n < 4; n++)
|
||||
writel(0, port->regs + PORT_DFUT(n));
|
||||
|
||||
/* clear special (DFSMTn) and other (DFOMTn) multicast tables */
|
||||
for (n = 0; n < 64; n++) {
|
||||
writel(0, port->regs + PORT_DFSMT(n));
|
||||
writel(0, port->regs + PORT_DFOMT(n));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* set the port unicast address table
|
||||
*
|
||||
* This function adds/removes MAC addresses from the port unicast
|
||||
* address table.
|
||||
*
|
||||
* Locate the proper entry in the Unicast table for the specified MAC
|
||||
* nibble and set its properties according to function parameters.
|
||||
*
|
||||
* @nibble Unicast MAC address, last nibble
|
||||
* @reject 0 = Accept, 1 = Reject MAC address
|
||||
*/
|
||||
static void port_set_unicast_filter(struct port_priv *port,
|
||||
u8 nibble, int reject)
|
||||
{
|
||||
u8 table, entry, shift;
|
||||
u32 reg;
|
||||
|
||||
/* Locate the Unicast table entry by nibble */
|
||||
nibble &= 0xf;
|
||||
table = nibble / 4;
|
||||
entry = nibble % 4;
|
||||
shift = (DFT_ENTRY_SIZE * entry);
|
||||
|
||||
reg = readl(port->regs + PORT_DFUT(table));
|
||||
reg &= DFT_ENTRY_MASK << shift;
|
||||
if (!reject)
|
||||
reg |= (DFT_PASS | (URXQ << DFT_QUEUE_SHIFT)) << shift;
|
||||
writel(reg, port->regs + PORT_DFUT(table));
|
||||
}
|
||||
|
||||
/* initialize rx descriptor ring */
|
||||
static void port_init_rxdesc_ring(struct port_priv *port)
|
||||
{
|
||||
struct rxdesc *rxdesc, *nxtdesc;
|
||||
void *rxbuf;
|
||||
int n;
|
||||
|
||||
/* initialize aligned rx descriptor ring-buffer */
|
||||
rxdesc = port->rxdesc;
|
||||
rxbuf = port->rxbuf;
|
||||
for (n = 0; n < RX_RING_SIZE; n++) {
|
||||
nxtdesc = ((void *)rxdesc) + ALIGN(sizeof(*port->rxdesc), 16);
|
||||
|
||||
rxdesc->cmd_sts = RXDESC_OWNED_BY_DMA;
|
||||
rxdesc->buf_size = ALIGN(PKTSIZE, 8);
|
||||
rxdesc->byte_cnt = 0;
|
||||
rxdesc->buf_ptr = rxbuf;
|
||||
if (n == RX_RING_SIZE-1)
|
||||
rxdesc->nxtdesc = port->rxdesc;
|
||||
else
|
||||
rxdesc->nxtdesc = nxtdesc;
|
||||
|
||||
rxbuf += ALIGN(PKTSIZE, 8);
|
||||
|
||||
rxdesc = nxtdesc;
|
||||
}
|
||||
|
||||
port->current_rxdesc = port->rxdesc;
|
||||
}
|
||||
|
||||
/* stop a queue and check for termination */
|
||||
static void port_stop_queue(void __iomem *ctrl)
|
||||
{
|
||||
u32 reg = readl(ctrl);
|
||||
|
||||
if (!(reg & 0xff))
|
||||
return;
|
||||
|
||||
/* stop active channels only */
|
||||
writel((reg << 8), ctrl);
|
||||
/* wait for all queues to terminate */
|
||||
while (readl(ctrl) & 0xff)
|
||||
;
|
||||
}
|
||||
|
||||
static void port_stop(struct port_priv *port)
|
||||
{
|
||||
/* stop all queues */
|
||||
port_stop_queue(port->regs + PORT_TQC);
|
||||
port_stop_queue(port->regs + PORT_RQC);
|
||||
/* disable port, release reset */
|
||||
writel(readl(port->regs + PORT_SC0) & ~PORT_ENABLE,
|
||||
port->regs + PORT_SC0);
|
||||
writel(readl(port->regs + PORT_SC1) & ~PORT_RESET,
|
||||
port->regs + PORT_SC1);
|
||||
/* clear and mask all interrupts */
|
||||
writel(0, port->regs + PORT_IC);
|
||||
writel(0, port->regs + PORT_IM);
|
||||
writel(0, port->regs + PORT_EIC);
|
||||
writel(0, port->regs + PORT_EIM);
|
||||
}
|
||||
|
||||
static void port_halt(struct eth_device *edev)
|
||||
{
|
||||
struct port_priv *port = edev->priv;
|
||||
|
||||
port_stop(port);
|
||||
}
|
||||
|
||||
static int port_send(struct eth_device *edev, void *data, int len)
|
||||
{
|
||||
struct port_priv *port = edev->priv;
|
||||
struct txdesc *txdesc = port->txdesc;
|
||||
u32 cmd_sts;
|
||||
int ret;
|
||||
|
||||
/* flush transmit data */
|
||||
dma_flush_range((unsigned long)data, (unsigned long)data+len);
|
||||
|
||||
txdesc->cmd_sts = TXDESC_OWNED_BY_DMA;
|
||||
txdesc->cmd_sts |= TXDESC_FIRST | TXDESC_LAST;
|
||||
txdesc->cmd_sts |= TXDESC_ZERO_PADDING | TXDESC_GEN_CRC;
|
||||
txdesc->buf_ptr = data;
|
||||
txdesc->byte_cnt = len;
|
||||
|
||||
/* assign tx descriptor and issue send command */
|
||||
writel((u32)txdesc, port->regs + PORT_TCQDP(UTXQ));
|
||||
writel(BIT(UTXQ), port->regs + PORT_TQC);
|
||||
|
||||
/* wait for packet transmit completion */
|
||||
ret = wait_on_timeout(TRANSFER_TIMEOUT,
|
||||
(readl(&txdesc->cmd_sts) & TXDESC_OWNED_BY_DMA) == 0);
|
||||
if (ret) {
|
||||
dev_err(&edev->dev, "transmit timeout\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cmd_sts = readl(&txdesc->cmd_sts);
|
||||
if ((cmd_sts & TXDESC_LAST) && (cmd_sts & TXDESC_ERROR)) {
|
||||
dev_err(&edev->dev, "transmit error %d\n",
|
||||
(cmd_sts & TXDESC_ERROR_MASK) >> TXDESC_ERROR_SHIFT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_recv(struct eth_device *edev)
|
||||
{
|
||||
struct port_priv *port = edev->priv;
|
||||
struct rxdesc *rxdesc = port->current_rxdesc;
|
||||
u32 cmd_sts;
|
||||
int ret = 0;
|
||||
|
||||
/* wait for received packet */
|
||||
if (readl(&rxdesc->cmd_sts) & RXDESC_OWNED_BY_DMA)
|
||||
return 0;
|
||||
|
||||
/* drop malicious packets */
|
||||
cmd_sts = readl(&rxdesc->cmd_sts);
|
||||
if ((cmd_sts & (RXDESC_FIRST | RXDESC_LAST)) !=
|
||||
(RXDESC_FIRST | RXDESC_LAST)) {
|
||||
dev_err(&edev->dev, "rx packet spread on multiple descriptors\n");
|
||||
ret = -EIO;
|
||||
goto recv_err;
|
||||
}
|
||||
|
||||
if (cmd_sts & RXDESC_ERROR) {
|
||||
dev_err(&edev->dev, "receive error %d\n",
|
||||
(cmd_sts & RXDESC_ERROR_MASK) >> RXDESC_ERROR_SHIFT);
|
||||
ret = -EIO;
|
||||
goto recv_err;
|
||||
}
|
||||
|
||||
/* invalidate current receive buffer */
|
||||
dma_inv_range((unsigned long)rxdesc->buf_ptr,
|
||||
(unsigned long)rxdesc->buf_ptr +
|
||||
ALIGN(PKTSIZE, 8));
|
||||
|
||||
/* received packet is padded with two null bytes */
|
||||
net_receive(rxdesc->buf_ptr + 0x2, rxdesc->byte_cnt - 0x2);
|
||||
ret = 0;
|
||||
|
||||
recv_err:
|
||||
/* reset this and get next rx descriptor*/
|
||||
rxdesc->byte_cnt = 0;
|
||||
rxdesc->buf_size = ALIGN(PKTSIZE, 8);
|
||||
rxdesc->cmd_sts = RXDESC_OWNED_BY_DMA;
|
||||
writel((u32)rxdesc->nxtdesc, &port->current_rxdesc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int port_set_ethaddr(struct eth_device *edev, unsigned char *mac)
|
||||
{
|
||||
struct port_priv *port = edev->priv;
|
||||
u32 mac_h = (mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | mac[3];
|
||||
u32 mac_l = (mac[4] << 8) | mac[5];
|
||||
|
||||
port_clear_mac_tables(port);
|
||||
|
||||
writel(mac_l, port->regs + PORT_MACAL);
|
||||
writel(mac_h, port->regs + PORT_MACAH);
|
||||
|
||||
/* accept frames for this address */
|
||||
port_set_unicast_filter(port, mac[5], ACCEPT_MAC_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_get_ethaddr(struct eth_device *edev, unsigned char *mac)
|
||||
{
|
||||
struct port_priv *port = edev->priv;
|
||||
u32 reg;
|
||||
|
||||
reg = readl(port->regs + PORT_MACAH);
|
||||
mac[0] = (u8)(reg >> 24) & 0xff;
|
||||
mac[1] = (u8)(reg >> 16) & 0xff;
|
||||
mac[2] = (u8)(reg >> 8) & 0xff;
|
||||
mac[3] = (u8)reg & 0xff;
|
||||
|
||||
reg = readl(port->regs + PORT_MACAL);
|
||||
mac[4] = (u8)(reg >> 8) & 0xff;
|
||||
mac[5] = (u8)reg & 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_open(struct eth_device *edev)
|
||||
{
|
||||
struct port_priv *port = edev->priv;
|
||||
|
||||
/* enable receive queue */
|
||||
writel(BIT(URXQ), port->regs + PORT_RQC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void port_adjust_link(struct eth_device *edev)
|
||||
{
|
||||
struct port_priv *port = edev->priv;
|
||||
struct phy_device *phy = edev->phydev;
|
||||
u32 reg;
|
||||
|
||||
/* disable port */
|
||||
reg = readl(port->regs + PORT_SC0);
|
||||
reg &= ~PORT_ENABLE;
|
||||
writel(reg, port->regs + PORT_SC0);
|
||||
|
||||
/* setup and enable port */
|
||||
reg &= ~(SET_SPEED_MASK | SET_FULL_DUPLEX | SET_FLOWCTRL_ENABLE);
|
||||
if (phy->speed == SPEED_1000)
|
||||
reg |= SET_SPEED_1000;
|
||||
else if (phy->speed == SPEED_100)
|
||||
reg |= SET_SPEED_100;
|
||||
else if (phy->speed == SPEED_10)
|
||||
reg |= SET_SPEED_10;
|
||||
if (phy->duplex)
|
||||
reg |= SET_FULL_DUPLEX;
|
||||
if (phy->pause)
|
||||
reg |= SET_FLOWCTRL_ENABLE;
|
||||
reg |= FORCE_LINK_PASS | FORCE_NO_LINK_FAIL | PORT_ENABLE;
|
||||
|
||||
writel(reg, port->regs + PORT_SC0);
|
||||
}
|
||||
|
||||
static int port_probe(struct device_d *parent, struct port_priv *port)
|
||||
{
|
||||
struct device_node *phynp;
|
||||
phy_interface_t intf = PHY_INTERFACE_MODE_RGMII;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
/* assume port0 but warn on missing port reg property */
|
||||
if (of_property_read_u32(port->np, "reg", &port->portno))
|
||||
dev_warn(parent, "port node is missing reg property\n");
|
||||
|
||||
phynp = of_parse_phandle(port->np, "phy-handle", 0);
|
||||
if (phynp) {
|
||||
ret = of_get_phy_mode(port->np);
|
||||
if (ret > 0)
|
||||
intf = ret;
|
||||
}
|
||||
|
||||
port->regs = dev_get_mem_region(parent, 0) + PORTn_REGS(port->portno);
|
||||
|
||||
/* allocate rx/tx descriptors and buffers */
|
||||
port->txdesc = dma_alloc_coherent(ALIGN(sizeof(*port->txdesc), 16));
|
||||
port->rxdesc = dma_alloc_coherent(RX_RING_SIZE *
|
||||
ALIGN(sizeof(*port->rxdesc), 16));
|
||||
port->rxbuf = dma_alloc(RX_RING_SIZE * ALIGN(PKTSIZE, 8));
|
||||
|
||||
port_stop(port);
|
||||
port_init_rxdesc_ring(port);
|
||||
|
||||
/* disable port bandwidth limitation */
|
||||
writel(~0, port->regs + PORT_TQTBCNT(UTXQ));
|
||||
writel(~0, port->regs + PORT_TQTBC(UTXQ));
|
||||
writel(0, port->regs + PORT_MTU);
|
||||
/* assign initial rx descriptor */
|
||||
writel((u32)port->current_rxdesc, port->regs + PORT_CRDP(URXQ));
|
||||
/* setup SDMA with maximum burst and no swap */
|
||||
reg = RX_BURST_SIZE_16 | RX_BLM_NO_SWAP |
|
||||
TX_BURST_SIZE_16 | TX_BLM_NO_SWAP;
|
||||
writel(reg, port->regs + PORT_SDC);
|
||||
|
||||
/* port configuration */
|
||||
reg = DEFAULT_RXQ(URXQ) | DEFAULT_ARPQ(URXQ);
|
||||
writel(reg, port->regs + PORT_C);
|
||||
writel(0, port->regs + PORT_CX);
|
||||
|
||||
reg = SC0_RESERVED | MRU_1518;
|
||||
reg |= DISABLE_ANEG_DUPLEX | DISABLE_ANEG_FLOWCTRL | DISABLE_ANEG_SPEED;
|
||||
writel(reg, port->regs + PORT_SC0);
|
||||
|
||||
reg = SC1_RESERVED;
|
||||
reg |= DEFAULT_COL_LIMIT | COL_ON_BACKPRESS | INBAND_ANEG_BYPASS;
|
||||
if (intf == PHY_INTERFACE_MODE_RGMII)
|
||||
reg |= RGMII_ENABLE;
|
||||
writel(reg, port->regs + PORT_SC1);
|
||||
|
||||
/* register eth device */
|
||||
port->edev.priv = port;
|
||||
port->edev.open = port_open;
|
||||
port->edev.send = port_send;
|
||||
port->edev.recv = port_recv;
|
||||
port->edev.halt = port_halt;
|
||||
port->edev.set_ethaddr = port_set_ethaddr;
|
||||
port->edev.get_ethaddr = port_get_ethaddr;
|
||||
port->edev.parent = parent;
|
||||
|
||||
ret = eth_register(&port->edev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* attach phy device */
|
||||
if (phynp) {
|
||||
ret = of_phy_device_connect(&port->edev, phynp,
|
||||
port_adjust_link, 0, intf);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int orion_gbe_probe(struct device_d *dev)
|
||||
{
|
||||
struct orion_gbe *gbe;
|
||||
struct port_priv *ppriv;
|
||||
struct device_node *pnp;
|
||||
int ret;
|
||||
|
||||
gbe = xzalloc(sizeof(*gbe));
|
||||
dev->priv = gbe;
|
||||
|
||||
gbe->regs = dev_get_mem_region(dev, 0);
|
||||
gbe->clk = clk_get(dev, 0);
|
||||
if (!IS_ERR(gbe->clk))
|
||||
clk_enable(gbe->clk);
|
||||
|
||||
eunit_set_dram_access(gbe);
|
||||
|
||||
/*
|
||||
* Orion SoCs only have one port per controller, but the
|
||||
* IP itself supports more than one port per controller.
|
||||
* Although untested, the driver should also be able to
|
||||
* deal with multi-port controllers.
|
||||
*/
|
||||
for_each_child_of_node(dev->device_node, pnp)
|
||||
gbe->num_ports++;
|
||||
|
||||
gbe->ports = xzalloc(gbe->num_ports * sizeof(*gbe->ports));
|
||||
|
||||
ppriv = gbe->ports;
|
||||
for_each_child_of_node(dev->device_node, pnp) {
|
||||
ppriv->np = pnp;
|
||||
|
||||
ret = port_probe(dev, ppriv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ppriv++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void orion_gbe_remove(struct device_d *dev)
|
||||
{
|
||||
struct orion_gbe *gbe = dev->priv;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < gbe->num_ports; n++)
|
||||
port_halt(&gbe->ports[n].edev);
|
||||
|
||||
/* disable all address windows */
|
||||
writel(~0, gbe->regs + EUNIT_BARE);
|
||||
|
||||
if (!IS_ERR(gbe->clk))
|
||||
clk_disable(gbe->clk);
|
||||
}
|
||||
|
||||
static struct of_device_id orion_gbe_dt_ids[] = {
|
||||
{ .compatible = "marvell,orion-eth", },
|
||||
{ .compatible = "marvell,kirkwood-eth", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct driver_d orion_gbe_driver = {
|
||||
.name = "orion-gbe",
|
||||
.probe = orion_gbe_probe,
|
||||
.remove = orion_gbe_remove,
|
||||
.of_compatible = DRV_OF_COMPAT(orion_gbe_dt_ids),
|
||||
};
|
||||
device_platform_driver(orion_gbe_driver);
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* (C) Copyright 2014
|
||||
* Pengutronix, Michael Grzeschik <mgr@pengutronix.de>
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* based on kirkwood_egiga driver from u-boot
|
||||
* (C) Copyright 2009
|
||||
* Marvell Semiconductor <www.marvell.com>
|
||||
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
|
||||
*
|
||||
* based on - Driver for MV64360X ethernet ports
|
||||
* Copyright (C) 2002 rabeeh@galileo.co.il
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __ORION_GBE_
|
||||
#define __ORION_GBE_
|
||||
|
||||
/* Ethernet Unit Base Address */
|
||||
#define EUNIT_BA(x) (0x200 + (x) * 0x8)
|
||||
/* Ethernet Unit Size */
|
||||
#define EUNIT_S(x) (0x204 + (x) * 0x8)
|
||||
/* Ethernet Unit High Address */
|
||||
#define EUNIT_HA(x) (0x280 + (x) * 0x4)
|
||||
/* Ethernet Unit Base Address Enable */
|
||||
#define EUNIT_BARE 0x290
|
||||
/* Ethernet Unit Port Access Protect */
|
||||
#define EUNIT_PAP 0x294
|
||||
#define NO_ACCESS 0
|
||||
#define ACCESS_READ_ONLY 1
|
||||
#define ACCESS_FULL 3
|
||||
|
||||
/* Port Registers Offset */
|
||||
#define PORTn_REGS(x) (0x400 + (x) * 0x400)
|
||||
/* Port Configuration */
|
||||
#define PORT_C 0x000
|
||||
#define PROMISCUOUS_MODE BIT(0)
|
||||
#define DEFAULT_RXQ(x) ((x) << 1)
|
||||
#define DEFAULT_ARPQ(x) ((x) << 4)
|
||||
#define BCAST_OTHER_REJECT BIT(7)
|
||||
#define BCAST_IP_REJECT BIT(8)
|
||||
#define BCAST_ARP_REJECT BIT(9)
|
||||
#define AUTO_SET_NO_TX_ERR BIT(12)
|
||||
#define TCPQ_CAPTURE_ENABLE BIT(14)
|
||||
#define UDPQ_CAPTURE_ENABLE BIT(15)
|
||||
#define DEFAULT_TCPQ(x) ((x) << 16)
|
||||
#define DEFAULT_UDPQ(x) ((x) << 19)
|
||||
#define DEFAULT_BPDUQ(x) ((x) << 22)
|
||||
#define RX_TCP_CHKSUM_HEADER BIT(25)
|
||||
/* Port Configuration Extended */
|
||||
#define PORT_CX 0x004
|
||||
#define TX_CRC_GEN_DISABLE BIT(3)
|
||||
#define BPDUQ_CAPTURE_ENABLE BIT(0)
|
||||
/* Port MAC Address High */
|
||||
#define PORT_MACAL 0x014
|
||||
/* Port MAC Address Low */
|
||||
#define PORT_MACAH 0x018
|
||||
/* Port SDMA Configuration */
|
||||
#define PORT_SDC 0x01c
|
||||
#define TX_BURST_SIZE_1 (0 << 22)
|
||||
#define TX_BURST_SIZE_2 (1 << 22)
|
||||
#define TX_BURST_SIZE_4 (2 << 22)
|
||||
#define TX_BURST_SIZE_8 (3 << 22)
|
||||
#define TX_BURST_SIZE_16 (4 << 22)
|
||||
#define TX_BLM_SWAP (0 << 5)
|
||||
#define TX_BLM_NO_SWAP (1 << 5)
|
||||
#define RX_BLM_SWAP (0 << 4)
|
||||
#define RX_BLM_NO_SWAP (1 << 4)
|
||||
#define RX_BURST_SIZE_1 (0 << 1)
|
||||
#define RX_BURST_SIZE_2 (1 << 1)
|
||||
#define RX_BURST_SIZE_4 (2 << 1)
|
||||
#define RX_BURST_SIZE_8 (3 << 1)
|
||||
#define RX_BURST_SIZE_16 (4 << 1)
|
||||
/* Port Serial Control 0 */
|
||||
#define PORT_SC0 0x03c
|
||||
#define SC0_RESERVED BIT(9)
|
||||
#define PORT_ENABLE BIT(0)
|
||||
#define FORCE_LINK_PASS BIT(1)
|
||||
#define DISABLE_ANEG_DUPLEX BIT(2)
|
||||
#define DISABLE_ANEG_FLOWCTRL BIT(3)
|
||||
#define ADVERTISE_PAUSE BIT(4)
|
||||
#define FORCE_FLOWCTRL_OFF (0 << 5)
|
||||
#define FORCE_FLOWCTRL_ON (1 << 5)
|
||||
#define FORCE_FLOWCTRL_MASK (3 << 5)
|
||||
#define FORCE_BACKPRESS_NO_JAM (0 << 7)
|
||||
#define FORCE_BACKPRESS_JAM (1 << 7)
|
||||
#define FORCE_BACKPRESS_MASK (3 << 7)
|
||||
#define FORCE_NO_LINK_FAIL BIT(10)
|
||||
#define DISABLE_ANEG_SPEED BIT(13)
|
||||
#define ADVERTISE_DTE BIT(14)
|
||||
#define MII_PHY_MODE BIT(15)
|
||||
#define MII_SRC_SYNCHRONOUS BIT(16)
|
||||
#define MRU_1518 (0 << 17)
|
||||
#define MRU_1522 (1 << 17)
|
||||
#define MRU_1552 (2 << 17)
|
||||
#define MRU_9022 (3 << 17)
|
||||
#define MRU_9192 (4 << 17)
|
||||
#define MRU_9700 (5 << 17)
|
||||
#define MRU_MASK (7 << 17)
|
||||
#define SET_FULL_DUPLEX BIT(21)
|
||||
#define SET_FLOWCTRL_ENABLE BIT(22)
|
||||
#define SET_SPEED_1000 (1 << 23)
|
||||
#define SET_SPEED_10 (0 << 23)
|
||||
#define SET_SPEED_100 (2 << 23)
|
||||
#define SET_SPEED_MASK (3 << 23)
|
||||
/* Port Status 0 */
|
||||
#define PORT_S0 0x044
|
||||
/* Port Trasmit Queue Command */
|
||||
#define PORT_TQC 0x048
|
||||
/* Port Serial Control 1 */
|
||||
#define PORT_SC1 0x04c
|
||||
#define SC1_RESERVED (0x2 << 9)
|
||||
#define LOOPBACK_PCS BIT(1)
|
||||
#define RGMII_ENABLE BIT(3)
|
||||
#define PORT_RESET BIT(4)
|
||||
#define CLK125_BYPASS BIT(5)
|
||||
#define INBAND_ANEG BIT(6)
|
||||
#define INBAND_ANEG_BYPASS BIT(7)
|
||||
#define INBAND_ANEG_RESTART BIT(8)
|
||||
#define LIMIT_TO_1000BASEX BIT(11)
|
||||
#define COL_ON_BACKPRESS BIT(15)
|
||||
#define COL_LIMIT(x) (((x) & 0xfff) << 16)
|
||||
#define DEFAULT_COL_LIMIT COL_LIMIT(0x23)
|
||||
#define COL_ON_BACKPRESS BIT(15)
|
||||
#define EN_MII_ODD_PREAMBLE BIT(22)
|
||||
/* Port Status 1 */
|
||||
#define PORT_S1 0x050
|
||||
/* Port Interrupt Cause */
|
||||
#define PORT_IC 0x060
|
||||
/* Port Interrupt Mask */
|
||||
#define PORT_IM 0x068
|
||||
#define INT_SUM BIT(31)
|
||||
#define TX_END BIT(19)
|
||||
#define RXQ_ERR (15 << 11)
|
||||
#define RX_ERR BIT(10)
|
||||
#define TXQ_ERR (15 << 2)
|
||||
#define EXTENDED_INT BIT(1)
|
||||
#define RX_RETURN BIT(0)
|
||||
/* Port Extended Interrupt Cause */
|
||||
#define PORT_EIC 0x064
|
||||
/* Port Extended Interrupt Mask */
|
||||
#define PORT_EIM 0x06c
|
||||
#define EXTENDED_INT_SUM BIT(31)
|
||||
#define PRBS_ERR BIT(25)
|
||||
#define INTERNAL_ADDR_ERR BIT(23)
|
||||
#define LINK_CHANGE BIT(20)
|
||||
#define TX_UNDERRUN BIT(19)
|
||||
#define RX_OVERRUN BIT(18)
|
||||
#define PHY_CHANGE BIT(16)
|
||||
#define TX_ERR BIT(8)
|
||||
#define TX_RETURN BIT(0)
|
||||
/* Port Maximum Transmit Unit */
|
||||
#define PORT_MTU 0x0e8
|
||||
/* Port Current Receive Descriptor Pointer */
|
||||
#define PORT_CRDP(x) (0x20c + (x) * 0x10)
|
||||
/* Port Receive Queue Command */
|
||||
#define PORT_RQC 0x280
|
||||
/* Port Transmit Current Queue Descriptor Pointer */
|
||||
#define PORT_TCQDP(x) (0x2c0 + (x) * 0x04)
|
||||
/* Port Transmit Queue Token Bucket Counter */
|
||||
#define PORT_TQTBCNT(x) (0x300 + (x) * 0x10)
|
||||
/* Port Transmit Queue Token Bucket Configuration */
|
||||
#define PORT_TQTBC(x) (0x304 + (x) * 0x10)
|
||||
|
||||
#define PORT_DFSMT(x) (0x1000 + ((x) * 0x04))
|
||||
#define PORT_DFOMT(x) (0x1100 + ((x) * 0x04))
|
||||
#define PORT_DFUT(x) (0x1200 + ((x) * 0x04))
|
||||
|
||||
#define DFT_ENTRY_MASK 0xff
|
||||
#define DFT_ENTRY_SIZE 8
|
||||
#define DFT_QUEUE_SHIFT 1
|
||||
#define DFT_PASS BIT(0)
|
||||
|
||||
#define RXDESC_ERROR BIT(0)
|
||||
#define RXDESC_ERROR_CRC (0 << 1)
|
||||
#define RXDESC_ERROR_OVERRUN (1 << 1)
|
||||
#define RXDESC_ERROR_MAXLEN (2 << 1)
|
||||
#define RXDESC_ERROR_RESOURCE (3 << 1)
|
||||
#define RXDESC_ERROR_MASK (3 << 1)
|
||||
#define RXDESC_ERROR_SHIFT 1
|
||||
#define RXDESC_L4_CHECKSUM(x) (((x) & (0xffff << 3)) >> 3)
|
||||
#define RXDESC_VLAN_TAGGED BIT(19)
|
||||
#define RXDESC_BDPU BIT(20)
|
||||
#define RXDESC_FRAME_TCP (0 << 21)
|
||||
#define RXDESC_FRAME_UDP (1 << 21)
|
||||
#define RXDESC_FRAME_OTHER (2 << 21)
|
||||
#define RXDESC_FRAME_MASK (3 << 21)
|
||||
#define RXDESC_L2_IS_ETHERNET BIT(23)
|
||||
#define RXDESC_L4_IS_IPV4 BIT(24)
|
||||
#define RXDESC_L4_HEADER_OK BIT(25)
|
||||
#define RXDESC_LAST BIT(26)
|
||||
#define RXDESC_FIRST BIT(27)
|
||||
#define RXDESC_UNKNOWN_DEST BIT(28)
|
||||
#define RXDESC_ENABLE_IRQ BIT(29)
|
||||
#define RXDESC_L4_CHECKSUM_OK BIT(30)
|
||||
#define RXDESC_OWNED_BY_DMA BIT(31)
|
||||
|
||||
#define RXDESC_BYTECOUNT_FRAG BIT(2)
|
||||
|
||||
#define TXDESC_ERROR BIT(0)
|
||||
#define TXDESC_ERROR_LATE_COLL (0 << 1)
|
||||
#define TXDESC_ERROR_UNDERRUN (1 << 1)
|
||||
#define TXDESC_ERROR_RET_LIMIT (2 << 1)
|
||||
#define TXDESC_ERROR_MASK (3 << 1)
|
||||
#define TXDESC_ERROR_SHIFT 1
|
||||
#define TXDESC_LCC_SNAP BIT(9)
|
||||
#define TXDESC_L4_CHK_FIRST BIT(10)
|
||||
#define TXDESC_IPV4_HEADER_LEN(x) (((x) & 0xf) << 11)
|
||||
#define TXDESC_VLAN_TAGGED BIT(15)
|
||||
#define TXDESC_FRAME_TCP (0 << 16)
|
||||
#define TXDESC_FRAME_UDP (1 << 16)
|
||||
#define TXDESC_GEN_FRAME_CHECKSUM BIT(17)
|
||||
#define TXDESC_GEN_IPV4_CHECKSUM BIT(18)
|
||||
#define TXDESC_ZERO_PADDING BIT(19)
|
||||
#define TXDESC_LAST BIT(20)
|
||||
#define TXDESC_FIRST BIT(21)
|
||||
#define TXDESC_GEN_CRC BIT(22) /* Orion5x only */
|
||||
#define TXDESC_ENABLE_IRQ BIT(23)
|
||||
#define TXDESC_NO_AUTO_RETURN BIT(30)
|
||||
#define TXDESC_OWNED_BY_DMA BIT(31)
|
||||
|
||||
#endif
|
|
@ -33,6 +33,14 @@ config SMSC_PHY
|
|||
---help---
|
||||
Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
|
||||
|
||||
comment "MII bus device drivers"
|
||||
|
||||
config MDIO_MVEBU
|
||||
bool "Driver for MVEBU SoC MDIO bus"
|
||||
depends on ARCH_MVEBU
|
||||
---help---
|
||||
Driver for the MDIO bus found on Marvell EBU SoCs.
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -4,3 +4,5 @@ obj-$(CONFIG_LXT_PHY) += lxt.o
|
|||
obj-$(CONFIG_MICREL_PHY) += micrel.o
|
||||
obj-$(CONFIG_NATIONAL_PHY) += national.o
|
||||
obj-$(CONFIG_SMSC_PHY) += smsc.o
|
||||
|
||||
obj-$(CONFIG_MDIO_MVEBU) += mdio-mvebu.o
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Marvell MVEBU SoC MDIO interface driver
|
||||
*
|
||||
* (C) Copyright 2014
|
||||
* Pengutronix, Michael Grzeschik <mgr@pengutronix.de>
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* based on mvmdio driver from Linux
|
||||
* Copyright (C) 2012 Marvell
|
||||
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
*
|
||||
* Since the MDIO interface of Marvell network interfaces is shared
|
||||
* between all network interfaces, having a single driver allows to
|
||||
* handle concurrent accesses properly (you may have four Ethernet
|
||||
* ports, but they in fact share the same SMI interface to access
|
||||
* the MDIO bus). This driver is currently used by the mvneta and
|
||||
* mv643xx_eth drivers.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <clock.h>
|
||||
#include <common.h>
|
||||
#include <driver.h>
|
||||
#include <init.h>
|
||||
#include <io.h>
|
||||
#include <of.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
#define SMI_DATA_SHIFT 0
|
||||
#define SMI_PHY_ADDR_SHIFT 16
|
||||
#define SMI_PHY_REG_SHIFT 21
|
||||
#define SMI_READ_OPERATION BIT(26)
|
||||
#define SMI_WRITE_OPERATION 0
|
||||
#define SMI_READ_VALID BIT(27)
|
||||
#define SMI_BUSY BIT(28)
|
||||
#define ERR_INT_CAUSE 0x007C
|
||||
#define ERR_INT_SMI_DONE BIT(4)
|
||||
#define ERR_INT_MASK BIT(7)
|
||||
|
||||
struct mdio_priv {
|
||||
struct mii_bus miibus;
|
||||
void __iomem *regs;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
#define SMI_POLL_TIMEOUT (10 * MSECOND)
|
||||
|
||||
static int mvebu_mdio_wait_ready(struct mdio_priv *priv)
|
||||
{
|
||||
int ret = wait_on_timeout(SMI_POLL_TIMEOUT,
|
||||
(readl(priv->regs) & SMI_BUSY) == 0);
|
||||
|
||||
if (ret)
|
||||
dev_err(&priv->miibus.dev, "timeout, SMI busy for too long\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mvebu_mdio_read(struct mii_bus *bus, int addr, int reg)
|
||||
{
|
||||
struct mdio_priv *priv = bus->priv;
|
||||
u32 smi;
|
||||
int ret;
|
||||
|
||||
ret = mvebu_mdio_wait_ready(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
smi = SMI_READ_OPERATION;
|
||||
smi |= (addr << SMI_PHY_ADDR_SHIFT) | (reg << SMI_PHY_REG_SHIFT);
|
||||
writel(smi, priv->regs);
|
||||
|
||||
ret = mvebu_mdio_wait_ready(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
smi = readl(priv->regs);
|
||||
if ((smi & SMI_READ_VALID) == 0) {
|
||||
dev_err(&bus->dev, "SMI bus read not valid\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return smi & 0xFFFF;
|
||||
}
|
||||
|
||||
static int mvebu_mdio_write(struct mii_bus *bus, int addr, int reg, u16 data)
|
||||
{
|
||||
struct mdio_priv *priv = bus->priv;
|
||||
u32 smi;
|
||||
int ret;
|
||||
|
||||
ret = mvebu_mdio_wait_ready(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
smi = SMI_WRITE_OPERATION;
|
||||
smi |= (addr << SMI_PHY_ADDR_SHIFT) | (reg << SMI_PHY_REG_SHIFT);
|
||||
smi |= data << SMI_DATA_SHIFT;
|
||||
writel(smi, priv->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_mdio_probe(struct device_d *dev)
|
||||
{
|
||||
struct mdio_priv *priv;
|
||||
|
||||
priv = xzalloc(sizeof(*priv));
|
||||
dev->priv = priv;
|
||||
|
||||
priv->regs = dev_get_mem_region(dev, 0);
|
||||
if (!priv->regs)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->clk = clk_get(dev, NULL);
|
||||
if (!IS_ERR(priv->clk))
|
||||
clk_enable(priv->clk);
|
||||
|
||||
priv->miibus.priv = priv;
|
||||
priv->miibus.parent = dev;
|
||||
priv->miibus.read = mvebu_mdio_read;
|
||||
priv->miibus.write = mvebu_mdio_write;
|
||||
|
||||
return mdiobus_register(&priv->miibus);
|
||||
}
|
||||
|
||||
static void mvebu_mdio_remove(struct device_d *dev)
|
||||
{
|
||||
struct mdio_priv *priv = dev->priv;
|
||||
|
||||
mdiobus_unregister(&priv->miibus);
|
||||
|
||||
if (!IS_ERR(priv->clk))
|
||||
clk_disable(priv->clk);
|
||||
}
|
||||
|
||||
static struct of_device_id mvebu_mdio_dt_ids[] = {
|
||||
{ .compatible = "marvell,orion-mdio" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct driver_d mvebu_mdio_driver = {
|
||||
.name = "mvebu-mdio",
|
||||
.probe = mvebu_mdio_probe,
|
||||
.remove = mvebu_mdio_remove,
|
||||
.of_compatible = DRV_OF_COMPAT(mvebu_mdio_dt_ids),
|
||||
};
|
||||
device_platform_driver(mvebu_mdio_driver);
|
|
@ -331,6 +331,37 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OFTREE)
|
||||
int of_phy_device_connect(struct eth_device *edev, struct device_node *phy_np,
|
||||
void (*adjust_link) (struct eth_device *edev),
|
||||
u32 flags, phy_interface_t interface)
|
||||
{
|
||||
struct device_node *bus_np;
|
||||
struct mii_bus *miibus;
|
||||
int phy_addr = -ENODEV;
|
||||
|
||||
if (!phy_np)
|
||||
return -EINVAL;
|
||||
|
||||
of_property_read_u32(phy_np, "reg", &phy_addr);
|
||||
|
||||
bus_np = of_get_parent(phy_np);
|
||||
if (!bus_np)
|
||||
return -ENODEV;
|
||||
|
||||
for_each_mii_bus(miibus) {
|
||||
if (miibus->parent && miibus->parent->device_node == bus_np)
|
||||
return phy_device_connect(edev, miibus, phy_addr,
|
||||
adjust_link, flags, interface);
|
||||
}
|
||||
|
||||
dev_err(&edev->dev, "unable to mdio bus for phy %s\n",
|
||||
phy_np->full_name);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generic PHY support and helper functions */
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Marvell MBUS common definitions.
|
||||
*
|
||||
* Copyright (C) 2008 Marvell Semiconductor
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MBUS_H
|
||||
#define __LINUX_MBUS_H
|
||||
|
||||
struct resource;
|
||||
|
||||
struct mbus_dram_target_info {
|
||||
/*
|
||||
* The 4-bit MBUS target ID of the DRAM controller.
|
||||
*/
|
||||
u8 mbus_dram_target_id;
|
||||
|
||||
/*
|
||||
* The base address, size, and MBUS attribute ID for each
|
||||
* of the possible DRAM chip selects. Peripherals are
|
||||
* required to support at least 4 decode windows.
|
||||
*/
|
||||
int num_cs;
|
||||
struct mbus_dram_window {
|
||||
u8 cs_index;
|
||||
u8 mbus_attr;
|
||||
u32 base;
|
||||
u32 size;
|
||||
} cs[4];
|
||||
};
|
||||
|
||||
/* Flags for PCI/PCIe address decoding regions */
|
||||
#define MVEBU_MBUS_PCI_IO 0x1
|
||||
#define MVEBU_MBUS_PCI_MEM 0x2
|
||||
#define MVEBU_MBUS_PCI_WA 0x3
|
||||
|
||||
/*
|
||||
* Magic value that explicits that we don't need a remapping-capable
|
||||
* address decoding window.
|
||||
*/
|
||||
#define MVEBU_MBUS_NO_REMAP (0xffffffff)
|
||||
|
||||
/* Maximum size of a mbus window name */
|
||||
#define MVEBU_MBUS_MAX_WINNAME_SZ 32
|
||||
|
||||
const struct mbus_dram_target_info *mvebu_mbus_dram_info(void);
|
||||
void mvebu_mbus_get_pcie_mem_aperture(struct resource *res);
|
||||
void mvebu_mbus_get_pcie_io_aperture(struct resource *res);
|
||||
int mvebu_mbus_add_window_remap_by_id(unsigned int target,
|
||||
unsigned int attribute,
|
||||
phys_addr_t base, size_t size,
|
||||
phys_addr_t remap);
|
||||
int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute,
|
||||
phys_addr_t base, size_t size);
|
||||
int mvebu_mbus_del_window(phys_addr_t base, size_t size);
|
||||
|
||||
#endif /* __LINUX_MBUS_H */
|
|
@ -280,6 +280,20 @@ int phy_device_connect(struct eth_device *dev, struct mii_bus *bus, int addr,
|
|||
void (*adjust_link) (struct eth_device *edev),
|
||||
u32 flags, phy_interface_t interface);
|
||||
|
||||
#if defined(CONFIG_OFTREE)
|
||||
int of_phy_device_connect(struct eth_device *edev, struct device_node *phy_np,
|
||||
void (*adjust_link) (struct eth_device *edev),
|
||||
u32 flags, phy_interface_t interface);
|
||||
#else
|
||||
static inline int of_phy_device_connect(struct eth_device *edev,
|
||||
struct device_node *phy_np,
|
||||
void (*adjust_link) (struct eth_device *edev),
|
||||
u32 flags, phy_interface_t interface)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
int phy_update_status(struct phy_device *phydev);
|
||||
int phy_wait_aneg_done(struct phy_device *phydev);
|
||||
|
||||
|
|
|
@ -701,18 +701,18 @@ static int image_create_payload(void *payload_start, size_t payloadsz,
|
|||
if (ret < 0) {
|
||||
fprintf(stderr, "Cannot stat payload file %s\n",
|
||||
payload_filename);
|
||||
fclose(payload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fread(payload_start, s.st_size, 1, payload);
|
||||
fclose(payload);
|
||||
if (ret != 1) {
|
||||
fprintf(stderr, "Cannot read payload file %s\n",
|
||||
payload_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(payload);
|
||||
|
||||
*payload_checksum = image_checksum32(payload_start, payloadsz);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1343,6 +1343,7 @@ static int image_create(const char *input, const char *output,
|
|||
rewind(fcfg);
|
||||
|
||||
ret = image_create_config_parse(fcfg, image_cfg, &cfgn);
|
||||
fclose(fcfg);
|
||||
if (ret) {
|
||||
free(image_cfg);
|
||||
return -1;
|
||||
|
|
Loading…
Reference in New Issue