Message ID | 20130304204335.GA27437@amd.pavel.ucw.cz (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Pavel, On Mon, 2013-03-04 at 21:43 +0100, ZY - pavel wrote: > Hi! > > Below are changes that get MMC/ethernet working for me. Probably not > everything is strictly neccessary, I'll try to prune them some more. > > Strange thing is that enh_desc.c (disabling checksumming AFAICT) seems > to be neccessary for NFS to work. > > In the meantime... does it make sense to split simple changes and > submit them upstream? > > arch/arm/boot/dts/Makefile -- dtb files should be build, this can be > probably considered bugfix. > > socfpga.c: socfpga_cyclone5_restart() -- this is self-contained reset > function marked with "TODO". Alot of these changes have already been pull for 3.9. I have patches queued up for restart, hotplug and some other misc function for SOCFPGA. I am close to having a patch that enables SD/MMC, but that should go to Seungwon Jeon and Jaehoon Chung. Can you please coordinate with myself before sending such patches to the mailing list? Thanks, Dinh > > (patches are originally from Altera). > Signed-off-by: Pavel Machek <pavel@denx.de> > (but not for merge for now). > > Thanks, > Pavel > > diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile > index 5ebb44f..d675c986 100644 > --- a/arch/arm/boot/dts/Makefile > +++ b/arch/arm/boot/dts/Makefile > @@ -124,6 +124,9 @@ dtb-$(CONFIG_ARCH_SHMOBILE) += emev2-kzm9d.dtb \ > r8a7740-armadillo800eva.dtb \ > sh73a0-kzm9g.dtb \ > sh7372-mackerel.dtb > +dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_cyclone5.dtb\ > + socfpga_ice.dtb\ > + socfpga_vt.dtb > dtb-$(CONFIG_ARCH_SPEAR13XX) += spear1310-evb.dtb \ > spear1340-evb.dtb > dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \ > diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi > index 19aec42..c59ca7d 100644 > --- a/arch/arm/boot/dts/socfpga.dtsi > +++ b/arch/arm/boot/dts/socfpga.dtsi > @@ -23,8 +23,13 @@ > > aliases { > ethernet0 = &gmac0; > + ethernet1 = &gmac1; > serial0 = &uart0; > serial1 = &uart1; > + timer0 = &timer0; > + timer1 = &timer1; > + timer2 = &timer2; > + timer3 = &timer3; > }; > > cpus { > @@ -61,6 +66,21 @@ > interrupt-parent = <&intc>; > ranges; > > + agpio0: gpio@0xc0000000 { > + compatible = "altr,pio-1.0"; > + /* Register base 0xff200000 is for a light-weight bridge */ > + reg = <0xff200000 0x10>; > + width = <32>; > + /* There are 64 interrupts from the FPGA start at 72, so 45 has to be wrong */ > + interrupts = <0 45 4>; > + interrupt-controller; > + #interrupt-cells = <1>; > + gpio-controller; > + #gpio-cells = <2>; > + level_trigger = <0>; > + }; > + > + > amba { > compatible = "arm,amba-bus"; > #address-cells = <1>; > @@ -74,13 +94,62 @@ > }; > }; > > - gmac0: stmmac@ff700000 { > + clkmgr@ffd04000 { > + compatible = "altr,clk-mgr"; > + reg = <0xffd04000 0x1000>; > + }; > + > + > + gmac0: ethernet@ff700000 { > compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; > reg = <0xff700000 0x2000>; > interrupts = <0 115 4>; > interrupt-names = "macirq"; > mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ > - phy-mode = "gmii"; > + }; > + > + gmac1: ethernet@ff702000 { > + compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; > + reg = <0xff702000 0x2000>; > + interrupts = <0 120 4>; > + interrupt-names = "macirq"; > + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ > + }; > + > + gpio0: gpio@ff708000 { > + compatible = "snps,dw-gpio"; > + reg = <0xff708000 0x1000>; > + interrupts = <0 164 4>; > + width = <29>; > + virtual_irq_start = <257>; > + interrupt-controller; > + #interrupt-cells = <2>; > + gpio-controller; > + #gpio-cells = <2>; > + }; > + > + gpio1: gpio@ff709000 { > + compatible = "snps,dw-gpio"; > + reg = <0xff709000 0x1000>; > + interrupts = <0 165 4>; > + width = <29>; > + virtual_irq_start = <286>; > + interrupt-controller; > + #interrupt-cells = <2>; > + gpio-controller; > + #gpio-cells = <2>; > + }; > + > + gpio2: gpio@ff70a000 { > + compatible = "snps,dw-gpio"; > + reg = <0xff70a000 0x1000>; > + interrupts = <0 166 4>; > + width = <27>; > + virtual_irq_start = <315>; > + interrupt-controller; > + #interrupt-cells = <2>; > + gpio-controller; > + #gpio-cells = <2>; > }; > > L2: l2-cache@fffef000 { > @@ -89,6 +158,83 @@ > interrupts = <0 38 0x04>; > cache-unified; > cache-level = <2>; > + arm,tag-latency = <1 1 1>; > + arm,data-latency = <2 1 1>; > + }; > + > + mmc: dwmmc0@ff704000 { > + compatible = "snps,dw-mshc"; > + reg = <0xff704000 0x1000>; > + interrupts = <0 139 4>; > + bus-hz = <12500000>; /*12.5 MHz*/ > + #address-cells = <1>; > + #size-cells = <0>; > + num-slots = <1>; > + supports-highspeed; > + broken-cd; > + fifo-depth = <0x400>; > + slot@0 { > + reg = <0>; > + bus-width = <4>; > + }; > + }; > + > + nand: nand@ff900000 { > + #address-cells = <1>; > + #size-cells = <1>; > + compatible = "denali,denali-nand-dt"; > + reg = <0xff900000 0x100000>, <0xffb80000 0x10000>; > + reg-names = "nand_data", "denali_reg"; > + interrupts = <0 144 4>; > + dma-mask = <0xffffffff>; > + }; > + > + rstmgr@ffd05000 { > + compatible = "altr,rst-mgr"; > + reg = <0xffd05000 0x1000>; > + }; > + > + spi0: spi@fff00000 { > + compatible = "snps,dw-spi-mmio"; > + #address-cells = <1>; > + #size-cells = <0>; > + reg = <0xfff00000 0x1000>; > + interrupts = <0 154 4>; > + num-chipselect = <4>; > + bus-num = <0>; > + tx-dma-channel = <&pdma 16>; > + rx-dma-channel = <&pdma 17>; > + > + spidev@0 { > + compatible = "spidev"; > + reg = <0>; /* chip select */ > + spi-max-frequency = <100000000>; > + enable-dma = <1>; > + }; > + }; > + > + spi1: spi@fff01000 { > + compatible = "snps,dw-spi-mmio"; > + #address-cells = <1>; > + #size-cells = <0>; > + reg = <0xfff01000 0x1000>; > + interrupts = <0 156 4>; > + num-chipselect = <4>; > + bus-num = <1>; > + tx-dma-channel = <&pdma 20>; > + rx-dma-channel = <&pdma 21>; > + > + spidev@0 { > + compatible = "spidev"; > + reg = <0>; > + spi-max-frequency = <100000000>; > + enable-dma = <1>; > + }; > + }; > + > + sysmgr@ffd08000 { > + compatible = "altr,sys-mgr"; > + reg = <0xffd08000 0x4000>; > }; > > /* Local timer */ > @@ -98,60 +244,44 @@ > interrupts = <1 13 0xf04>; > }; > > - timer0: timer@ffc08000 { > + timer0: timer0@ffc08000 { > compatible = "snps,dw-apb-timer-sp"; > interrupts = <0 167 4>; > - clock-frequency = <200000000>; > reg = <0xffc08000 0x1000>; > }; > > - timer1: timer@ffc09000 { > + timer1: timer1@ffc09000 { > compatible = "snps,dw-apb-timer-sp"; > interrupts = <0 168 4>; > - clock-frequency = <200000000>; > reg = <0xffc09000 0x1000>; > }; > > - timer2: timer@ffd00000 { > + timer2: timer2@ffd00000 { > compatible = "snps,dw-apb-timer-osc"; > interrupts = <0 169 4>; > - clock-frequency = <200000000>; > reg = <0xffd00000 0x1000>; > }; > > - timer3: timer@ffd01000 { > + timer3: timer3@ffd01000 { > compatible = "snps,dw-apb-timer-osc"; > interrupts = <0 170 4>; > - clock-frequency = <200000000>; > reg = <0xffd01000 0x1000>; > }; > > - uart0: uart@ffc02000 { > + uart0: serial0@ffc02000 { > compatible = "snps,dw-apb-uart"; > reg = <0xffc02000 0x1000>; > - clock-frequency = <7372800>; > interrupts = <0 162 4>; > reg-shift = <2>; > reg-io-width = <4>; > }; > > - uart1: uart@ffc03000 { > + uart1: serial1@ffc03000 { > compatible = "snps,dw-apb-uart"; > reg = <0xffc03000 0x1000>; > - clock-frequency = <7372800>; > interrupts = <0 163 4>; > reg-shift = <2>; > reg-io-width = <4>; > }; > - > - rstmgr@ffd05000 { > - compatible = "altr,rst-mgr"; > - reg = <0xffd05000 0x1000>; > - }; > - > - sysmgr@ffd08000 { > - compatible = "altr,sys-mgr"; > - reg = <0xffd08000 0x4000>; > - }; > }; > }; > diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts > index ab7e4a9..d29addc 100644 > --- a/arch/arm/boot/dts/socfpga_cyclone5.dts > +++ b/arch/arm/boot/dts/socfpga_cyclone5.dts > @@ -26,9 +26,169 @@ > bootargs = "console=ttyS0,57600"; > }; > > - memory { > - name = "memory"; > - device_type = "memory"; > - reg = <0x0 0x10000000>; /* 256MB */ > + aliases { > + /* this allow the ethaddr uboot environmnet variable contents > + * to be added to the gmac1 device tree blob. > + */ > + ethernet0 = &gmac1; > + }; > + > + soc { > + ethernet@ff700000 { > + status = "disabled"; > + }; > + > + ethernet@ff702000 { > + phy-mode = "rgmii"; > + phy-addr = <0xffffffff>; /* probe for phy addr */ > + }; > + > + qspi: spi@ff705000 { > + compatible = "cadence,qspi"; > + #address-cells = <1>; > + #size-cells = <0>; > + reg = <0xff705000 0x1000>, > + <0xffa00000 0x1000>; > + interrupts = <0 151 4>; > + master-ref-clk = <400000000>; > + ext-decoder = <0>; /* external decoder */ > + num-chipselect = <4>; > + fifo-depth = <128>; > + bus-num = <2>; > + > + flash0: n25q128@0 { > + #address-cells = <1>; > + #size-cells = <1>; > + compatible = "n25q128"; > + reg = <0>; /* chip select */ > + spi-max-frequency = <100000000>; > + page-size = <256>; > + block-size = <16>; /* 2^16, 64KB */ > + quad = <1>; /* 1-support quad */ > + tshsl-ns = <200>; > + tsd2d-ns = <255>; > + tchsh-ns = <20>; > + tslch-ns = <20>; > + > + partition@0 { > + /* 8MB for raw data. */ > + label = "Flash 0 Raw Data"; > + reg = <0x0 0x800000>; > + }; > + partition@800000 { > + /* 8MB for jffs2 data. */ > + label = "Flash 0 jffs2 Filesystem"; > + reg = <0x800000 0x800000>; > + }; > + }; > + > + flash1: n25q128@1 { > + #address-cells = <1>; > + #size-cells = <1>; > + compatible = "n25q128"; > + reg = <1>; /* chip select */ > + spi-max-frequency = <100000000>; > + page-size = <256>; > + block-size = <16>; /* 2^16, 64KB */ > + quad = <1>; > + tshsl-ns = <200>; > + tsd2d-ns = <255>; > + tchsh-ns = <20>; > + tslch-ns = <20>; > + > + partition@0 { > + /* 16MB for user data. */ > + label = "Flash 1 User Data"; > + reg = <0x0 0x1000000>; > + }; > + }; > + }; > + > + timer0@ffc08000 { > + clock-frequency = <100000000>; > + }; > + > + timer1@ffc09000 { > + clock-frequency = <100000000>; > + }; > + > + timer2@ffd00000 { > + clock-frequency = <25000000>; > + }; > + > + timer3@ffd01000 { > + clock-frequency = <25000000>; > + }; > + > + serial0@ffc02000 { > + clock-frequency = <100000000>; > + }; > + > + serial1@ffc03000 { > + clock-frequency = <100000000>; > + }; > + > + i2c0: i2c@ffc04000 { > + speed-mode = <0>; > + }; > + > + leds { > + compatible = "gpio-leds"; > + fpga0 { > + label = "fpga_led0"; > + gpios = <&agpio0 0 1>; > + }; > + > + fpga1 { > + label = "fpga_led1"; > + gpios = <&agpio0 1 1>; > + }; > + > + fpga2 { > + label = "fpga_led2"; > + gpios = <&agpio0 2 1>; > + }; > + > + fpga3 { > + label = "fpga_led3"; > + gpios = <&agpio0 3 1>; > + }; > + > + hps0 { > + label = "hps_led0"; > + gpios = <&gpio1 15 1>; > + }; > + > + hps1 { > + label = "hps_led1"; > + gpios = <&gpio1 14 1>; > + }; > + > + hps2 { > + label = "hps_led2"; > + gpios = <&gpio1 13 1>; > + }; > + > + hps3 { > + label = "hps_led3"; > + gpios = <&gpio1 12 1>; > + }; > + }; > + }; > +}; > + > +&i2c0 { > + lcd: lcd@28 { > + compatible = "newhaven,nhd-0216k3z-nsw-bbw"; > + reg = <0x28>; > + height = <2>; > + width = <16>; > + brightness = <8>; > + }; > + > + eeprom@51 { > + compatible = "atmel,24c32"; > + reg = <0x51>; > + pagesize = <32>; > }; > }; > diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h > index 9941caa..e297307 100644 > --- a/arch/arm/mach-socfpga/core.h > +++ b/arch/arm/mach-socfpga/core.h > @@ -24,11 +24,34 @@ extern void secondary_startup(void); > extern void __iomem *socfpga_scu_base_addr; > > extern void socfpga_init_clocks(void); > -extern void socfpga_sysmgr_init(void); > +//extern void socfpga_sysmgr_init(void); > > extern struct smp_operations socfpga_smp_ops; > extern char secondary_trampoline, secondary_trampoline_end; > > #define SOCFPGA_SCU_VIRT_BASE 0xfffec000 > > + > +#define SOCFPGA_RSTMGR_CTRL 0x04 > +#define SOCFPGA_RSTMGR_MODPERRST 0x14 > +#define SOCFPGA_RSTMGR_BRGMODRST 0x1c > + > +/* System Manager bits */ > +#define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ > +#define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ > +/*MPU Module Reset Register */ > + #define RSTMGR_MPUMODRST_CPU0 0x1 /*CPU0 Reset*/ > + #define RSTMGR_MPUMODRST_CPU1 0x2 /*CPU1 Reset*/ > + #define RSTMGR_MPUMODRST_WDS 0x4 /*Watchdog Reset*/ > + #define RSTMGR_MPUMODRST_SCUPER 0x8 /*SCU and periphs reset*/ > + #define RSTMGR_MPUMODRST_L2 0x10 /*L2 Cache reset*/ > + > +#define SYSMGR_EMACGRP_CTRL_OFFSET 0x60 > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 > + > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 > + > #endif > diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c > index 6732924..4d41642 100644 > --- a/arch/arm/mach-socfpga/socfpga.c > +++ b/arch/arm/mach-socfpga/socfpga.c > @@ -17,12 +17,19 @@ > #include <linux/dw_apb_timer.h> > #include <linux/of_address.h> > #include <linux/of_irq.h> > +#include <linux/of_address.h> > #include <linux/of_platform.h> > +#include <linux/of_net.h> > +#include <linux/stmmac.h> > +#include <linux/phy.h> > +#include <linux/micrel_phy.h> > + > > #include <asm/hardware/cache-l2x0.h> > #include <asm/hardware/gic.h> > #include <asm/mach/arch.h> > #include <asm/mach/map.h> > +#include <asm/smp_twd.h> > > #include "core.h" > > @@ -30,6 +37,29 @@ void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE)); > void __iomem *sys_manager_base_addr; > void __iomem *rst_manager_base_addr; > > +static int socfpga_phy_reset_mii(struct mii_bus *bus, int phyaddr); > +static int stmmac_plat_init(struct platform_device *pdev); > + > +static struct stmmac_mdio_bus_data stmmacenet_mdio_bus_data = { > + .phy_reset_mii = socfpga_phy_reset_mii, > +}; > + > +static struct plat_stmmacenet_data stmmacenet0_data = { > + .mdio_bus_data = &stmmacenet_mdio_bus_data, > + .init = &stmmac_plat_init, > +}; > + > +static struct plat_stmmacenet_data stmmacenet1_data = { > + .mdio_bus_data = &stmmacenet_mdio_bus_data, > + .init = &stmmac_plat_init, > +}; > + > +static const struct of_dev_auxdata socfpga_auxdata_lookup[] __initconst = { > + OF_DEV_AUXDATA("snps,dwmac-3.70a", 0xff700000, NULL, &stmmacenet0_data), > + OF_DEV_AUXDATA("snps,dwmac-3.70a", 0xff702000, NULL, &stmmacenet1_data), > + { /* sentinel */ } > +}; > + > static struct map_desc scu_io_desc __initdata = { > .virtual = SOCFPGA_SCU_VIRT_BASE, > .pfn = 0, /* run-time */ > @@ -55,19 +85,126 @@ static void __init socfpga_scu_map_io(void) > iotable_init(&scu_io_desc, 1); > } > > -static void __init socfpga_map_io(void) > +static void __init enable_periphs(void) > { > - socfpga_scu_map_io(); > - iotable_init(&uart_io_desc, 1); > - early_printk("Early printk initialized\n"); > + /* Release all peripherals from reset.*/ > + __raw_writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODPERRST); > + > + /* Release all FPGA bridges from reset.*/ > + __raw_writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_BRGMODRST); > } > > -const static struct of_device_id irq_match[] = { > - { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, > - {} > -}; > +static int stmmac_mdio_write_null(struct mii_bus *bus, int phyaddr, int phyreg, > + u16 phydata) > +{ > + return 0; > +} > + > +#define MICREL_KSZ9021_EXTREG_CTRL 11 > +#define MICREL_KSZ9021_EXTREG_DATA_WRITE 12 > +#define MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW 260 > +#define MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW 261 > > -void __init socfpga_sysmgr_init(void) > +static int stmmac_emdio_write(struct mii_bus *bus, int phyaddr, int phyreg, > + u16 phydata) > +{ > + int ret = (bus->write)(bus, phyaddr, > + MICREL_KSZ9021_EXTREG_CTRL, 0x8000|phyreg); > + if (ret) { > + pr_warn("stmmac_emdio_write write1 failed %d\n", ret); > + return ret; > + } > + > + ret = (bus->write)(bus, phyaddr, > + MICREL_KSZ9021_EXTREG_DATA_WRITE, phydata); > + if (ret) { > + pr_warn("stmmac_emdio_write write2 failed %d\n", ret); > + return ret; > + } > + > + return ret; > +} > + > +static int socfpga_phy_reset_mii(struct mii_bus *bus, int phyaddr) > +{ > + struct phy_device *phydev; > + > + if (of_machine_is_compatible("altr,socfpga-vt")) > + return 0; > + > + phydev = bus->phy_map[phyaddr]; > + > + if (NULL == phydev) { > + pr_err("%s no phydev found\n", __func__); > + return -EINVAL; > + } > + > + if (PHY_ID_KSZ9021RLRN != phydev->phy_id) { > + pr_err("%s unexpected PHY ID %08x\n", __func__, phydev->phy_id); > + return -EINVAL; > + } > + > + pr_info("%s writing extended registers to phyaddr %d\n", > + __func__, phyaddr); > + > + /* add 2 ns of RXC PAD Skew and 2.6 ns of TXC PAD Skew */ > + stmmac_emdio_write(bus, phyaddr, > + MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW, 0xa0d0); > + > + /* set no PAD skew for data */ > + stmmac_emdio_write(bus, phyaddr, > + MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW, 0x0000); > + > + bus->write = &stmmac_mdio_write_null; > + return 0; > +} > + > +static int stmmac_plat_init(struct platform_device *pdev) > +{ > + u32 ctrl, val, shift; > + int phymode; > + > + if (of_machine_is_compatible("altr,socfpga-vt")) > + return 0; > + > + phymode = of_get_phy_mode(pdev->dev.of_node); > + > + switch (phymode) { > + case PHY_INTERFACE_MODE_RGMII: > + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; > + break; > + case PHY_INTERFACE_MODE_MII: > + case PHY_INTERFACE_MODE_GMII: > + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; > + break; > + default: > + pr_err("%s bad phy mode %d", __func__, phymode); > + return -EINVAL; > + } > + > + if (&stmmacenet1_data == pdev->dev.platform_data) > + shift = SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH; > + else if (&stmmacenet0_data == pdev->dev.platform_data) > + shift = 0; > + else { > + pr_err("%s unexpected platform data pointer\n", __func__); > + return -EINVAL; > + } > + > + ctrl = __raw_readl(sys_manager_base_addr + > + SYSMGR_EMACGRP_CTRL_OFFSET); > + > + ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << shift); > + > + ctrl |= (val << shift); > + > + __raw_writel(ctrl, (sys_manager_base_addr + > + SYSMGR_EMACGRP_CTRL_OFFSET)); > + > + return 0; > +} > + > +static void __init socfpga_sysmgr_init(void) > { > struct device_node *np; > > @@ -78,27 +215,58 @@ void __init socfpga_sysmgr_init(void) > rst_manager_base_addr = of_iomap(np, 0); > } > > +static void __init socfpga_map_io(void) > +{ > + socfpga_scu_map_io(); > + iotable_init(&uart_io_desc, 1); > + early_printk("Early printk initialized\n"); > +} > + > +const static struct of_device_id irq_match[] = { > + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, > + {} > +}; > + > static void __init gic_init_irq(void) > { > of_irq_init(irq_match); > socfpga_sysmgr_init(); > + socfpga_init_clocks(); > + twd_local_timer_of_register(); > } > > static void socfpga_cyclone5_restart(char mode, const char *cmd) > { > - /* TODO: */ > + u32 temp; > + > + temp = __raw_readl(rst_manager_base_addr + SOCFPGA_RSTMGR_CTRL); > + > + if (mode == 'h') > + temp |= RSTMGR_CTRL_SWCOLDRSTREQ; > + else > + temp |= RSTMGR_CTRL_SWWARMRSTREQ; > + __raw_writel(temp, rst_manager_base_addr + SOCFPGA_RSTMGR_CTRL); > } > > static void __init socfpga_cyclone5_init(void) > { > - l2x0_of_init(0, ~0UL); > - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); > - socfpga_init_clocks(); > +#ifdef CONFIG_CACHE_L2X0 > + u32 aux_ctrl = 0; > + aux_ctrl |= (1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | > + (1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT); > + l2x0_of_init(aux_ctrl, ~0UL); > +#endif > + of_platform_populate(NULL, of_default_bus_match_table, > + socfpga_auxdata_lookup, NULL); > + > + enable_periphs(); > } > > static const char *altera_dt_match[] = { > "altr,socfpga", > "altr,socfpga-cyclone5", > + "altr,socfpga-vt", > + "altr,socfpga-ice", > NULL > }; > > diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c > index 2c855a6..30c76c4 100644 > --- a/drivers/clk/socfpga/clk.c > +++ b/drivers/clk/socfpga/clk.c > @@ -17,6 +17,11 @@ > #include <linux/clk.h> > #include <linux/clkdev.h> > #include <linux/clk-provider.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > + > +static DEFINE_SPINLOCK(_lock); > > #define SOCFPGA_OSC1_CLK 10000000 > #define SOCFPGA_MPU_CLK 800000000 > @@ -24,28 +29,124 @@ > #define SOCFPGA_MAIN_NAND_SDMMC_CLK 250000000 > #define SOCFPGA_S2F_USR_CLK 125000000 > > +#define SOCFPGA_MAIN_PLL_CLK 1200000000 > +#define SOCFPGA_PER_PLL_CLK 900000000 > +#define SOCFPGA_SDRAM_PLL_CLK 800000000 > + > +#define CLKMGR_PERPLLGRP_EN 0xA0 > + > +#define CLKMGR_QSPI_CLK_EN 11 > +#define CLKMGR_NAND_CLK_EN 10 > +#define CLKMGR_NAND_X_CLK_EN 9 > +#define CLKMGR_SDMMC_CLK_EN 8 > +#define CLKMGR_S2FUSR_CLK_EN 7 > +#define CLKMGR_GPIO_CLK_EN 6 > +#define CLKMGR_CAN1_CLK_EN 5 > +#define CLKMGR_CAN0_CLK_EN 4 > +#define CLKMGR_SPI_M_CLK_EN 3 > +#define CLKMGR_USB_MP_CLK_EN 2 > +#define CLKMGR_EMAC1_CLK_EN 1 > +#define CLKMGR_EMAC0_CLK_EN 0 > + > +void __iomem *clk_mgr_base_addr; > + > void __init socfpga_init_clocks(void) > { > struct clk *clk; > + struct device_node *np; > > - clk = clk_register_fixed_rate(NULL, "osc1_clk", NULL, CLK_IS_ROOT, SOCFPGA_OSC1_CLK); > + np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); > + clk_mgr_base_addr = of_iomap(np, 0); > + > + clk = clk_register_fixed_rate(NULL, "main_pll_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_MAIN_PLL_CLK); > + clk_register_clkdev(clk, "main_pll_clk", NULL); > + > + clk = clk_register_fixed_rate(NULL, "per_pll_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_PER_PLL_CLK); > + clk_register_clkdev(clk, "per_pll_clk", NULL); > + > + clk = clk_register_fixed_rate(NULL, "sdram_pll_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_SDRAM_PLL_CLK); > + clk_register_clkdev(clk, "sdram_pll_clk", NULL); > + > + clk = clk_register_fixed_rate(NULL, "osc1_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_OSC1_CLK); > clk_register_clkdev(clk, "osc1_clk", NULL); > > - clk = clk_register_fixed_rate(NULL, "mpu_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK); > + clk = clk_register_fixed_rate(NULL, "mpu_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_MPU_CLK); > clk_register_clkdev(clk, "mpu_clk", NULL); > > - clk = clk_register_fixed_rate(NULL, "main_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK/2); > + clk = clk_register_fixed_rate(NULL, "main_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_MPU_CLK/2); > clk_register_clkdev(clk, "main_clk", NULL); > > - clk = clk_register_fixed_rate(NULL, "dbg_base_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK/2); > + clk = clk_register_fixed_rate(NULL, "dbg_base_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_MPU_CLK/2); > clk_register_clkdev(clk, "dbg_base_clk", NULL); > > - clk = clk_register_fixed_rate(NULL, "main_qspi_clk", NULL, CLK_IS_ROOT, SOCFPGA_MAIN_QSPI_CLK); > + clk = clk_register_fixed_rate(NULL, "smp_twd", NULL, CLK_IS_ROOT, > + SOCFPGA_MPU_CLK/4); > + clk_register_clkdev(clk, NULL, "smp_twd"); > + > + clk = clk_register_fixed_rate(NULL, "main_qspi_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_MAIN_QSPI_CLK); > clk_register_clkdev(clk, "main_qspi_clk", NULL); > > - clk = clk_register_fixed_rate(NULL, "main_nand_sdmmc_clk", NULL, CLK_IS_ROOT, SOCFPGA_MAIN_NAND_SDMMC_CLK); > + clk = clk_register_fixed_rate(NULL, "main_nand_sdmmc_clk", NULL, > + CLK_IS_ROOT, SOCFPGA_MAIN_NAND_SDMMC_CLK); > clk_register_clkdev(clk, "main_nand_sdmmc_clk", NULL); > > - clk = clk_register_fixed_rate(NULL, "s2f_usr_clk", NULL, CLK_IS_ROOT, SOCFPGA_S2F_USR_CLK); > + clk = clk_register_fixed_rate(NULL, "s2f_usr_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_S2F_USR_CLK); > clk_register_clkdev(clk, "s2f_usr_clk", NULL); > + > + clk = clk_register_fixed_rate(NULL, "i2c0_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_PER_PLL_CLK); > + clk_register_clkdev(clk, NULL, "ffc04000.i2c"); > + > + clk = clk_register_fixed_rate(NULL, "i2c1_clk", NULL, CLK_IS_ROOT, > + SOCFPGA_PER_PLL_CLK); > + clk_register_clkdev(clk, NULL, "ffc05000.i2c"); > + > + clk = clk_register_gate(NULL, "gmac0_clk", "per_pll_clk", 0, > + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, > + CLKMGR_EMAC0_CLK_EN, 0, &_lock); > + clk_register_clkdev(clk, NULL, "ff700000.ethernet"); > + > + clk = clk_register_gate(NULL, "gmac1_clk", "per_pll_clk", 0, > + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, > + CLKMGR_EMAC1_CLK_EN, 0, &_lock); > + clk_register_clkdev(clk, NULL, "ff702000.ethernet"); > + > + clk = clk_register_gate(NULL, "spi0_clk", "per_pll_clk", 0, > + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, > + CLKMGR_SPI_M_CLK_EN, 0, &_lock); > + clk_register_clkdev(clk, NULL, "fff00000.spi"); > + > + clk = clk_register_gate(NULL, "spi1_clk", "per_pll_clk", 0, > + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, > + CLKMGR_SPI_M_CLK_EN, 0, &_lock); > + clk_register_clkdev(clk, NULL, "fff01000.spi"); > + > + clk = clk_register_gate(NULL, "gpio0_clk", "per_pll_clk", 0, > + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, > + CLKMGR_GPIO_CLK_EN, 0, &_lock); > + clk_register_clkdev(clk, NULL, "ff708000.gpio"); > + > + clk = clk_register_gate(NULL, "gpio1_clk", "per_pll_clk", 0, > + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, > + CLKMGR_GPIO_CLK_EN, 0, &_lock); > + clk_register_clkdev(clk, NULL, "ff709000.gpio"); > + > + clk = clk_register_gate(NULL, "gpio2_clk", "per_pll_clk", 0, > + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, > + CLKMGR_GPIO_CLK_EN, 0, &_lock); > + clk_register_clkdev(clk, NULL, "ff70a000.gpio"); > + > + clk = clk_register_gate(NULL, "nand_clk", "main_nand_sdmmc_clk", 0, > + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, > + CLKMGR_NAND_CLK_EN, 0, &_lock); > + clk_register_clkdev(clk, NULL, "ff900000.nand"); > } > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 323c502..c199847 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -38,9 +38,14 @@ > #include "dw_mmc.h" > > /* Common flag combinations */ > -#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | \ > - SDMMC_INT_HTO | SDMMC_INT_SBE | \ > - SDMMC_INT_EBE) > + > +/* According to Synopsys, the data starvation interrupt (HTO) should not treat > + * as error. Software should continue the data transfer. We have verified this > + * in Virtual Target. The same is applied to FIFO under/overrun (FRUN) as well. > + */ > +#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | \ > + SDMMC_INT_HTO | SDMMC_INT_FRUN | SDMMC_INT_SBE | SDMMC_INT_EBE) > + > #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ > SDMMC_INT_RESP_ERR) > #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ > @@ -265,6 +270,9 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) > if (drv_data && drv_data->prepare_command) > drv_data->prepare_command(slot->host, &cmdr); > > + if (slot->host->use_hold_reg) > + cmdr |= SDMMC_CMD_USE_HOLD_REG; > + > return cmdr; > } > > @@ -2047,6 +2055,16 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) > return ERR_PTR(-ENOMEM); > } > > + if (of_property_read_u32(dev->of_node, "bus-hz", &pdata->bus_hz)) { > + dev_err(dev, "couldn't determine bus-hz\n"); > + pdata->bus_hz = 50000000; > + } > + > + if (of_property_read_u32(dev->of_node, "pwr-en", &pdata->pwr_en)) { > + dev_info(dev, "couldn't determine pwr-en, assuming pwr-en = 0\n"); > + pdata->pwr_en = 0; > + } > + > /* find out number of slots supported */ > if (of_property_read_u32(dev->of_node, "num-slots", > &pdata->num_slots)) { > @@ -2183,6 +2201,9 @@ int dw_mci_probe(struct dw_mci *host) > host->data_shift = 2; > } > > + /* Get the USE_HOLD_REG */ > + host->use_hold_reg = mci_readl(host, CMD) & SDMMC_CMD_USE_HOLD_REG; > + > /* Reset all blocks */ > if (!mci_wait_reset(host->dev, host)) > return -ENODEV; > @@ -2194,6 +2215,9 @@ int dw_mci_probe(struct dw_mci *host) > mci_writel(host, RINTSTS, 0xFFFFFFFF); > mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ > > + /* Set PWREN bit */ > + mci_writel(host, PWREN, host->pdata->pwr_en); > + > /* Put in max timeout */ > mci_writel(host, TMOUT, 0xFFFFFFFF); > > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 53b8fd9..6172900 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -111,6 +111,7 @@ > #define SDMMC_INT_ERROR 0xbfc2 > /* Command register defines */ > #define SDMMC_CMD_START BIT(31) > +#define SDMMC_CMD_USE_HOLD_REG BIT(29) > #define SDMMC_CMD_CCS_EXP BIT(23) > #define SDMMC_CMD_CEATA_RD BIT(22) > #define SDMMC_CMD_UPD_CLK BIT(21) > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h > index 7ad56af..03846dc 100644 > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h > @@ -228,6 +228,9 @@ enum rtc_control { > #define GMAC_MMC_CTRL 0x100 > #define GMAC_MMC_RX_INTR 0x104 > #define GMAC_MMC_TX_INTR 0x108 > +#define GMAC_MMC_INTR_MASK_RX 0x10C > +#define GMAC_MMC_INTR_MASK_TX 0x110 > +#define GMAC_MMC_IPC_INTR_MASK_RX 0x200 > #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 > > extern const struct stmmac_dma_ops dwmac1000_dma_ops; > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c > index bfe0226..ade7bfb 100644 > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c > @@ -40,6 +40,11 @@ static void dwmac1000_core_init(void __iomem *ioaddr) > /* Mask GMAC interrupts */ > writel(0x207, ioaddr + GMAC_INT_MASK); > > + /* mask out interrupts because we don't handle them yet */ > + writel(~0UL, ioaddr + GMAC_MMC_INTR_MASK_RX); > + writel(~0UL, ioaddr + GMAC_MMC_INTR_MASK_TX); > + writel(~0UL, ioaddr + GMAC_MMC_IPC_INTR_MASK_RX); > + > #ifdef STMMAC_VLAN_TAG_USED > /* Tag detection without filtering */ > writel(0x0, ioaddr + GMAC_VLAN_TAG); > @@ -198,6 +203,7 @@ static int dwmac1000_irq_status(void __iomem *ioaddr) > { > u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); > int status = 0; > + u32 value; > > /* Not used events (e.g. MMC interrupts) are not handled. */ > if ((intr_status & mmc_tx_irq)) { > @@ -222,6 +228,11 @@ static int dwmac1000_irq_status(void __iomem *ioaddr) > readl(ioaddr + GMAC_PMT); > status |= core_irq_receive_pmt_irq; > } > + if (unlikely(intr_status & rgmii_irq)) { > + CHIP_DBG(KERN_INFO "GMAC: Interrupt Status\n"); > + /* clear this link change interrupt because we are not handling it yet. */ > + value = readl(ioaddr + GMAC_GMII_STATUS); > + } > /* MAC trx/rx EEE LPI entry/exit interrupts */ > if (intr_status & lpiis_irq) { > /* Clean LPI interrupt by reading the Reg 12 */ > diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c > index 2fc8ef9..6996b2e 100644 > --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c > +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c > @@ -145,7 +145,11 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err) > ret = discard_frame; > } else if (status == 0x3) { > CHIP_DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n"); > +#ifdef CONFIG_ARCH_SOCFPGA > + ret = csum_none; > +#else > ret = discard_frame; > +#endif > } > return ret; > } > diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c > index 0b9829f..294060e 100644 > --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c > +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c > @@ -242,6 +242,11 @@ int stmmac_mdio_register(struct net_device *ndev) > return -ENODEV; > } > > + if (priv->plat->mdio_bus_data->phy_reset_mii) { > + priv->plat->mdio_bus_data->phy_reset_mii(new_bus, > + priv->plat->phy_addr); > + } > + > priv->mii = new_bus; > > return 0; > diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c > index b43d68b..e7b455a 100644 > --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c > +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c > @@ -34,15 +34,18 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, > const char **mac) > { > struct device_node *np = pdev->dev.of_node; > + u32 phyaddr; > > if (!np) > return -ENODEV; > > *mac = of_get_mac_address(np); > plat->interface = of_get_phy_mode(np); > - plat->mdio_bus_data = devm_kzalloc(&pdev->dev, > + if (NULL == plat->mdio_bus_data) { > + plat->mdio_bus_data = devm_kzalloc(&pdev->dev, > sizeof(struct stmmac_mdio_bus_data), > GFP_KERNEL); > + } > > /* > * Currently only the properties needed on SPEAr600 > @@ -56,6 +59,17 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, > plat->pmt = 1; > } > > + if (0 == of_property_read_u32(np, "phy-addr", &phyaddr)) { > + if ((-1 == phyaddr) || > + ((phyaddr >= 0) && (phyaddr < PHY_MAX_ADDR))) { > + plat->phy_addr = phyaddr; > + } else { > + pr_err("%s: ERROR: bad phy address: %d\n", > + __func__, phyaddr); > + return -EINVAL; > + } > + } > + > return 0; > } > #else > @@ -94,10 +108,14 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) > return -ENOMEM; > } > > + plat_dat = pdev->dev.platform_data; > + > if (pdev->dev.of_node) { > - plat_dat = devm_kzalloc(&pdev->dev, > + if (NULL == plat_dat) { > + plat_dat = devm_kzalloc(&pdev->dev, > sizeof(struct plat_stmmacenet_data), > GFP_KERNEL); > + } > if (!plat_dat) { > pr_err("%s: ERROR: no memory", __func__); > return -ENOMEM; > @@ -108,8 +126,6 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) > pr_err("%s: main dt probe failed", __func__); > return ret; > } > - } else { > - plat_dat = pdev->dev.platform_data; > } > > /* Custom initialisation (if needed)*/ > diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h > index adfe8c0..f699596 100644 > --- a/include/linux/micrel_phy.h > +++ b/include/linux/micrel_phy.h > @@ -17,6 +17,7 @@ > > #define PHY_ID_KSZ8873MLL 0x000e7237 > #define PHY_ID_KSZ9021 0x00221610 > +#define PHY_ID_KSZ9021RLRN 0x00221611 > #define PHY_ID_KS8737 0x00221720 > #define PHY_ID_KSZ8021 0x00221555 > #define PHY_ID_KSZ8041 0x00221510 > diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h > index 34be4f4..cf22d32 100644 > --- a/include/linux/mmc/dw_mmc.h > +++ b/include/linux/mmc/dw_mmc.h > @@ -187,6 +187,11 @@ struct dw_mci { > struct regulator *vmmc; /* Power regulator */ > unsigned long irq_flags; /* IRQ flags */ > int irq; > + > + /* Set to one for SDR12 and SDR25 */ > + unsigned int use_hold_reg; > + /*Card needs power enable bit */ > + u32 pwr_en; > }; > > /* DMA ops for Internal/External DMAC interface */ > @@ -228,6 +233,8 @@ struct dw_mci_board { > > u32 quirks; /* Workaround / Quirk flags */ > unsigned int bus_hz; /* Clock speed at the cclk_in pad */ > + /*Card needs power enable bit */ > + u32 pwr_en; > > u32 caps; /* Capabilities */ > u32 caps2; /* More capabilities */ > diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h > index c1b3ed3..3666be2 100644 > --- a/include/linux/stmmac.h > +++ b/include/linux/stmmac.h > @@ -27,6 +27,8 @@ > #define __STMMAC_PLATFORM_DATA > > #include <linux/platform_device.h> > +#include <linux/mii.h> > +#include <linux/phy.h> > > #define STMMAC_RX_COE_NONE 0 > #define STMMAC_RX_COE_TYPE1 1 > @@ -77,6 +79,7 @@ > > struct stmmac_mdio_bus_data { > int (*phy_reset)(void *priv); > + int (*phy_reset_mii)(struct mii_bus *bus, int phyaddr); > unsigned int phy_mask; > int *irqs; > int probed_phy_irq; >
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 5ebb44f..d675c986 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -124,6 +124,9 @@ dtb-$(CONFIG_ARCH_SHMOBILE) += emev2-kzm9d.dtb \ r8a7740-armadillo800eva.dtb \ sh73a0-kzm9g.dtb \ sh7372-mackerel.dtb +dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_cyclone5.dtb\ + socfpga_ice.dtb\ + socfpga_vt.dtb dtb-$(CONFIG_ARCH_SPEAR13XX) += spear1310-evb.dtb \ spear1340-evb.dtb dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \ diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 19aec42..c59ca7d 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -23,8 +23,13 @@ aliases { ethernet0 = &gmac0; + ethernet1 = &gmac1; serial0 = &uart0; serial1 = &uart1; + timer0 = &timer0; + timer1 = &timer1; + timer2 = &timer2; + timer3 = &timer3; }; cpus { @@ -61,6 +66,21 @@ interrupt-parent = <&intc>; ranges; + agpio0: gpio@0xc0000000 { + compatible = "altr,pio-1.0"; + /* Register base 0xff200000 is for a light-weight bridge */ + reg = <0xff200000 0x10>; + width = <32>; + /* There are 64 interrupts from the FPGA start at 72, so 45 has to be wrong */ + interrupts = <0 45 4>; + interrupt-controller; + #interrupt-cells = <1>; + gpio-controller; + #gpio-cells = <2>; + level_trigger = <0>; + }; + + amba { compatible = "arm,amba-bus"; #address-cells = <1>; @@ -74,13 +94,62 @@ }; }; - gmac0: stmmac@ff700000 { + clkmgr@ffd04000 { + compatible = "altr,clk-mgr"; + reg = <0xffd04000 0x1000>; + }; + + + gmac0: ethernet@ff700000 { compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; reg = <0xff700000 0x2000>; interrupts = <0 115 4>; interrupt-names = "macirq"; mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ - phy-mode = "gmii"; + }; + + gmac1: ethernet@ff702000 { + compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff702000 0x2000>; + interrupts = <0 120 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + }; + + gpio0: gpio@ff708000 { + compatible = "snps,dw-gpio"; + reg = <0xff708000 0x1000>; + interrupts = <0 164 4>; + width = <29>; + virtual_irq_start = <257>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio1: gpio@ff709000 { + compatible = "snps,dw-gpio"; + reg = <0xff709000 0x1000>; + interrupts = <0 165 4>; + width = <29>; + virtual_irq_start = <286>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio2: gpio@ff70a000 { + compatible = "snps,dw-gpio"; + reg = <0xff70a000 0x1000>; + interrupts = <0 166 4>; + width = <27>; + virtual_irq_start = <315>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; }; L2: l2-cache@fffef000 { @@ -89,6 +158,83 @@ interrupts = <0 38 0x04>; cache-unified; cache-level = <2>; + arm,tag-latency = <1 1 1>; + arm,data-latency = <2 1 1>; + }; + + mmc: dwmmc0@ff704000 { + compatible = "snps,dw-mshc"; + reg = <0xff704000 0x1000>; + interrupts = <0 139 4>; + bus-hz = <12500000>; /*12.5 MHz*/ + #address-cells = <1>; + #size-cells = <0>; + num-slots = <1>; + supports-highspeed; + broken-cd; + fifo-depth = <0x400>; + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + + nand: nand@ff900000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "denali,denali-nand-dt"; + reg = <0xff900000 0x100000>, <0xffb80000 0x10000>; + reg-names = "nand_data", "denali_reg"; + interrupts = <0 144 4>; + dma-mask = <0xffffffff>; + }; + + rstmgr@ffd05000 { + compatible = "altr,rst-mgr"; + reg = <0xffd05000 0x1000>; + }; + + spi0: spi@fff00000 { + compatible = "snps,dw-spi-mmio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfff00000 0x1000>; + interrupts = <0 154 4>; + num-chipselect = <4>; + bus-num = <0>; + tx-dma-channel = <&pdma 16>; + rx-dma-channel = <&pdma 17>; + + spidev@0 { + compatible = "spidev"; + reg = <0>; /* chip select */ + spi-max-frequency = <100000000>; + enable-dma = <1>; + }; + }; + + spi1: spi@fff01000 { + compatible = "snps,dw-spi-mmio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfff01000 0x1000>; + interrupts = <0 156 4>; + num-chipselect = <4>; + bus-num = <1>; + tx-dma-channel = <&pdma 20>; + rx-dma-channel = <&pdma 21>; + + spidev@0 { + compatible = "spidev"; + reg = <0>; + spi-max-frequency = <100000000>; + enable-dma = <1>; + }; + }; + + sysmgr@ffd08000 { + compatible = "altr,sys-mgr"; + reg = <0xffd08000 0x4000>; }; /* Local timer */ @@ -98,60 +244,44 @@ interrupts = <1 13 0xf04>; }; - timer0: timer@ffc08000 { + timer0: timer0@ffc08000 { compatible = "snps,dw-apb-timer-sp"; interrupts = <0 167 4>; - clock-frequency = <200000000>; reg = <0xffc08000 0x1000>; }; - timer1: timer@ffc09000 { + timer1: timer1@ffc09000 { compatible = "snps,dw-apb-timer-sp"; interrupts = <0 168 4>; - clock-frequency = <200000000>; reg = <0xffc09000 0x1000>; }; - timer2: timer@ffd00000 { + timer2: timer2@ffd00000 { compatible = "snps,dw-apb-timer-osc"; interrupts = <0 169 4>; - clock-frequency = <200000000>; reg = <0xffd00000 0x1000>; }; - timer3: timer@ffd01000 { + timer3: timer3@ffd01000 { compatible = "snps,dw-apb-timer-osc"; interrupts = <0 170 4>; - clock-frequency = <200000000>; reg = <0xffd01000 0x1000>; }; - uart0: uart@ffc02000 { + uart0: serial0@ffc02000 { compatible = "snps,dw-apb-uart"; reg = <0xffc02000 0x1000>; - clock-frequency = <7372800>; interrupts = <0 162 4>; reg-shift = <2>; reg-io-width = <4>; }; - uart1: uart@ffc03000 { + uart1: serial1@ffc03000 { compatible = "snps,dw-apb-uart"; reg = <0xffc03000 0x1000>; - clock-frequency = <7372800>; interrupts = <0 163 4>; reg-shift = <2>; reg-io-width = <4>; }; - - rstmgr@ffd05000 { - compatible = "altr,rst-mgr"; - reg = <0xffd05000 0x1000>; - }; - - sysmgr@ffd08000 { - compatible = "altr,sys-mgr"; - reg = <0xffd08000 0x4000>; - }; }; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts index ab7e4a9..d29addc 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5.dts @@ -26,9 +26,169 @@ bootargs = "console=ttyS0,57600"; }; - memory { - name = "memory"; - device_type = "memory"; - reg = <0x0 0x10000000>; /* 256MB */ + aliases { + /* this allow the ethaddr uboot environmnet variable contents + * to be added to the gmac1 device tree blob. + */ + ethernet0 = &gmac1; + }; + + soc { + ethernet@ff700000 { + status = "disabled"; + }; + + ethernet@ff702000 { + phy-mode = "rgmii"; + phy-addr = <0xffffffff>; /* probe for phy addr */ + }; + + qspi: spi@ff705000 { + compatible = "cadence,qspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xff705000 0x1000>, + <0xffa00000 0x1000>; + interrupts = <0 151 4>; + master-ref-clk = <400000000>; + ext-decoder = <0>; /* external decoder */ + num-chipselect = <4>; + fifo-depth = <128>; + bus-num = <2>; + + flash0: n25q128@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q128"; + reg = <0>; /* chip select */ + spi-max-frequency = <100000000>; + page-size = <256>; + block-size = <16>; /* 2^16, 64KB */ + quad = <1>; /* 1-support quad */ + tshsl-ns = <200>; + tsd2d-ns = <255>; + tchsh-ns = <20>; + tslch-ns = <20>; + + partition@0 { + /* 8MB for raw data. */ + label = "Flash 0 Raw Data"; + reg = <0x0 0x800000>; + }; + partition@800000 { + /* 8MB for jffs2 data. */ + label = "Flash 0 jffs2 Filesystem"; + reg = <0x800000 0x800000>; + }; + }; + + flash1: n25q128@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q128"; + reg = <1>; /* chip select */ + spi-max-frequency = <100000000>; + page-size = <256>; + block-size = <16>; /* 2^16, 64KB */ + quad = <1>; + tshsl-ns = <200>; + tsd2d-ns = <255>; + tchsh-ns = <20>; + tslch-ns = <20>; + + partition@0 { + /* 16MB for user data. */ + label = "Flash 1 User Data"; + reg = <0x0 0x1000000>; + }; + }; + }; + + timer0@ffc08000 { + clock-frequency = <100000000>; + }; + + timer1@ffc09000 { + clock-frequency = <100000000>; + }; + + timer2@ffd00000 { + clock-frequency = <25000000>; + }; + + timer3@ffd01000 { + clock-frequency = <25000000>; + }; + + serial0@ffc02000 { + clock-frequency = <100000000>; + }; + + serial1@ffc03000 { + clock-frequency = <100000000>; + }; + + i2c0: i2c@ffc04000 { + speed-mode = <0>; + }; + + leds { + compatible = "gpio-leds"; + fpga0 { + label = "fpga_led0"; + gpios = <&agpio0 0 1>; + }; + + fpga1 { + label = "fpga_led1"; + gpios = <&agpio0 1 1>; + }; + + fpga2 { + label = "fpga_led2"; + gpios = <&agpio0 2 1>; + }; + + fpga3 { + label = "fpga_led3"; + gpios = <&agpio0 3 1>; + }; + + hps0 { + label = "hps_led0"; + gpios = <&gpio1 15 1>; + }; + + hps1 { + label = "hps_led1"; + gpios = <&gpio1 14 1>; + }; + + hps2 { + label = "hps_led2"; + gpios = <&gpio1 13 1>; + }; + + hps3 { + label = "hps_led3"; + gpios = <&gpio1 12 1>; + }; + }; + }; +}; + +&i2c0 { + lcd: lcd@28 { + compatible = "newhaven,nhd-0216k3z-nsw-bbw"; + reg = <0x28>; + height = <2>; + width = <16>; + brightness = <8>; + }; + + eeprom@51 { + compatible = "atmel,24c32"; + reg = <0x51>; + pagesize = <32>; }; }; diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h index 9941caa..e297307 100644 --- a/arch/arm/mach-socfpga/core.h +++ b/arch/arm/mach-socfpga/core.h @@ -24,11 +24,34 @@ extern void secondary_startup(void); extern void __iomem *socfpga_scu_base_addr; extern void socfpga_init_clocks(void); -extern void socfpga_sysmgr_init(void); +//extern void socfpga_sysmgr_init(void); extern struct smp_operations socfpga_smp_ops; extern char secondary_trampoline, secondary_trampoline_end; #define SOCFPGA_SCU_VIRT_BASE 0xfffec000 + +#define SOCFPGA_RSTMGR_CTRL 0x04 +#define SOCFPGA_RSTMGR_MODPERRST 0x14 +#define SOCFPGA_RSTMGR_BRGMODRST 0x1c + +/* System Manager bits */ +#define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ +#define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ +/*MPU Module Reset Register */ + #define RSTMGR_MPUMODRST_CPU0 0x1 /*CPU0 Reset*/ + #define RSTMGR_MPUMODRST_CPU1 0x2 /*CPU1 Reset*/ + #define RSTMGR_MPUMODRST_WDS 0x4 /*Watchdog Reset*/ + #define RSTMGR_MPUMODRST_SCUPER 0x8 /*SCU and periphs reset*/ + #define RSTMGR_MPUMODRST_L2 0x10 /*L2 Cache reset*/ + +#define SYSMGR_EMACGRP_CTRL_OFFSET 0x60 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 + +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 + #endif diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c index 6732924..4d41642 100644 --- a/arch/arm/mach-socfpga/socfpga.c +++ b/arch/arm/mach-socfpga/socfpga.c @@ -17,12 +17,19 @@ #include <linux/dw_apb_timer.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/of_address.h> #include <linux/of_platform.h> +#include <linux/of_net.h> +#include <linux/stmmac.h> +#include <linux/phy.h> +#include <linux/micrel_phy.h> + #include <asm/hardware/cache-l2x0.h> #include <asm/hardware/gic.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/smp_twd.h> #include "core.h" @@ -30,6 +37,29 @@ void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE)); void __iomem *sys_manager_base_addr; void __iomem *rst_manager_base_addr; +static int socfpga_phy_reset_mii(struct mii_bus *bus, int phyaddr); +static int stmmac_plat_init(struct platform_device *pdev); + +static struct stmmac_mdio_bus_data stmmacenet_mdio_bus_data = { + .phy_reset_mii = socfpga_phy_reset_mii, +}; + +static struct plat_stmmacenet_data stmmacenet0_data = { + .mdio_bus_data = &stmmacenet_mdio_bus_data, + .init = &stmmac_plat_init, +}; + +static struct plat_stmmacenet_data stmmacenet1_data = { + .mdio_bus_data = &stmmacenet_mdio_bus_data, + .init = &stmmac_plat_init, +}; + +static const struct of_dev_auxdata socfpga_auxdata_lookup[] __initconst = { + OF_DEV_AUXDATA("snps,dwmac-3.70a", 0xff700000, NULL, &stmmacenet0_data), + OF_DEV_AUXDATA("snps,dwmac-3.70a", 0xff702000, NULL, &stmmacenet1_data), + { /* sentinel */ } +}; + static struct map_desc scu_io_desc __initdata = { .virtual = SOCFPGA_SCU_VIRT_BASE, .pfn = 0, /* run-time */ @@ -55,19 +85,126 @@ static void __init socfpga_scu_map_io(void) iotable_init(&scu_io_desc, 1); } -static void __init socfpga_map_io(void) +static void __init enable_periphs(void) { - socfpga_scu_map_io(); - iotable_init(&uart_io_desc, 1); - early_printk("Early printk initialized\n"); + /* Release all peripherals from reset.*/ + __raw_writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODPERRST); + + /* Release all FPGA bridges from reset.*/ + __raw_writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_BRGMODRST); } -const static struct of_device_id irq_match[] = { - { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, - {} -}; +static int stmmac_mdio_write_null(struct mii_bus *bus, int phyaddr, int phyreg, + u16 phydata) +{ + return 0; +} + +#define MICREL_KSZ9021_EXTREG_CTRL 11 +#define MICREL_KSZ9021_EXTREG_DATA_WRITE 12 +#define MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW 260 +#define MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW 261 -void __init socfpga_sysmgr_init(void) +static int stmmac_emdio_write(struct mii_bus *bus, int phyaddr, int phyreg, + u16 phydata) +{ + int ret = (bus->write)(bus, phyaddr, + MICREL_KSZ9021_EXTREG_CTRL, 0x8000|phyreg); + if (ret) { + pr_warn("stmmac_emdio_write write1 failed %d\n", ret); + return ret; + } + + ret = (bus->write)(bus, phyaddr, + MICREL_KSZ9021_EXTREG_DATA_WRITE, phydata); + if (ret) { + pr_warn("stmmac_emdio_write write2 failed %d\n", ret); + return ret; + } + + return ret; +} + +static int socfpga_phy_reset_mii(struct mii_bus *bus, int phyaddr) +{ + struct phy_device *phydev; + + if (of_machine_is_compatible("altr,socfpga-vt")) + return 0; + + phydev = bus->phy_map[phyaddr]; + + if (NULL == phydev) { + pr_err("%s no phydev found\n", __func__); + return -EINVAL; + } + + if (PHY_ID_KSZ9021RLRN != phydev->phy_id) { + pr_err("%s unexpected PHY ID %08x\n", __func__, phydev->phy_id); + return -EINVAL; + } + + pr_info("%s writing extended registers to phyaddr %d\n", + __func__, phyaddr); + + /* add 2 ns of RXC PAD Skew and 2.6 ns of TXC PAD Skew */ + stmmac_emdio_write(bus, phyaddr, + MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW, 0xa0d0); + + /* set no PAD skew for data */ + stmmac_emdio_write(bus, phyaddr, + MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW, 0x0000); + + bus->write = &stmmac_mdio_write_null; + return 0; +} + +static int stmmac_plat_init(struct platform_device *pdev) +{ + u32 ctrl, val, shift; + int phymode; + + if (of_machine_is_compatible("altr,socfpga-vt")) + return 0; + + phymode = of_get_phy_mode(pdev->dev.of_node); + + switch (phymode) { + case PHY_INTERFACE_MODE_RGMII: + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; + break; + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; + break; + default: + pr_err("%s bad phy mode %d", __func__, phymode); + return -EINVAL; + } + + if (&stmmacenet1_data == pdev->dev.platform_data) + shift = SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH; + else if (&stmmacenet0_data == pdev->dev.platform_data) + shift = 0; + else { + pr_err("%s unexpected platform data pointer\n", __func__); + return -EINVAL; + } + + ctrl = __raw_readl(sys_manager_base_addr + + SYSMGR_EMACGRP_CTRL_OFFSET); + + ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << shift); + + ctrl |= (val << shift); + + __raw_writel(ctrl, (sys_manager_base_addr + + SYSMGR_EMACGRP_CTRL_OFFSET)); + + return 0; +} + +static void __init socfpga_sysmgr_init(void) { struct device_node *np; @@ -78,27 +215,58 @@ void __init socfpga_sysmgr_init(void) rst_manager_base_addr = of_iomap(np, 0); } +static void __init socfpga_map_io(void) +{ + socfpga_scu_map_io(); + iotable_init(&uart_io_desc, 1); + early_printk("Early printk initialized\n"); +} + +const static struct of_device_id irq_match[] = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + {} +}; + static void __init gic_init_irq(void) { of_irq_init(irq_match); socfpga_sysmgr_init(); + socfpga_init_clocks(); + twd_local_timer_of_register(); } static void socfpga_cyclone5_restart(char mode, const char *cmd) { - /* TODO: */ + u32 temp; + + temp = __raw_readl(rst_manager_base_addr + SOCFPGA_RSTMGR_CTRL); + + if (mode == 'h') + temp |= RSTMGR_CTRL_SWCOLDRSTREQ; + else + temp |= RSTMGR_CTRL_SWWARMRSTREQ; + __raw_writel(temp, rst_manager_base_addr + SOCFPGA_RSTMGR_CTRL); } static void __init socfpga_cyclone5_init(void) { - l2x0_of_init(0, ~0UL); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - socfpga_init_clocks(); +#ifdef CONFIG_CACHE_L2X0 + u32 aux_ctrl = 0; + aux_ctrl |= (1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | + (1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT); + l2x0_of_init(aux_ctrl, ~0UL); +#endif + of_platform_populate(NULL, of_default_bus_match_table, + socfpga_auxdata_lookup, NULL); + + enable_periphs(); } static const char *altera_dt_match[] = { "altr,socfpga", "altr,socfpga-cyclone5", + "altr,socfpga-vt", + "altr,socfpga-ice", NULL }; diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c index 2c855a6..30c76c4 100644 --- a/drivers/clk/socfpga/clk.c +++ b/drivers/clk/socfpga/clk.c @@ -17,6 +17,11 @@ #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> + +static DEFINE_SPINLOCK(_lock); #define SOCFPGA_OSC1_CLK 10000000 #define SOCFPGA_MPU_CLK 800000000 @@ -24,28 +29,124 @@ #define SOCFPGA_MAIN_NAND_SDMMC_CLK 250000000 #define SOCFPGA_S2F_USR_CLK 125000000 +#define SOCFPGA_MAIN_PLL_CLK 1200000000 +#define SOCFPGA_PER_PLL_CLK 900000000 +#define SOCFPGA_SDRAM_PLL_CLK 800000000 + +#define CLKMGR_PERPLLGRP_EN 0xA0 + +#define CLKMGR_QSPI_CLK_EN 11 +#define CLKMGR_NAND_CLK_EN 10 +#define CLKMGR_NAND_X_CLK_EN 9 +#define CLKMGR_SDMMC_CLK_EN 8 +#define CLKMGR_S2FUSR_CLK_EN 7 +#define CLKMGR_GPIO_CLK_EN 6 +#define CLKMGR_CAN1_CLK_EN 5 +#define CLKMGR_CAN0_CLK_EN 4 +#define CLKMGR_SPI_M_CLK_EN 3 +#define CLKMGR_USB_MP_CLK_EN 2 +#define CLKMGR_EMAC1_CLK_EN 1 +#define CLKMGR_EMAC0_CLK_EN 0 + +void __iomem *clk_mgr_base_addr; + void __init socfpga_init_clocks(void) { struct clk *clk; + struct device_node *np; - clk = clk_register_fixed_rate(NULL, "osc1_clk", NULL, CLK_IS_ROOT, SOCFPGA_OSC1_CLK); + np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); + clk_mgr_base_addr = of_iomap(np, 0); + + clk = clk_register_fixed_rate(NULL, "main_pll_clk", NULL, CLK_IS_ROOT, + SOCFPGA_MAIN_PLL_CLK); + clk_register_clkdev(clk, "main_pll_clk", NULL); + + clk = clk_register_fixed_rate(NULL, "per_pll_clk", NULL, CLK_IS_ROOT, + SOCFPGA_PER_PLL_CLK); + clk_register_clkdev(clk, "per_pll_clk", NULL); + + clk = clk_register_fixed_rate(NULL, "sdram_pll_clk", NULL, CLK_IS_ROOT, + SOCFPGA_SDRAM_PLL_CLK); + clk_register_clkdev(clk, "sdram_pll_clk", NULL); + + clk = clk_register_fixed_rate(NULL, "osc1_clk", NULL, CLK_IS_ROOT, + SOCFPGA_OSC1_CLK); clk_register_clkdev(clk, "osc1_clk", NULL); - clk = clk_register_fixed_rate(NULL, "mpu_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK); + clk = clk_register_fixed_rate(NULL, "mpu_clk", NULL, CLK_IS_ROOT, + SOCFPGA_MPU_CLK); clk_register_clkdev(clk, "mpu_clk", NULL); - clk = clk_register_fixed_rate(NULL, "main_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK/2); + clk = clk_register_fixed_rate(NULL, "main_clk", NULL, CLK_IS_ROOT, + SOCFPGA_MPU_CLK/2); clk_register_clkdev(clk, "main_clk", NULL); - clk = clk_register_fixed_rate(NULL, "dbg_base_clk", NULL, CLK_IS_ROOT, SOCFPGA_MPU_CLK/2); + clk = clk_register_fixed_rate(NULL, "dbg_base_clk", NULL, CLK_IS_ROOT, + SOCFPGA_MPU_CLK/2); clk_register_clkdev(clk, "dbg_base_clk", NULL); - clk = clk_register_fixed_rate(NULL, "main_qspi_clk", NULL, CLK_IS_ROOT, SOCFPGA_MAIN_QSPI_CLK); + clk = clk_register_fixed_rate(NULL, "smp_twd", NULL, CLK_IS_ROOT, + SOCFPGA_MPU_CLK/4); + clk_register_clkdev(clk, NULL, "smp_twd"); + + clk = clk_register_fixed_rate(NULL, "main_qspi_clk", NULL, CLK_IS_ROOT, + SOCFPGA_MAIN_QSPI_CLK); clk_register_clkdev(clk, "main_qspi_clk", NULL); - clk = clk_register_fixed_rate(NULL, "main_nand_sdmmc_clk", NULL, CLK_IS_ROOT, SOCFPGA_MAIN_NAND_SDMMC_CLK); + clk = clk_register_fixed_rate(NULL, "main_nand_sdmmc_clk", NULL, + CLK_IS_ROOT, SOCFPGA_MAIN_NAND_SDMMC_CLK); clk_register_clkdev(clk, "main_nand_sdmmc_clk", NULL); - clk = clk_register_fixed_rate(NULL, "s2f_usr_clk", NULL, CLK_IS_ROOT, SOCFPGA_S2F_USR_CLK); + clk = clk_register_fixed_rate(NULL, "s2f_usr_clk", NULL, CLK_IS_ROOT, + SOCFPGA_S2F_USR_CLK); clk_register_clkdev(clk, "s2f_usr_clk", NULL); + + clk = clk_register_fixed_rate(NULL, "i2c0_clk", NULL, CLK_IS_ROOT, + SOCFPGA_PER_PLL_CLK); + clk_register_clkdev(clk, NULL, "ffc04000.i2c"); + + clk = clk_register_fixed_rate(NULL, "i2c1_clk", NULL, CLK_IS_ROOT, + SOCFPGA_PER_PLL_CLK); + clk_register_clkdev(clk, NULL, "ffc05000.i2c"); + + clk = clk_register_gate(NULL, "gmac0_clk", "per_pll_clk", 0, + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, + CLKMGR_EMAC0_CLK_EN, 0, &_lock); + clk_register_clkdev(clk, NULL, "ff700000.ethernet"); + + clk = clk_register_gate(NULL, "gmac1_clk", "per_pll_clk", 0, + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, + CLKMGR_EMAC1_CLK_EN, 0, &_lock); + clk_register_clkdev(clk, NULL, "ff702000.ethernet"); + + clk = clk_register_gate(NULL, "spi0_clk", "per_pll_clk", 0, + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, + CLKMGR_SPI_M_CLK_EN, 0, &_lock); + clk_register_clkdev(clk, NULL, "fff00000.spi"); + + clk = clk_register_gate(NULL, "spi1_clk", "per_pll_clk", 0, + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, + CLKMGR_SPI_M_CLK_EN, 0, &_lock); + clk_register_clkdev(clk, NULL, "fff01000.spi"); + + clk = clk_register_gate(NULL, "gpio0_clk", "per_pll_clk", 0, + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, + CLKMGR_GPIO_CLK_EN, 0, &_lock); + clk_register_clkdev(clk, NULL, "ff708000.gpio"); + + clk = clk_register_gate(NULL, "gpio1_clk", "per_pll_clk", 0, + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, + CLKMGR_GPIO_CLK_EN, 0, &_lock); + clk_register_clkdev(clk, NULL, "ff709000.gpio"); + + clk = clk_register_gate(NULL, "gpio2_clk", "per_pll_clk", 0, + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, + CLKMGR_GPIO_CLK_EN, 0, &_lock); + clk_register_clkdev(clk, NULL, "ff70a000.gpio"); + + clk = clk_register_gate(NULL, "nand_clk", "main_nand_sdmmc_clk", 0, + clk_mgr_base_addr + CLKMGR_PERPLLGRP_EN, + CLKMGR_NAND_CLK_EN, 0, &_lock); + clk_register_clkdev(clk, NULL, "ff900000.nand"); } diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 323c502..c199847 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -38,9 +38,14 @@ #include "dw_mmc.h" /* Common flag combinations */ -#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | \ - SDMMC_INT_HTO | SDMMC_INT_SBE | \ - SDMMC_INT_EBE) + +/* According to Synopsys, the data starvation interrupt (HTO) should not treat + * as error. Software should continue the data transfer. We have verified this + * in Virtual Target. The same is applied to FIFO under/overrun (FRUN) as well. + */ +#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | \ + SDMMC_INT_HTO | SDMMC_INT_FRUN | SDMMC_INT_SBE | SDMMC_INT_EBE) + #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ SDMMC_INT_RESP_ERR) #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ @@ -265,6 +270,9 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) if (drv_data && drv_data->prepare_command) drv_data->prepare_command(slot->host, &cmdr); + if (slot->host->use_hold_reg) + cmdr |= SDMMC_CMD_USE_HOLD_REG; + return cmdr; } @@ -2047,6 +2055,16 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) return ERR_PTR(-ENOMEM); } + if (of_property_read_u32(dev->of_node, "bus-hz", &pdata->bus_hz)) { + dev_err(dev, "couldn't determine bus-hz\n"); + pdata->bus_hz = 50000000; + } + + if (of_property_read_u32(dev->of_node, "pwr-en", &pdata->pwr_en)) { + dev_info(dev, "couldn't determine pwr-en, assuming pwr-en = 0\n"); + pdata->pwr_en = 0; + } + /* find out number of slots supported */ if (of_property_read_u32(dev->of_node, "num-slots", &pdata->num_slots)) { @@ -2183,6 +2201,9 @@ int dw_mci_probe(struct dw_mci *host) host->data_shift = 2; } + /* Get the USE_HOLD_REG */ + host->use_hold_reg = mci_readl(host, CMD) & SDMMC_CMD_USE_HOLD_REG; + /* Reset all blocks */ if (!mci_wait_reset(host->dev, host)) return -ENODEV; @@ -2194,6 +2215,9 @@ int dw_mci_probe(struct dw_mci *host) mci_writel(host, RINTSTS, 0xFFFFFFFF); mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ + /* Set PWREN bit */ + mci_writel(host, PWREN, host->pdata->pwr_en); + /* Put in max timeout */ mci_writel(host, TMOUT, 0xFFFFFFFF); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 53b8fd9..6172900 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -111,6 +111,7 @@ #define SDMMC_INT_ERROR 0xbfc2 /* Command register defines */ #define SDMMC_CMD_START BIT(31) +#define SDMMC_CMD_USE_HOLD_REG BIT(29) #define SDMMC_CMD_CCS_EXP BIT(23) #define SDMMC_CMD_CEATA_RD BIT(22) #define SDMMC_CMD_UPD_CLK BIT(21) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index 7ad56af..03846dc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -228,6 +228,9 @@ enum rtc_control { #define GMAC_MMC_CTRL 0x100 #define GMAC_MMC_RX_INTR 0x104 #define GMAC_MMC_TX_INTR 0x108 +#define GMAC_MMC_INTR_MASK_RX 0x10C +#define GMAC_MMC_INTR_MASK_TX 0x110 +#define GMAC_MMC_IPC_INTR_MASK_RX 0x200 #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 extern const struct stmmac_dma_ops dwmac1000_dma_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index bfe0226..ade7bfb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -40,6 +40,11 @@ static void dwmac1000_core_init(void __iomem *ioaddr) /* Mask GMAC interrupts */ writel(0x207, ioaddr + GMAC_INT_MASK); + /* mask out interrupts because we don't handle them yet */ + writel(~0UL, ioaddr + GMAC_MMC_INTR_MASK_RX); + writel(~0UL, ioaddr + GMAC_MMC_INTR_MASK_TX); + writel(~0UL, ioaddr + GMAC_MMC_IPC_INTR_MASK_RX); + #ifdef STMMAC_VLAN_TAG_USED /* Tag detection without filtering */ writel(0x0, ioaddr + GMAC_VLAN_TAG); @@ -198,6 +203,7 @@ static int dwmac1000_irq_status(void __iomem *ioaddr) { u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); int status = 0; + u32 value; /* Not used events (e.g. MMC interrupts) are not handled. */ if ((intr_status & mmc_tx_irq)) { @@ -222,6 +228,11 @@ static int dwmac1000_irq_status(void __iomem *ioaddr) readl(ioaddr + GMAC_PMT); status |= core_irq_receive_pmt_irq; } + if (unlikely(intr_status & rgmii_irq)) { + CHIP_DBG(KERN_INFO "GMAC: Interrupt Status\n"); + /* clear this link change interrupt because we are not handling it yet. */ + value = readl(ioaddr + GMAC_GMII_STATUS); + } /* MAC trx/rx EEE LPI entry/exit interrupts */ if (intr_status & lpiis_irq) { /* Clean LPI interrupt by reading the Reg 12 */ diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c index 2fc8ef9..6996b2e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c @@ -145,7 +145,11 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err) ret = discard_frame; } else if (status == 0x3) { CHIP_DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n"); +#ifdef CONFIG_ARCH_SOCFPGA + ret = csum_none; +#else ret = discard_frame; +#endif } return ret; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 0b9829f..294060e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -242,6 +242,11 @@ int stmmac_mdio_register(struct net_device *ndev) return -ENODEV; } + if (priv->plat->mdio_bus_data->phy_reset_mii) { + priv->plat->mdio_bus_data->phy_reset_mii(new_bus, + priv->plat->phy_addr); + } + priv->mii = new_bus; return 0; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index b43d68b..e7b455a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -34,15 +34,18 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { struct device_node *np = pdev->dev.of_node; + u32 phyaddr; if (!np) return -ENODEV; *mac = of_get_mac_address(np); plat->interface = of_get_phy_mode(np); - plat->mdio_bus_data = devm_kzalloc(&pdev->dev, + if (NULL == plat->mdio_bus_data) { + plat->mdio_bus_data = devm_kzalloc(&pdev->dev, sizeof(struct stmmac_mdio_bus_data), GFP_KERNEL); + } /* * Currently only the properties needed on SPEAr600 @@ -56,6 +59,17 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, plat->pmt = 1; } + if (0 == of_property_read_u32(np, "phy-addr", &phyaddr)) { + if ((-1 == phyaddr) || + ((phyaddr >= 0) && (phyaddr < PHY_MAX_ADDR))) { + plat->phy_addr = phyaddr; + } else { + pr_err("%s: ERROR: bad phy address: %d\n", + __func__, phyaddr); + return -EINVAL; + } + } + return 0; } #else @@ -94,10 +108,14 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) return -ENOMEM; } + plat_dat = pdev->dev.platform_data; + if (pdev->dev.of_node) { - plat_dat = devm_kzalloc(&pdev->dev, + if (NULL == plat_dat) { + plat_dat = devm_kzalloc(&pdev->dev, sizeof(struct plat_stmmacenet_data), GFP_KERNEL); + } if (!plat_dat) { pr_err("%s: ERROR: no memory", __func__); return -ENOMEM; @@ -108,8 +126,6 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) pr_err("%s: main dt probe failed", __func__); return ret; } - } else { - plat_dat = pdev->dev.platform_data; } /* Custom initialisation (if needed)*/ diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h index adfe8c0..f699596 100644 --- a/include/linux/micrel_phy.h +++ b/include/linux/micrel_phy.h @@ -17,6 +17,7 @@ #define PHY_ID_KSZ8873MLL 0x000e7237 #define PHY_ID_KSZ9021 0x00221610 +#define PHY_ID_KSZ9021RLRN 0x00221611 #define PHY_ID_KS8737 0x00221720 #define PHY_ID_KSZ8021 0x00221555 #define PHY_ID_KSZ8041 0x00221510 diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 34be4f4..cf22d32 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -187,6 +187,11 @@ struct dw_mci { struct regulator *vmmc; /* Power regulator */ unsigned long irq_flags; /* IRQ flags */ int irq; + + /* Set to one for SDR12 and SDR25 */ + unsigned int use_hold_reg; + /*Card needs power enable bit */ + u32 pwr_en; }; /* DMA ops for Internal/External DMAC interface */ @@ -228,6 +233,8 @@ struct dw_mci_board { u32 quirks; /* Workaround / Quirk flags */ unsigned int bus_hz; /* Clock speed at the cclk_in pad */ + /*Card needs power enable bit */ + u32 pwr_en; u32 caps; /* Capabilities */ u32 caps2; /* More capabilities */ diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index c1b3ed3..3666be2 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -27,6 +27,8 @@ #define __STMMAC_PLATFORM_DATA #include <linux/platform_device.h> +#include <linux/mii.h> +#include <linux/phy.h> #define STMMAC_RX_COE_NONE 0 #define STMMAC_RX_COE_TYPE1 1 @@ -77,6 +79,7 @@ struct stmmac_mdio_bus_data { int (*phy_reset)(void *priv); + int (*phy_reset_mii)(struct mii_bus *bus, int phyaddr); unsigned int phy_mask; int *irqs; int probed_phy_irq;
Hi! Below are changes that get MMC/ethernet working for me. Probably not everything is strictly neccessary, I'll try to prune them some more. Strange thing is that enh_desc.c (disabling checksumming AFAICT) seems to be neccessary for NFS to work. In the meantime... does it make sense to split simple changes and submit them upstream? arch/arm/boot/dts/Makefile -- dtb files should be build, this can be probably considered bugfix. socfpga.c: socfpga_cyclone5_restart() -- this is self-contained reset function marked with "TODO". (patches are originally from Altera). Signed-off-by: Pavel Machek <pavel@denx.de> (but not for merge for now). Thanks, Pavel