9
0
Fork 0

Merge branch 'for-next/marvell'

Conflicts:
	arch/arm/dts/Makefile
This commit is contained in:
Sascha Hauer 2014-03-07 09:25:02 +01:00
commit 2331b1d8e8
20 changed files with 2554 additions and 410 deletions

View File

@ -87,6 +87,7 @@ config ARCH_MVEBU
select CLKDEV_LOOKUP
select GPIOLIB
select HAS_DEBUG_LL
select MVEBU_MBUS
select OFTREE
config ARCH_MXS

View File

@ -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);
}

View File

@ -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

View File

@ -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";
};
};
};

View File

@ -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"; };
&eth { status = "okay"; };
&lcd0 {
status = "okay";
clocks = <&si5351 0>;
&ethphy {
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";
};
};

View File

@ -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 = <&ethphy>;
};
};
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>;
};
};
};
};

View File

@ -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

View File

@ -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

743
drivers/bus/mvebu-mbus.c Normal file
View File

@ -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);

View File

@ -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

View File

@ -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

541
drivers/net/orion-gbe.c Normal file
View File

@ -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);

236
drivers/net/orion-gbe.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 */
/**

61
include/linux/mbus.h Normal file
View File

@ -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 */

View File

@ -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);

View File

@ -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;