From 3e25f4f243db6495cf57c1fcb3a4c0311a92b203 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sat, 21 Jan 2012 18:13:13 +0100 Subject: MIPS: Alchemy: use 64MB RAM as minimum for devboards YAMON on all devboards provides the "memsize" envvar; in the unlikely case that it can't be parsed just assume 64MB, which all boards have at least. Signed-off-by: Manuel Lauss Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3286/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c index 93a2210..57320f2 100644 --- a/arch/mips/alchemy/devboards/prom.c +++ b/arch/mips/alchemy/devboards/prom.c @@ -33,15 +33,6 @@ #include #include -#if defined(CONFIG_MIPS_DB1000) || \ - defined(CONFIG_MIPS_PB1100) || \ - defined(CONFIG_MIPS_PB1500) -#define ALCHEMY_BOARD_DEFAULT_MEMSIZE 0x04000000 - -#else /* Au1550/Au1200-based develboards */ -#define ALCHEMY_BOARD_DEFAULT_MEMSIZE 0x08000000 -#endif - void __init prom_init(void) { unsigned char *memsize_str; @@ -54,7 +45,7 @@ void __init prom_init(void) prom_init_cmdline(); memsize_str = prom_getenv("memsize"); if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize)) - memsize = ALCHEMY_BOARD_DEFAULT_MEMSIZE; + memsize = 64 << 20; /* all devboards have at least 64MB RAM */ add_memory_region(0, memsize, BOOT_MEM_RAM); } -- cgit v0.10.2 From 278bf05cf68a6e5e965c85217ddc1318d18fcbf7 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sat, 21 Jan 2012 18:13:14 +0100 Subject: MIPS: Alchemy: devboards: kill prom.c move contents to already existing platform.c file. Signed-off-by: Manuel Lauss Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3287/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile index 3c37fb3..c9e747d 100644 --- a/arch/mips/alchemy/devboards/Makefile +++ b/arch/mips/alchemy/devboards/Makefile @@ -2,7 +2,7 @@ # Alchemy Develboards # -obj-y += prom.o bcsr.o platform.o +obj-y += bcsr.o platform.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_MIPS_PB1100) += pb1100.o obj-$(CONFIG_MIPS_PB1500) += pb1500.o diff --git a/arch/mips/alchemy/devboards/platform.c b/arch/mips/alchemy/devboards/platform.c index 621f70a..f39042e 100644 --- a/arch/mips/alchemy/devboards/platform.c +++ b/arch/mips/alchemy/devboards/platform.c @@ -10,9 +10,39 @@ #include #include +#include #include +#include #include +#include + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = (int)fw_arg0; + prom_argv = (char **)fw_arg1; + prom_envp = (char **)fw_arg2; + + prom_init_cmdline(); + memsize_str = prom_getenv("memsize"); + if (!memsize_str || kstrtoul(memsize_str, 0, &memsize)) + memsize = 64 << 20; /* all devboards have at least 64MB RAM */ + + add_memory_region(0, memsize, BOOT_MEM_RAM); +} + +void prom_putchar(unsigned char c) +{ +#ifdef CONFIG_MIPS_DB1300 + alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c); +#else + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); +#endif +} + static struct platform_device db1x00_rtc_dev = { .name = "rtc-au1xxx", diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c deleted file mode 100644 index 57320f2..0000000 --- a/arch/mips/alchemy/devboards/prom.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Common code used by all Alchemy develboards. - * - * Extracted from files which had this to say: - * - * Copyright 2000, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -void __init prom_init(void) -{ - unsigned char *memsize_str; - unsigned long memsize; - - prom_argc = (int)fw_arg0; - prom_argv = (char **)fw_arg1; - prom_envp = (char **)fw_arg2; - - prom_init_cmdline(); - memsize_str = prom_getenv("memsize"); - if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize)) - memsize = 64 << 20; /* all devboards have at least 64MB RAM */ - - add_memory_region(0, memsize, BOOT_MEM_RAM); -} - -void prom_putchar(unsigned char c) -{ -#ifdef CONFIG_MIPS_DB1300 - alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c); -#else - alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); -#endif -} -- cgit v0.10.2 From 6c2be5cf1d4e70e98d995f9c403b5fbe7b5f2a80 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sat, 21 Jan 2012 18:13:15 +0100 Subject: MIPS: Alchemy: handle db1200 cpld ints as they come in Remove the loop in the cascade handler and instead unconditionally handle just the first set interrupt coming from the CPLD. This gets rid of a lot of spurious interrupts being triggered for the SMSC91111 ethernet chip especially under high(er) IDE load: "eth0: spurious interrupt (mask = 0xb3)" Verified on DB1200 and DB1300. Signed-off-by: Manuel Lauss Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3288/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c index 1e83ce2..f2039ef 100644 --- a/arch/mips/alchemy/devboards/bcsr.c +++ b/arch/mips/alchemy/devboards/bcsr.c @@ -90,10 +90,7 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT); disable_irq_nosync(irq); - - for ( ; bisr; bisr &= bisr - 1) - generic_handle_irq(bcsr_csc_base + __ffs(bisr)); - + generic_handle_irq(bcsr_csc_base + __ffs(bisr)); enable_irq(irq); } -- cgit v0.10.2 From d9831a41e3409ae60e0cac353272d8ae4996b442 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:57:09 +0200 Subject: MIPS: BCM63XX: Be consistent in clock bits enable naming Remove the _CLK suffix from the BCM6368 clock bits definitions to be consistent with what is already present. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3312/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c index 9d57c71..8d2ea22 100644 --- a/arch/mips/bcm63xx/clk.c +++ b/arch/mips/bcm63xx/clk.c @@ -120,7 +120,7 @@ static void enetsw_set(struct clk *clk, int enable) { if (!BCMCPU_IS_6368()) return; - bcm_hwclock_set(CKCTL_6368_ROBOSW_CLK_EN | + bcm_hwclock_set(CKCTL_6368_ROBOSW_EN | CKCTL_6368_SWPKT_USB_EN | CKCTL_6368_SWPKT_SAR_EN, enable); if (enable) { @@ -163,7 +163,7 @@ static void usbh_set(struct clk *clk, int enable) if (BCMCPU_IS_6348()) bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); else if (BCMCPU_IS_6368()) - bcm_hwclock_set(CKCTL_6368_USBH_CLK_EN, enable); + bcm_hwclock_set(CKCTL_6368_USBH_EN, enable); } static struct clk clk_usbh = { @@ -199,7 +199,7 @@ static void xtm_set(struct clk *clk, int enable) if (!BCMCPU_IS_6368()) return; - bcm_hwclock_set(CKCTL_6368_SAR_CLK_EN | + bcm_hwclock_set(CKCTL_6368_SAR_EN | CKCTL_6368_SWPKT_SAR_EN, enable); if (enable) { diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index fdcd78c..e372132 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -90,29 +90,29 @@ #define CKCTL_6368_PHYMIPS_EN (1 << 6) #define CKCTL_6368_SWPKT_USB_EN (1 << 7) #define CKCTL_6368_SWPKT_SAR_EN (1 << 8) -#define CKCTL_6368_SPI_CLK_EN (1 << 9) -#define CKCTL_6368_USBD_CLK_EN (1 << 10) -#define CKCTL_6368_SAR_CLK_EN (1 << 11) -#define CKCTL_6368_ROBOSW_CLK_EN (1 << 12) -#define CKCTL_6368_UTOPIA_CLK_EN (1 << 13) -#define CKCTL_6368_PCM_CLK_EN (1 << 14) -#define CKCTL_6368_USBH_CLK_EN (1 << 15) +#define CKCTL_6368_SPI_EN (1 << 9) +#define CKCTL_6368_USBD_EN (1 << 10) +#define CKCTL_6368_SAR_EN (1 << 11) +#define CKCTL_6368_ROBOSW_EN (1 << 12) +#define CKCTL_6368_UTOPIA_EN (1 << 13) +#define CKCTL_6368_PCM_EN (1 << 14) +#define CKCTL_6368_USBH_EN (1 << 15) #define CKCTL_6368_DISABLE_GLESS_EN (1 << 16) -#define CKCTL_6368_NAND_CLK_EN (1 << 17) -#define CKCTL_6368_IPSEC_CLK_EN (1 << 18) +#define CKCTL_6368_NAND_EN (1 << 17) +#define CKCTL_6368_IPSEC_EN (1 << 18) #define CKCTL_6368_ALL_SAFE_EN (CKCTL_6368_SWPKT_USB_EN | \ CKCTL_6368_SWPKT_SAR_EN | \ - CKCTL_6368_SPI_CLK_EN | \ - CKCTL_6368_USBD_CLK_EN | \ - CKCTL_6368_SAR_CLK_EN | \ - CKCTL_6368_ROBOSW_CLK_EN | \ - CKCTL_6368_UTOPIA_CLK_EN | \ - CKCTL_6368_PCM_CLK_EN | \ - CKCTL_6368_USBH_CLK_EN | \ + CKCTL_6368_SPI_EN | \ + CKCTL_6368_USBD_EN | \ + CKCTL_6368_SAR_EN | \ + CKCTL_6368_ROBOSW_EN | \ + CKCTL_6368_UTOPIA_EN | \ + CKCTL_6368_PCM_EN | \ + CKCTL_6368_USBH_EN | \ CKCTL_6368_DISABLE_GLESS_EN | \ - CKCTL_6368_NAND_CLK_EN | \ - CKCTL_6368_IPSEC_CLK_EN) + CKCTL_6368_NAND_EN | \ + CKCTL_6368_IPSEC_EN) /* System PLL Control register */ #define PERF_SYS_PLL_CTL_REG 0x8 -- cgit v0.10.2 From 0aeee715b0c30a19a81d06b5e8c7e18a41a4d17d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:58:27 +0200 Subject: MIPS: BCM63xx: Add IRQ_SPI and CPU specific SPI IRQ values Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: grant.likely@secretlab.ca Cc: spi-devel-general@lists.sourceforge.net Patchwork: https://patchwork.linux-mips.org/patch/3320/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index 5b8d15b..9975727 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -478,6 +478,7 @@ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set) */ enum bcm63xx_irq { IRQ_TIMER = 0, + IRQ_SPI, IRQ_UART0, IRQ_UART1, IRQ_DSL, @@ -509,6 +510,7 @@ enum bcm63xx_irq { * 6338 irqs */ #define BCM_6338_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) +#define BCM_6338_SPI_IRQ (IRQ_INTERNAL_BASE + 1) #define BCM_6338_UART0_IRQ (IRQ_INTERNAL_BASE + 2) #define BCM_6338_UART1_IRQ 0 #define BCM_6338_DSL_IRQ (IRQ_INTERNAL_BASE + 5) @@ -539,6 +541,7 @@ enum bcm63xx_irq { * 6345 irqs */ #define BCM_6345_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) +#define BCM_6345_SPI_IRQ 0 #define BCM_6345_UART0_IRQ (IRQ_INTERNAL_BASE + 2) #define BCM_6345_UART1_IRQ 0 #define BCM_6345_DSL_IRQ (IRQ_INTERNAL_BASE + 3) @@ -569,6 +572,7 @@ enum bcm63xx_irq { * 6348 irqs */ #define BCM_6348_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) +#define BCM_6348_SPI_IRQ (IRQ_INTERNAL_BASE + 1) #define BCM_6348_UART0_IRQ (IRQ_INTERNAL_BASE + 2) #define BCM_6348_UART1_IRQ 0 #define BCM_6348_DSL_IRQ (IRQ_INTERNAL_BASE + 4) @@ -599,6 +603,7 @@ enum bcm63xx_irq { * 6358 irqs */ #define BCM_6358_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) +#define BCM_6358_SPI_IRQ (IRQ_INTERNAL_BASE + 1) #define BCM_6358_UART0_IRQ (IRQ_INTERNAL_BASE + 2) #define BCM_6358_UART1_IRQ (IRQ_INTERNAL_BASE + 3) #define BCM_6358_DSL_IRQ (IRQ_INTERNAL_BASE + 29) @@ -638,6 +643,7 @@ enum bcm63xx_irq { #define BCM_6368_HIGH_IRQ_BASE (IRQ_INTERNAL_BASE + 32) #define BCM_6368_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) +#define BCM_6368_SPI_IRQ (IRQ_INTERNAL_BASE + 1) #define BCM_6368_UART0_IRQ (IRQ_INTERNAL_BASE + 2) #define BCM_6368_UART1_IRQ (IRQ_INTERNAL_BASE + 3) #define BCM_6368_DSL_IRQ (IRQ_INTERNAL_BASE + 4) @@ -677,6 +683,7 @@ extern const int *bcm63xx_irqs; #define __GEN_CPU_IRQ_TABLE(__cpu) \ [IRQ_TIMER] = BCM_## __cpu ##_TIMER_IRQ, \ + [IRQ_SPI] = BCM_## __cpu ##_SPI_IRQ, \ [IRQ_UART0] = BCM_## __cpu ##_UART0_IRQ, \ [IRQ_UART1] = BCM_## __cpu ##_UART1_IRQ, \ [IRQ_DSL] = BCM_## __cpu ##_DSL_IRQ, \ -- cgit v0.10.2 From 9e368e49dadc90e9105d43d8875aaf1bfd268196 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:58:29 +0200 Subject: MIPS: BCM63xx: Define BCM6358 SPI base address Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: grant.likely@secretlab.ca Cc: spi-devel-general@lists.sourceforge.net Patchwork: https://patchwork.linux-mips.org/patch/3315/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index 9975727..016dc9e 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -289,7 +289,7 @@ enum bcm63xx_regs_set { #define BCM_6358_UART0_BASE (0xfffe0100) #define BCM_6358_UART1_BASE (0xfffe0120) #define BCM_6358_GPIO_BASE (0xfffe0080) -#define BCM_6358_SPI_BASE (0xdeadbeef) +#define BCM_6358_SPI_BASE (0xfffe0800) #define BCM_6358_SPI2_BASE (0xfffe0800) #define BCM_6358_UDC0_BASE (0xfffe0800) #define BCM_6358_OHCI0_BASE (0xfffe1400) -- cgit v0.10.2 From 19372b24780868dc7cb983c4aaa8b796273bd4b6 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:58:30 +0200 Subject: MIPS: BCM63xx: Add BCM6368 SPI clock mask Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: grant.likely@secretlab.ca Cc: spi-devel-general@lists.sourceforge.net Patchwork: https://patchwork.linux-mips.org/patch/3319/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c index 8d2ea22..be49b9a 100644 --- a/arch/mips/bcm63xx/clk.c +++ b/arch/mips/bcm63xx/clk.c @@ -181,9 +181,11 @@ static void spi_set(struct clk *clk, int enable) mask = CKCTL_6338_SPI_EN; else if (BCMCPU_IS_6348()) mask = CKCTL_6348_SPI_EN; - else - /* BCMCPU_IS_6358 */ + else if (BCMCPU_IS_6358()) mask = CKCTL_6358_SPI_EN; + else + /* BCMCPU_IS_6368 */ + mask = CKCTL_6368_SPI_EN; bcm_hwclock_set(mask, enable); } -- cgit v0.10.2 From 7546d71a9c30893660714f9bef0e94d81aea127c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:58:32 +0200 Subject: MIPS: BCM63xx: Define SPI register sizes. There are two distinct sizes for the SPI register depending on the SoC generation (6338 & 6348 vs 6358 & 6368). Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: grant.likely@secretlab.ca Cc: spi-devel-general@lists.sourceforge.net Patchwork: https://patchwork.linux-mips.org/patch/3314/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index 016dc9e..4c1e147 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -135,6 +135,10 @@ enum bcm63xx_regs_set { #define RSET_DSL_LMEM_SIZE (64 * 1024 * 4) #define RSET_DSL_SIZE 4096 #define RSET_WDT_SIZE 12 +#define BCM_6338_RSET_SPI_SIZE 64 +#define BCM_6348_RSET_SPI_SIZE 64 +#define BCM_6358_RSET_SPI_SIZE 1804 +#define BCM_6368_RSET_SPI_SIZE 1804 #define RSET_ENET_SIZE 2048 #define RSET_ENETDMA_SIZE 2048 #define RSET_ENETSW_SIZE 65536 -- cgit v0.10.2 From 15514e78381e093dcdbc4613c96e077f0953f049 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:58:33 +0200 Subject: MIPS: BCM63xx: Remove SPI2 register This register was introduced with the support of the BCM6368 CPU in the idea that its internal layout was different from the other CPUs SPI controller. The controller is actually the same as the one present on BCM6358 so we can remove this register and use the usual SPI register instead. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: grant.likely@secretlab.ca Cc: spi-devel-general@lists.sourceforge.net Patchwork: https://patchwork.linux-mips.org/patch/3316/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index 4c1e147..82a8175 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -102,7 +102,6 @@ enum bcm63xx_regs_set { RSET_UART1, RSET_GPIO, RSET_SPI, - RSET_SPI2, RSET_UDC0, RSET_OHCI0, RSET_OHCI_PRIV, @@ -166,7 +165,6 @@ enum bcm63xx_regs_set { #define BCM_6338_UART1_BASE (0xdeadbeef) #define BCM_6338_GPIO_BASE (0xfffe0400) #define BCM_6338_SPI_BASE (0xfffe0c00) -#define BCM_6338_SPI2_BASE (0xdeadbeef) #define BCM_6338_UDC0_BASE (0xdeadbeef) #define BCM_6338_USBDMA_BASE (0xfffe2400) #define BCM_6338_OHCI0_BASE (0xdeadbeef) @@ -210,7 +208,6 @@ enum bcm63xx_regs_set { #define BCM_6345_UART1_BASE (0xdeadbeef) #define BCM_6345_GPIO_BASE (0xfffe0400) #define BCM_6345_SPI_BASE (0xdeadbeef) -#define BCM_6345_SPI2_BASE (0xdeadbeef) #define BCM_6345_UDC0_BASE (0xdeadbeef) #define BCM_6345_USBDMA_BASE (0xfffe2800) #define BCM_6345_ENET0_BASE (0xfffe1800) @@ -253,7 +250,6 @@ enum bcm63xx_regs_set { #define BCM_6348_UART1_BASE (0xdeadbeef) #define BCM_6348_GPIO_BASE (0xfffe0400) #define BCM_6348_SPI_BASE (0xfffe0c00) -#define BCM_6348_SPI2_BASE (0xdeadbeef) #define BCM_6348_UDC0_BASE (0xfffe1000) #define BCM_6348_OHCI0_BASE (0xfffe1b00) #define BCM_6348_OHCI_PRIV_BASE (0xfffe1c00) @@ -294,7 +290,6 @@ enum bcm63xx_regs_set { #define BCM_6358_UART1_BASE (0xfffe0120) #define BCM_6358_GPIO_BASE (0xfffe0080) #define BCM_6358_SPI_BASE (0xfffe0800) -#define BCM_6358_SPI2_BASE (0xfffe0800) #define BCM_6358_UDC0_BASE (0xfffe0800) #define BCM_6358_OHCI0_BASE (0xfffe1400) #define BCM_6358_OHCI_PRIV_BASE (0xdeadbeef) @@ -335,8 +330,7 @@ enum bcm63xx_regs_set { #define BCM_6368_UART0_BASE (0xb0000100) #define BCM_6368_UART1_BASE (0xb0000120) #define BCM_6368_GPIO_BASE (0xb0000080) -#define BCM_6368_SPI_BASE (0xdeadbeef) -#define BCM_6368_SPI2_BASE (0xb0000800) +#define BCM_6368_SPI_BASE (0xb0000800) #define BCM_6368_UDC0_BASE (0xdeadbeef) #define BCM_6368_OHCI0_BASE (0xb0001600) #define BCM_6368_OHCI_PRIV_BASE (0xdeadbeef) @@ -383,7 +377,6 @@ extern const unsigned long *bcm63xx_regs_base; __GEN_RSET_BASE(__cpu, UART1) \ __GEN_RSET_BASE(__cpu, GPIO) \ __GEN_RSET_BASE(__cpu, SPI) \ - __GEN_RSET_BASE(__cpu, SPI2) \ __GEN_RSET_BASE(__cpu, UDC0) \ __GEN_RSET_BASE(__cpu, OHCI0) \ __GEN_RSET_BASE(__cpu, OHCI_PRIV) \ @@ -422,7 +415,6 @@ extern const unsigned long *bcm63xx_regs_base; [RSET_UART1] = BCM_## __cpu ##_UART1_BASE, \ [RSET_GPIO] = BCM_## __cpu ##_GPIO_BASE, \ [RSET_SPI] = BCM_## __cpu ##_SPI_BASE, \ - [RSET_SPI2] = BCM_## __cpu ##_SPI2_BASE, \ [RSET_UDC0] = BCM_## __cpu ##_UDC0_BASE, \ [RSET_OHCI0] = BCM_## __cpu ##_OHCI0_BASE, \ [RSET_OHCI_PRIV] = BCM_## __cpu ##_OHCI_PRIV_BASE, \ -- cgit v0.10.2 From 0f6db0d07289c9ebf46be8909afe2b3772e06015 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:58:35 +0200 Subject: MIPS: BCM63xx: Define internal registers offsets of the SPI controller BCM6338, BCM6348, BCM6358 and BCM6368 basically use the same SPI controller though the internal registers are shuffled, which still allows a common driver to drive that IP block. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: grant.likely@secretlab.ca Cc: spi-devel-general@lists.sourceforge.net Patchwork: https://patchwork.linux-mips.org/patch/3318/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index e372132..be107e9 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -973,4 +973,123 @@ #define M2M_SRCID_REG(x) ((x) * 0x40 + 0x14) #define M2M_DSTID_REG(x) ((x) * 0x40 + 0x18) +/************************************************************************* + * _REG relative to RSET_SPI + *************************************************************************/ + +/* BCM 6338 SPI core */ +#define SPI_6338_CMD 0x00 /* 16-bits register */ +#define SPI_6338_INT_STATUS 0x02 +#define SPI_6338_INT_MASK_ST 0x03 +#define SPI_6338_INT_MASK 0x04 +#define SPI_6338_ST 0x05 +#define SPI_6338_CLK_CFG 0x06 +#define SPI_6338_FILL_BYTE 0x07 +#define SPI_6338_MSG_TAIL 0x09 +#define SPI_6338_RX_TAIL 0x0b +#define SPI_6338_MSG_CTL 0x40 +#define SPI_6338_MSG_DATA 0x41 +#define SPI_6338_MSG_DATA_SIZE 0x3f +#define SPI_6338_RX_DATA 0x80 +#define SPI_6338_RX_DATA_SIZE 0x3f + +/* BCM 6348 SPI core */ +#define SPI_6348_CMD 0x00 /* 16-bits register */ +#define SPI_6348_INT_STATUS 0x02 +#define SPI_6348_INT_MASK_ST 0x03 +#define SPI_6348_INT_MASK 0x04 +#define SPI_6348_ST 0x05 +#define SPI_6348_CLK_CFG 0x06 +#define SPI_6348_FILL_BYTE 0x07 +#define SPI_6348_MSG_TAIL 0x09 +#define SPI_6348_RX_TAIL 0x0b +#define SPI_6348_MSG_CTL 0x40 +#define SPI_6348_MSG_DATA 0x41 +#define SPI_6348_MSG_DATA_SIZE 0x3f +#define SPI_6348_RX_DATA 0x80 +#define SPI_6348_RX_DATA_SIZE 0x3f + +/* BCM 6358 SPI core */ +#define SPI_6358_MSG_CTL 0x00 /* 16-bits register */ +#define SPI_6358_MSG_DATA 0x02 +#define SPI_6358_MSG_DATA_SIZE 0x21e +#define SPI_6358_RX_DATA 0x400 +#define SPI_6358_RX_DATA_SIZE 0x220 +#define SPI_6358_CMD 0x700 /* 16-bits register */ +#define SPI_6358_INT_STATUS 0x702 +#define SPI_6358_INT_MASK_ST 0x703 +#define SPI_6358_INT_MASK 0x704 +#define SPI_6358_ST 0x705 +#define SPI_6358_CLK_CFG 0x706 +#define SPI_6358_FILL_BYTE 0x707 +#define SPI_6358_MSG_TAIL 0x709 +#define SPI_6358_RX_TAIL 0x70B + +/* BCM 6358 SPI core */ +#define SPI_6368_MSG_CTL 0x00 /* 16-bits register */ +#define SPI_6368_MSG_DATA 0x02 +#define SPI_6368_MSG_DATA_SIZE 0x21e +#define SPI_6368_RX_DATA 0x400 +#define SPI_6368_RX_DATA_SIZE 0x220 +#define SPI_6368_CMD 0x700 /* 16-bits register */ +#define SPI_6368_INT_STATUS 0x702 +#define SPI_6368_INT_MASK_ST 0x703 +#define SPI_6368_INT_MASK 0x704 +#define SPI_6368_ST 0x705 +#define SPI_6368_CLK_CFG 0x706 +#define SPI_6368_FILL_BYTE 0x707 +#define SPI_6368_MSG_TAIL 0x709 +#define SPI_6368_RX_TAIL 0x70B + +/* Shared SPI definitions */ + +/* Message configuration */ +#define SPI_FD_RW 0x00 +#define SPI_HD_W 0x01 +#define SPI_HD_R 0x02 +#define SPI_BYTE_CNT_SHIFT 0 +#define SPI_MSG_TYPE_SHIFT 14 + +/* Command */ +#define SPI_CMD_NOOP 0x00 +#define SPI_CMD_SOFT_RESET 0x01 +#define SPI_CMD_HARD_RESET 0x02 +#define SPI_CMD_START_IMMEDIATE 0x03 +#define SPI_CMD_COMMAND_SHIFT 0 +#define SPI_CMD_COMMAND_MASK 0x000f +#define SPI_CMD_DEVICE_ID_SHIFT 4 +#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT 8 +#define SPI_CMD_ONE_BYTE_SHIFT 11 +#define SPI_CMD_ONE_WIRE_SHIFT 12 +#define SPI_DEV_ID_0 0 +#define SPI_DEV_ID_1 1 +#define SPI_DEV_ID_2 2 +#define SPI_DEV_ID_3 3 + +/* Interrupt mask */ +#define SPI_INTR_CMD_DONE 0x01 +#define SPI_INTR_RX_OVERFLOW 0x02 +#define SPI_INTR_TX_UNDERFLOW 0x04 +#define SPI_INTR_TX_OVERFLOW 0x08 +#define SPI_INTR_RX_UNDERFLOW 0x10 +#define SPI_INTR_CLEAR_ALL 0x1f + +/* Status */ +#define SPI_RX_EMPTY 0x02 +#define SPI_CMD_BUSY 0x04 +#define SPI_SERIAL_BUSY 0x08 + +/* Clock configuration */ +#define SPI_CLK_20MHZ 0x00 +#define SPI_CLK_0_391MHZ 0x01 +#define SPI_CLK_0_781MHZ 0x02 /* default */ +#define SPI_CLK_1_563MHZ 0x03 +#define SPI_CLK_3_125MHZ 0x04 +#define SPI_CLK_6_250MHZ 0x05 +#define SPI_CLK_12_50MHZ 0x06 +#define SPI_CLK_MASK 0x07 +#define SPI_SSOFFTIME_MASK 0x38 +#define SPI_SSOFFTIME_SHIFT 3 +#define SPI_BYTE_SWAP 0x80 + #endif /* BCM63XX_REGS_H_ */ -- cgit v0.10.2 From 39ca476e3439bb135ff37ed1310469735ade06bf Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:58:36 +0200 Subject: MIPS: BCM63xx: Add stub to register the SPI platform driver This patch adds the necessary stub to register the SPI platform driver. Since the registers are shuffled between the 4 BCM63xx CPUs supported by this SPI driver we also need to generate the internal register layout and export this layout for the driver to use it properly. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: grant.likely@secretlab.ca Cc: spi-devel-general@lists.sourceforge.net Patchwork: https://patchwork.linux-mips.org/patch/3321/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile index 6dfdc69..4049cd5 100644 --- a/arch/mips/bcm63xx/Makefile +++ b/arch/mips/bcm63xx/Makefile @@ -1,5 +1,6 @@ obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \ - dev-dsp.o dev-enet.o dev-pcmcia.o dev-uart.o dev-wdt.o + dev-dsp.o dev-enet.o dev-pcmcia.o dev-spi.o dev-uart.o \ + dev-wdt.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-y += boards/ diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c new file mode 100644 index 0000000..67fa45b --- /dev/null +++ b/arch/mips/bcm63xx/dev-spi.c @@ -0,0 +1,119 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2009-2011 Florian Fainelli + * Copyright (C) 2010 Tanguy Bouzeloc + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef BCMCPU_RUNTIME_DETECT +/* + * register offsets + */ +static const unsigned long bcm6338_regs_spi[] = { + __GEN_SPI_REGS_TABLE(6338) +}; + +static const unsigned long bcm6348_regs_spi[] = { + __GEN_SPI_REGS_TABLE(6348) +}; + +static const unsigned long bcm6358_regs_spi[] = { + __GEN_SPI_REGS_TABLE(6358) +}; + +static const unsigned long bcm6368_regs_spi[] = { + __GEN_SPI_REGS_TABLE(6368) +}; + +const unsigned long *bcm63xx_regs_spi; +EXPORT_SYMBOL(bcm63xx_regs_spi); + +static __init void bcm63xx_spi_regs_init(void) +{ + if (BCMCPU_IS_6338()) + bcm63xx_regs_spi = bcm6338_regs_spi; + if (BCMCPU_IS_6348()) + bcm63xx_regs_spi = bcm6348_regs_spi; + if (BCMCPU_IS_6358()) + bcm63xx_regs_spi = bcm6358_regs_spi; + if (BCMCPU_IS_6368()) + bcm63xx_regs_spi = bcm6368_regs_spi; +} +#else +static __init void bcm63xx_spi_regs_init(void) { } +#endif + +static struct resource spi_resources[] = { + { + .start = -1, /* filled at runtime */ + .end = -1, /* filled at runtime */ + .flags = IORESOURCE_MEM, + }, + { + .start = -1, /* filled at runtime */ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct bcm63xx_spi_pdata spi_pdata = { + .bus_num = 0, + .num_chipselect = 8, +}; + +static struct platform_device bcm63xx_spi_device = { + .name = "bcm63xx-spi", + .id = -1, + .num_resources = ARRAY_SIZE(spi_resources), + .resource = spi_resources, + .dev = { + .platform_data = &spi_pdata, + }, +}; + +int __init bcm63xx_spi_register(void) +{ + struct clk *periph_clk; + + if (BCMCPU_IS_6345()) + return -ENODEV; + + periph_clk = clk_get(NULL, "periph"); + if (IS_ERR(periph_clk)) { + pr_err("unable to get periph clock\n"); + return -ENODEV; + } + + /* Set bus frequency */ + spi_pdata.speed_hz = clk_get_rate(periph_clk); + + spi_resources[0].start = bcm63xx_regset_address(RSET_SPI); + spi_resources[0].end = spi_resources[0].start; + spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI); + + if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) { + spi_resources[0].end += BCM_6338_RSET_SPI_SIZE - 1; + spi_pdata.fifo_size = SPI_6338_MSG_DATA_SIZE; + } + + if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) { + spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1; + spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE; + } + + bcm63xx_spi_regs_init(); + + return platform_device_register(&bcm63xx_spi_device); +} diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h new file mode 100644 index 0000000..7d98dbe --- /dev/null +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h @@ -0,0 +1,89 @@ +#ifndef BCM63XX_DEV_SPI_H +#define BCM63XX_DEV_SPI_H + +#include +#include +#include + +int __init bcm63xx_spi_register(void); + +struct bcm63xx_spi_pdata { + unsigned int fifo_size; + int bus_num; + int num_chipselect; + u32 speed_hz; +}; + +enum bcm63xx_regs_spi { + SPI_CMD, + SPI_INT_STATUS, + SPI_INT_MASK_ST, + SPI_INT_MASK, + SPI_ST, + SPI_CLK_CFG, + SPI_FILL_BYTE, + SPI_MSG_TAIL, + SPI_RX_TAIL, + SPI_MSG_CTL, + SPI_MSG_DATA, + SPI_RX_DATA, +}; + +#define __GEN_SPI_RSET_BASE(__cpu, __rset) \ + case SPI_## __rset: \ + return SPI_## __cpu ##_## __rset; + +#define __GEN_SPI_RSET(__cpu) \ + switch (reg) { \ + __GEN_SPI_RSET_BASE(__cpu, CMD) \ + __GEN_SPI_RSET_BASE(__cpu, INT_STATUS) \ + __GEN_SPI_RSET_BASE(__cpu, INT_MASK_ST) \ + __GEN_SPI_RSET_BASE(__cpu, INT_MASK) \ + __GEN_SPI_RSET_BASE(__cpu, ST) \ + __GEN_SPI_RSET_BASE(__cpu, CLK_CFG) \ + __GEN_SPI_RSET_BASE(__cpu, FILL_BYTE) \ + __GEN_SPI_RSET_BASE(__cpu, MSG_TAIL) \ + __GEN_SPI_RSET_BASE(__cpu, RX_TAIL) \ + __GEN_SPI_RSET_BASE(__cpu, MSG_CTL) \ + __GEN_SPI_RSET_BASE(__cpu, MSG_DATA) \ + __GEN_SPI_RSET_BASE(__cpu, RX_DATA) \ + } + +#define __GEN_SPI_REGS_TABLE(__cpu) \ + [SPI_CMD] = SPI_## __cpu ##_CMD, \ + [SPI_INT_STATUS] = SPI_## __cpu ##_INT_STATUS, \ + [SPI_INT_MASK_ST] = SPI_## __cpu ##_INT_MASK_ST, \ + [SPI_INT_MASK] = SPI_## __cpu ##_INT_MASK, \ + [SPI_ST] = SPI_## __cpu ##_ST, \ + [SPI_CLK_CFG] = SPI_## __cpu ##_CLK_CFG, \ + [SPI_FILL_BYTE] = SPI_## __cpu ##_FILL_BYTE, \ + [SPI_MSG_TAIL] = SPI_## __cpu ##_MSG_TAIL, \ + [SPI_RX_TAIL] = SPI_## __cpu ##_RX_TAIL, \ + [SPI_MSG_CTL] = SPI_## __cpu ##_MSG_CTL, \ + [SPI_MSG_DATA] = SPI_## __cpu ##_MSG_DATA, \ + [SPI_RX_DATA] = SPI_## __cpu ##_RX_DATA, + +static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg) +{ +#ifdef BCMCPU_RUNTIME_DETECT + extern const unsigned long *bcm63xx_regs_spi; + + return bcm63xx_regs_spi[reg]; +#else +#ifdef CONFIG_BCM63XX_CPU_6338 + __GEN_SPI_RSET(6338) +#endif +#ifdef CONFIG_BCM63XX_CPU_6348 + __GEN_SPI_RSET(6348) +#endif +#ifdef CONFIG_BCM63XX_CPU_6358 + __GEN_SPI_RSET(6358) +#endif +#ifdef CONFIG_BCM63XX_CPU_6368 + __GEN_SPI_RSET(6368) +#endif +#endif + return 0; +} + +#endif /* BCM63XX_DEV_SPI_H */ -- cgit v0.10.2 From 76ca4e1484f2ada3e455eafdcc89e3cba089a37a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Jul 2012 16:58:37 +0200 Subject: MIPS: BCM63xx: Make board setup code register the spi platform device Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: grant.likely@secretlab.ca Cc: spi-devel-general@lists.sourceforge.net Patchwork: https://patchwork.linux-mips.org/patch/3317/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index 2f1773f..ea65c0f 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define PFX "board_bcm963xx: " @@ -890,6 +891,8 @@ int __init board_register_devices(void) } #endif + bcm63xx_spi_register(); + /* read base address of boot chip select (0) */ val = bcm_mpi_readl(MPI_CSBASE_REG(0)); val &= MPI_CSBASE_BASE_MASK; -- cgit v0.10.2 From 05b8c8c1288c078f8920f5894854086f0e10f095 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 14:49:49 +0200 Subject: MIPS: OCTEON: Remove some unused files. These FPA related files are not used anywhere in the kernel. Remove them. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3892/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/executive/cvmx-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-fpa.c deleted file mode 100644 index ad44b8b..0000000 --- a/arch/mips/cavium-octeon/executive/cvmx-fpa.c +++ /dev/null @@ -1,183 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Support library for the hardware Free Pool Allocator. - * - * - */ - -#include "cvmx-config.h" -#include "cvmx.h" -#include "cvmx-fpa.h" -#include "cvmx-ipd.h" - -/** - * Current state of all the pools. Use access functions - * instead of using it directly. - */ -CVMX_SHARED cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS]; - -/** - * Setup a FPA pool to control a new block of memory. The - * buffer pointer must be a physical address. - * - * @pool: Pool to initialize - * 0 <= pool < 8 - * @name: Constant character string to name this pool. - * String is not copied. - * @buffer: Pointer to the block of memory to use. This must be - * accessible by all processors and external hardware. - * @block_size: Size for each block controlled by the FPA - * @num_blocks: Number of blocks - * - * Returns 0 on Success, - * -1 on failure - */ -int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer, - uint64_t block_size, uint64_t num_blocks) -{ - char *ptr; - if (!buffer) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: NULL buffer pointer!\n"); - return -1; - } - if (pool >= CVMX_FPA_NUM_POOLS) { - cvmx_dprintf("ERROR: cvmx_fpa_setup_pool: Illegal pool!\n"); - return -1; - } - - if (block_size < CVMX_FPA_MIN_BLOCK_SIZE) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: Block size too small.\n"); - return -1; - } - - if (((unsigned long)buffer & (CVMX_FPA_ALIGNMENT - 1)) != 0) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: Buffer not aligned properly.\n"); - return -1; - } - - cvmx_fpa_pool_info[pool].name = name; - cvmx_fpa_pool_info[pool].size = block_size; - cvmx_fpa_pool_info[pool].starting_element_count = num_blocks; - cvmx_fpa_pool_info[pool].base = buffer; - - ptr = (char *)buffer; - while (num_blocks--) { - cvmx_fpa_free(ptr, pool, 0); - ptr += block_size; - } - return 0; -} - -/** - * Shutdown a Memory pool and validate that it had all of - * the buffers originally placed in it. - * - * @pool: Pool to shutdown - * Returns Zero on success - * - Positive is count of missing buffers - * - Negative is too many buffers or corrupted pointers - */ -uint64_t cvmx_fpa_shutdown_pool(uint64_t pool) -{ - uint64_t errors = 0; - uint64_t count = 0; - uint64_t base = cvmx_ptr_to_phys(cvmx_fpa_pool_info[pool].base); - uint64_t finish = - base + - cvmx_fpa_pool_info[pool].size * - cvmx_fpa_pool_info[pool].starting_element_count; - void *ptr; - uint64_t address; - - count = 0; - do { - ptr = cvmx_fpa_alloc(pool); - if (ptr) - address = cvmx_ptr_to_phys(ptr); - else - address = 0; - if (address) { - if ((address >= base) && (address < finish) && - (((address - - base) % cvmx_fpa_pool_info[pool].size) == 0)) { - count++; - } else { - cvmx_dprintf - ("ERROR: cvmx_fpa_shutdown_pool: Illegal address 0x%llx in pool %s(%d)\n", - (unsigned long long)address, - cvmx_fpa_pool_info[pool].name, (int)pool); - errors++; - } - } - } while (address); - -#ifdef CVMX_ENABLE_PKO_FUNCTIONS - if (pool == 0) - cvmx_ipd_free_ptr(); -#endif - - if (errors) { - cvmx_dprintf - ("ERROR: cvmx_fpa_shutdown_pool: Pool %s(%d) started at 0x%llx, ended at 0x%llx, with a step of 0x%llx\n", - cvmx_fpa_pool_info[pool].name, (int)pool, - (unsigned long long)base, (unsigned long long)finish, - (unsigned long long)cvmx_fpa_pool_info[pool].size); - return -errors; - } else - return 0; -} - -uint64_t cvmx_fpa_get_block_size(uint64_t pool) -{ - switch (pool) { - case 0: - return CVMX_FPA_POOL_0_SIZE; - case 1: - return CVMX_FPA_POOL_1_SIZE; - case 2: - return CVMX_FPA_POOL_2_SIZE; - case 3: - return CVMX_FPA_POOL_3_SIZE; - case 4: - return CVMX_FPA_POOL_4_SIZE; - case 5: - return CVMX_FPA_POOL_5_SIZE; - case 6: - return CVMX_FPA_POOL_6_SIZE; - case 7: - return CVMX_FPA_POOL_7_SIZE; - default: - return 0; - } -} diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c deleted file mode 100644 index c239e5f..0000000 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c +++ /dev/null @@ -1,243 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Helper functions for FPA setup. - * - */ -#include "executive-config.h" -#include "cvmx-config.h" -#include "cvmx.h" -#include "cvmx-bootmem.h" -#include "cvmx-fpa.h" -#include "cvmx-helper-fpa.h" - -/** - * Allocate memory for and initialize a single FPA pool. - * - * @pool: Pool to initialize - * @buffer_size: Size of buffers to allocate in bytes - * @buffers: Number of buffers to put in the pool. Zero is allowed - * @name: String name of the pool for debugging purposes - * Returns Zero on success, non-zero on failure - */ -static int __cvmx_helper_initialize_fpa_pool(int pool, uint64_t buffer_size, - uint64_t buffers, const char *name) -{ - uint64_t current_num; - void *memory; - uint64_t align = CVMX_CACHE_LINE_SIZE; - - /* - * Align the allocation so that power of 2 size buffers are - * naturally aligned. - */ - while (align < buffer_size) - align = align << 1; - - if (buffers == 0) - return 0; - - current_num = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(pool)); - if (current_num) { - cvmx_dprintf("Fpa pool %d(%s) already has %llu buffers. " - "Skipping setup.\n", - pool, name, (unsigned long long)current_num); - return 0; - } - - memory = cvmx_bootmem_alloc(buffer_size * buffers, align); - if (memory == NULL) { - cvmx_dprintf("Out of memory initializing fpa pool %d(%s).\n", - pool, name); - return -1; - } - cvmx_fpa_setup_pool(pool, name, memory, buffer_size, buffers); - return 0; -} - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Specifying zero for the number of - * buffers will cause that FPA pool to not be setup. This is - * useful if you aren't using some of the hardware and want - * to save memory. Use cvmx_helper_initialize_fpa instead of - * this function directly. - * - * @pip_pool: Should always be CVMX_FPA_PACKET_POOL - * @pip_size: Should always be CVMX_FPA_PACKET_POOL_SIZE - * @pip_buffers: - * Number of packet buffers. - * @wqe_pool: Should always be CVMX_FPA_WQE_POOL - * @wqe_size: Should always be CVMX_FPA_WQE_POOL_SIZE - * @wqe_entries: - * Number of work queue entries - * @pko_pool: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL - * @pko_size: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_pool: Should always be CVMX_FPA_TIMER_POOL - * @tim_size: Should always be CVMX_FPA_TIMER_POOL_SIZE - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_pool: Should always be CVMX_FPA_DFA_POOL - * @dfa_size: Should always be CVMX_FPA_DFA_POOL_SIZE - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -static int __cvmx_helper_initialize_fpa(int pip_pool, int pip_size, - int pip_buffers, int wqe_pool, - int wqe_size, int wqe_entries, - int pko_pool, int pko_size, - int pko_buffers, int tim_pool, - int tim_size, int tim_buffers, - int dfa_pool, int dfa_size, - int dfa_buffers) -{ - int status; - - cvmx_fpa_enable(); - - if ((pip_buffers > 0) && (pip_buffers <= 64)) - cvmx_dprintf - ("Warning: %d packet buffers may not be enough for hardware" - " prefetch. 65 or more is recommended.\n", pip_buffers); - - if (pip_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(pip_pool, pip_size, - pip_buffers, - "Packet Buffers"); - if (status) - return status; - } - - if (wqe_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(wqe_pool, wqe_size, - wqe_entries, - "Work Queue Entries"); - if (status) - return status; - } - - if (pko_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(pko_pool, pko_size, - pko_buffers, - "PKO Command Buffers"); - if (status) - return status; - } - - if (tim_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(tim_pool, tim_size, - tim_buffers, - "TIM Command Buffers"); - if (status) - return status; - } - - if (dfa_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(dfa_pool, dfa_size, - dfa_buffers, - "DFA Command Buffers"); - if (status) - return status; - } - - return 0; -} - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Sizes of each element in the pools is - * controlled by the cvmx-config.h header file. Specifying - * zero for any parameter will cause that FPA pool to not be - * setup. This is useful if you aren't using some of the - * hardware and want to save memory. - * - * @packet_buffers: - * Number of packet buffers to allocate - * @work_queue_entries: - * Number of work queue entries - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -int cvmx_helper_initialize_fpa(int packet_buffers, int work_queue_entries, - int pko_buffers, int tim_buffers, - int dfa_buffers) -{ -#ifndef CVMX_FPA_PACKET_POOL -#define CVMX_FPA_PACKET_POOL -1 -#define CVMX_FPA_PACKET_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_WQE_POOL -#define CVMX_FPA_WQE_POOL -1 -#define CVMX_FPA_WQE_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_OUTPUT_BUFFER_POOL -#define CVMX_FPA_OUTPUT_BUFFER_POOL -1 -#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_TIMER_POOL -#define CVMX_FPA_TIMER_POOL -1 -#define CVMX_FPA_TIMER_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_DFA_POOL -#define CVMX_FPA_DFA_POOL -1 -#define CVMX_FPA_DFA_POOL_SIZE 0 -#endif - return __cvmx_helper_initialize_fpa(CVMX_FPA_PACKET_POOL, - CVMX_FPA_PACKET_POOL_SIZE, - packet_buffers, CVMX_FPA_WQE_POOL, - CVMX_FPA_WQE_POOL_SIZE, - work_queue_entries, - CVMX_FPA_OUTPUT_BUFFER_POOL, - CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, - pko_buffers, CVMX_FPA_TIMER_POOL, - CVMX_FPA_TIMER_POOL_SIZE, - tim_buffers, CVMX_FPA_DFA_POOL, - CVMX_FPA_DFA_POOL_SIZE, - dfa_buffers); -} diff --git a/arch/mips/include/asm/octeon/cvmx-helper-fpa.h b/arch/mips/include/asm/octeon/cvmx-helper-fpa.h deleted file mode 100644 index 5ff8c93..0000000 --- a/arch/mips/include/asm/octeon/cvmx-helper-fpa.h +++ /dev/null @@ -1,64 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Helper functions for FPA setup. - * - */ -#ifndef __CVMX_HELPER_H_FPA__ -#define __CVMX_HELPER_H_FPA__ - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Sizes of each element in the pools is - * controlled by the cvmx-config.h header file. Specifying - * zero for any parameter will cause that FPA pool to not be - * setup. This is useful if you aren't using some of the - * hardware and want to save memory. - * - * @packet_buffers: - * Number of packet buffers to allocate - * @work_queue_entries: - * Number of work queue entries - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -extern int cvmx_helper_initialize_fpa(int packet_buffers, - int work_queue_entries, int pko_buffers, - int tim_buffers, int dfa_buffers); - -#endif /* __CVMX_HELPER_H__ */ diff --git a/arch/mips/include/asm/octeon/cvmx-helper.h b/arch/mips/include/asm/octeon/cvmx-helper.h index 3169cd7..0ac6b9f 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper.h +++ b/arch/mips/include/asm/octeon/cvmx-helper.h @@ -61,8 +61,6 @@ typedef union { } s; } cvmx_helper_link_info_t; -#include "cvmx-helper-fpa.h" - #include #include "cvmx-helper-loop.h" #include "cvmx-helper-npi.h" -- cgit v0.10.2 From 6d1ab4c22d43bd2b17cc42513c2fbbde9af93031 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:37 +0200 Subject: MIPS: Octeon: Add irq handlers for GPIO interrupts. This is needed for follow-on on patches for Octeon to use the Device Tree to configure GPIO interrupts. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3932/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index ffd4ae6..168b489 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -505,6 +505,85 @@ static void octeon_irq_ciu_enable_all_v2(struct irq_data *data) } } +static void octeon_irq_gpio_setup(struct irq_data *data) +{ + union cvmx_gpio_bit_cfgx cfg; + union octeon_ciu_chip_data cd; + u32 t = irqd_get_trigger_type(data); + + cd.p = irq_data_get_irq_chip_data(data); + + cfg.u64 = 0; + cfg.s.int_en = 1; + cfg.s.int_type = (t & IRQ_TYPE_EDGE_BOTH) != 0; + cfg.s.rx_xor = (t & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) != 0; + + /* 140 nS glitch filter*/ + cfg.s.fil_cnt = 7; + cfg.s.fil_sel = 3; + + cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), cfg.u64); +} + +static void octeon_irq_ciu_enable_gpio_v2(struct irq_data *data) +{ + octeon_irq_gpio_setup(data); + octeon_irq_ciu_enable_v2(data); +} + +static void octeon_irq_ciu_enable_gpio(struct irq_data *data) +{ + octeon_irq_gpio_setup(data); + octeon_irq_ciu_enable(data); +} + +static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t) +{ + irqd_set_trigger_type(data, t); + octeon_irq_gpio_setup(data); + + return IRQ_SET_MASK_OK; +} + +static void octeon_irq_ciu_disable_gpio_v2(struct irq_data *data) +{ + union octeon_ciu_chip_data cd; + + cd.p = irq_data_get_irq_chip_data(data); + cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), 0); + + octeon_irq_ciu_disable_all_v2(data); +} + +static void octeon_irq_ciu_disable_gpio(struct irq_data *data) +{ + union octeon_ciu_chip_data cd; + + cd.p = irq_data_get_irq_chip_data(data); + cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), 0); + + octeon_irq_ciu_disable_all(data); +} + +static void octeon_irq_ciu_gpio_ack(struct irq_data *data) +{ + union octeon_ciu_chip_data cd; + u64 mask; + + cd.p = irq_data_get_irq_chip_data(data); + mask = 1ull << (cd.s.bit - 16); + + cvmx_write_csr(CVMX_GPIO_INT_CLR, mask); +} + +static void octeon_irq_handle_gpio(unsigned int irq, struct irq_desc *desc) +{ + if (irqd_get_trigger_type(irq_desc_get_irq_data(desc)) & IRQ_TYPE_EDGE_BOTH) + handle_edge_irq(irq, desc); + else + handle_level_irq(irq, desc); +} + #ifdef CONFIG_SMP static void octeon_irq_cpu_offline_ciu(struct irq_data *data) @@ -717,6 +796,33 @@ static struct irq_chip octeon_irq_chip_ciu_mbox = { .flags = IRQCHIP_ONOFFLINE_ENABLED, }; +static struct irq_chip octeon_irq_chip_ciu_gpio_v2 = { + .name = "CIU-GPIO", + .irq_enable = octeon_irq_ciu_enable_gpio_v2, + .irq_disable = octeon_irq_ciu_disable_gpio_v2, + .irq_ack = octeon_irq_ciu_gpio_ack, + .irq_mask = octeon_irq_ciu_disable_local_v2, + .irq_unmask = octeon_irq_ciu_enable_v2, + .irq_set_type = octeon_irq_ciu_gpio_set_type, +#ifdef CONFIG_SMP + .irq_set_affinity = octeon_irq_ciu_set_affinity_v2, +#endif + .flags = IRQCHIP_SET_TYPE_MASKED, +}; + +static struct irq_chip octeon_irq_chip_ciu_gpio = { + .name = "CIU-GPIO", + .irq_enable = octeon_irq_ciu_enable_gpio, + .irq_disable = octeon_irq_ciu_disable_gpio, + .irq_mask = octeon_irq_dummy_mask, + .irq_ack = octeon_irq_ciu_gpio_ack, + .irq_set_type = octeon_irq_ciu_gpio_set_type, +#ifdef CONFIG_SMP + .irq_set_affinity = octeon_irq_ciu_set_affinity, +#endif + .flags = IRQCHIP_SET_TYPE_MASKED, +}; + /* * Watchdog interrupts are special. They are associated with a single * core, so we hardwire the affinity to that core. @@ -890,6 +996,7 @@ static void __init octeon_irq_init_ciu(void) struct irq_chip *chip_edge; struct irq_chip *chip_mbox; struct irq_chip *chip_wd; + struct irq_chip *chip_gpio; octeon_irq_init_ciu_percpu(); octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu; @@ -904,6 +1011,7 @@ static void __init octeon_irq_init_ciu(void) chip_edge = &octeon_irq_chip_ciu_edge_v2; chip_mbox = &octeon_irq_chip_ciu_mbox_v2; chip_wd = &octeon_irq_chip_ciu_wd_v2; + chip_gpio = &octeon_irq_chip_ciu_gpio_v2; } else { octeon_irq_ip2 = octeon_irq_ip2_v1; octeon_irq_ip3 = octeon_irq_ip3_v1; @@ -911,6 +1019,7 @@ static void __init octeon_irq_init_ciu(void) chip_edge = &octeon_irq_chip_ciu_edge; chip_mbox = &octeon_irq_chip_ciu_mbox; chip_wd = &octeon_irq_chip_ciu_wd; + chip_gpio = &octeon_irq_chip_ciu_gpio; } octeon_irq_ip4 = octeon_irq_ip4_mask; @@ -921,7 +1030,7 @@ static void __init octeon_irq_init_ciu(void) for (i = 0; i < 16; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq); for (i = 0; i < 16; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip, handle_level_irq); + octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip_gpio, octeon_irq_handle_gpio); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq); -- cgit v0.10.2 From 0b28b823ac5bd4f9b2876ce9432ff2006c529f06 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:37 +0200 Subject: MIPS: Octeon: Remove use of OCTEON_IRQ_RST. This symbol will be removed, so don't use it as part of the definition of OCTEON_IRQ_LAST. Set OCTEON_IRQ_LAST to 127 so there is space for all the automatically allocated (via irq_domain) irqs. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3946/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h index 5b05f18..81a0324 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/irq.h +++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h @@ -86,6 +86,9 @@ enum octeon_irq { OCTEON_IRQ_LMC0, OCTEON_IRQ_DFM = OCTEON_IRQ_LMC0 + 4, /* Summary of DFM */ OCTEON_IRQ_RST, +#ifndef CONFIG_PCI_MSI + OCTEON_IRQ_LAST = 127 +#endif }; #ifdef CONFIG_PCI_MSI @@ -94,8 +97,6 @@ enum octeon_irq { #define OCTEON_IRQ_MSI_LAST (OCTEON_IRQ_MSI_BIT0 + 255) #define OCTEON_IRQ_LAST (OCTEON_IRQ_MSI_LAST + 1) -#else -#define OCTEON_IRQ_LAST (OCTEON_IRQ_RST + 1) #endif #endif -- cgit v0.10.2 From f5e08284211b09bc4aa85727a44293c529cfa923 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:38 +0200 Subject: MIPS: OCTEON: Remove unneeded OCTEON_IRQ_* defines. The follow-on patch to add irq_domain support will be the supported method for using these irq lines, so get these defines out of the way in preperation for that. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3930/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 168b489..bccbda9 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -1045,23 +1045,11 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI, 0, 45, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_TRACE0, 0, 47, chip, handle_level_irq); - - for (i = 0; i < 2; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GMX_DRP0, 0, i + 48, chip_edge, handle_edge_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPD_DRP, 0, 50, chip_edge, handle_edge_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_KEY_ZERO, 0, 51, chip_edge, handle_edge_irq); - for (i = 0; i < 4; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip_edge, handle_edge_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_PCM, 0, 57, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_MPI, 0, 58, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI2, 0, 59, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_POWIQ, 0, 60, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPDPPTHR, 0, 61, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII0, 0, 62, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq); @@ -1072,37 +1060,6 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART2, 1, 16, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII1, 1, 18, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_NAND, 1, 19, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_MIO, 1, 20, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_IOB, 1, 21, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_FPA, 1, 22, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_POW, 1, 23, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_L2C, 1, 24, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPD, 1, 25, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_PIP, 1, 26, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_PKO, 1, 27, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_ZIP, 1, 28, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_TIM, 1, 29, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_RAD, 1, 30, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_KEY, 1, 31, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_DFA, 1, 32, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_USBCTL, 1, 33, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_SLI, 1, 34, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_DPI, 1, 35, chip, handle_level_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_AGX0, 1, 36, chip, handle_level_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_AGL, 1, 46, chip, handle_level_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_PTP, 1, 47, chip_edge, handle_edge_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_PEM0, 1, 48, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_PEM1, 1, 49, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_SRIO0, 1, 50, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_SRIO1, 1, 51, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_LMC0, 1, 52, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_DFM, 1, 56, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_RST, 1, 63, chip, handle_level_irq); /* Enable the CIU lines */ set_c0_status(STATUSF_IP3 | STATUSF_IP2); diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h index 81a0324..4189920 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/irq.h +++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h @@ -41,59 +41,23 @@ enum octeon_irq { OCTEON_IRQ_TWSI, OCTEON_IRQ_TWSI2, OCTEON_IRQ_RML, - OCTEON_IRQ_TRACE0, - OCTEON_IRQ_GMX_DRP0 = OCTEON_IRQ_TRACE0 + 4, - OCTEON_IRQ_IPD_DRP = OCTEON_IRQ_GMX_DRP0 + 5, - OCTEON_IRQ_KEY_ZERO, OCTEON_IRQ_TIMER0, OCTEON_IRQ_TIMER1, OCTEON_IRQ_TIMER2, OCTEON_IRQ_TIMER3, OCTEON_IRQ_USB0, OCTEON_IRQ_USB1, - OCTEON_IRQ_PCM, - OCTEON_IRQ_MPI, - OCTEON_IRQ_POWIQ, - OCTEON_IRQ_IPDPPTHR, OCTEON_IRQ_MII0, OCTEON_IRQ_MII1, OCTEON_IRQ_BOOTDMA, - - OCTEON_IRQ_NAND, - OCTEON_IRQ_MIO, /* Summary of MIO_BOOT_ERR */ - OCTEON_IRQ_IOB, /* Summary of IOB_INT_SUM */ - OCTEON_IRQ_FPA, /* Summary of FPA_INT_SUM */ - OCTEON_IRQ_POW, /* Summary of POW_ECC_ERR */ - OCTEON_IRQ_L2C, /* Summary of L2C_INT_STAT */ - OCTEON_IRQ_IPD, /* Summary of IPD_INT_SUM */ - OCTEON_IRQ_PIP, /* Summary of PIP_INT_REG */ - OCTEON_IRQ_PKO, /* Summary of PKO_REG_ERROR */ - OCTEON_IRQ_ZIP, /* Summary of ZIP_ERROR */ - OCTEON_IRQ_TIM, /* Summary of TIM_REG_ERROR */ - OCTEON_IRQ_RAD, /* Summary of RAD_REG_ERROR */ - OCTEON_IRQ_KEY, /* Summary of KEY_INT_SUM */ - OCTEON_IRQ_DFA, /* Summary of DFA */ - OCTEON_IRQ_USBCTL, /* Summary of USBN0_INT_SUM */ - OCTEON_IRQ_SLI, /* Summary of SLI_INT_SUM */ - OCTEON_IRQ_DPI, /* Summary of DPI_INT_SUM */ - OCTEON_IRQ_AGX0, /* Summary of GMX0*+PCS0_INT*_REG */ - OCTEON_IRQ_AGL = OCTEON_IRQ_AGX0 + 5, - OCTEON_IRQ_PTP, - OCTEON_IRQ_PEM0, - OCTEON_IRQ_PEM1, - OCTEON_IRQ_SRIO0, - OCTEON_IRQ_SRIO1, - OCTEON_IRQ_LMC0, - OCTEON_IRQ_DFM = OCTEON_IRQ_LMC0 + 4, /* Summary of DFM */ - OCTEON_IRQ_RST, #ifndef CONFIG_PCI_MSI OCTEON_IRQ_LAST = 127 #endif }; #ifdef CONFIG_PCI_MSI -/* 152 - 407 represent the MSI interrupts 0-255 */ -#define OCTEON_IRQ_MSI_BIT0 (OCTEON_IRQ_RST + 1) +/* 256 - 511 represent the MSI interrupts 0-255 */ +#define OCTEON_IRQ_MSI_BIT0 (256) #define OCTEON_IRQ_MSI_LAST (OCTEON_IRQ_MSI_BIT0 + 255) #define OCTEON_IRQ_LAST (OCTEON_IRQ_MSI_LAST + 1) -- cgit v0.10.2 From a339aef90470cf21debb138f95e22adf143eecca Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:38 +0200 Subject: MIPS: OCTEON: Consolidate the edge and level irq_chip structures. We can consolidate octeon_irq_chip_ciu_edge and octeon_irq_chip_ciu as they only differ in the .irq_ack element, and that is unused by the level handler. This gets rid of a bunch of duplicate definitions. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3931/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index bccbda9..fac22a8 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -729,18 +729,6 @@ static struct irq_chip octeon_irq_chip_ciu_v2 = { .name = "CIU", .irq_enable = octeon_irq_ciu_enable_v2, .irq_disable = octeon_irq_ciu_disable_all_v2, - .irq_mask = octeon_irq_ciu_disable_local_v2, - .irq_unmask = octeon_irq_ciu_enable_v2, -#ifdef CONFIG_SMP - .irq_set_affinity = octeon_irq_ciu_set_affinity_v2, - .irq_cpu_offline = octeon_irq_cpu_offline_ciu, -#endif -}; - -static struct irq_chip octeon_irq_chip_ciu_edge_v2 = { - .name = "CIU-E", - .irq_enable = octeon_irq_ciu_enable_v2, - .irq_disable = octeon_irq_ciu_disable_all_v2, .irq_ack = octeon_irq_ciu_ack, .irq_mask = octeon_irq_ciu_disable_local_v2, .irq_unmask = octeon_irq_ciu_enable_v2, @@ -754,19 +742,8 @@ static struct irq_chip octeon_irq_chip_ciu = { .name = "CIU", .irq_enable = octeon_irq_ciu_enable, .irq_disable = octeon_irq_ciu_disable_all, - .irq_mask = octeon_irq_dummy_mask, -#ifdef CONFIG_SMP - .irq_set_affinity = octeon_irq_ciu_set_affinity, - .irq_cpu_offline = octeon_irq_cpu_offline_ciu, -#endif -}; - -static struct irq_chip octeon_irq_chip_ciu_edge = { - .name = "CIU-E", - .irq_enable = octeon_irq_ciu_enable, - .irq_disable = octeon_irq_ciu_disable_all, - .irq_mask = octeon_irq_dummy_mask, .irq_ack = octeon_irq_ciu_ack, + .irq_mask = octeon_irq_dummy_mask, #ifdef CONFIG_SMP .irq_set_affinity = octeon_irq_ciu_set_affinity, .irq_cpu_offline = octeon_irq_cpu_offline_ciu, @@ -993,7 +970,6 @@ static void __init octeon_irq_init_ciu(void) { unsigned int i; struct irq_chip *chip; - struct irq_chip *chip_edge; struct irq_chip *chip_mbox; struct irq_chip *chip_wd; struct irq_chip *chip_gpio; @@ -1008,7 +984,6 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_ip2 = octeon_irq_ip2_v2; octeon_irq_ip3 = octeon_irq_ip3_v2; chip = &octeon_irq_chip_ciu_v2; - chip_edge = &octeon_irq_chip_ciu_edge_v2; chip_mbox = &octeon_irq_chip_ciu_mbox_v2; chip_wd = &octeon_irq_chip_ciu_wd_v2; chip_gpio = &octeon_irq_chip_ciu_gpio_v2; @@ -1016,7 +991,6 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_ip2 = octeon_irq_ip2_v1; octeon_irq_ip3 = octeon_irq_ip3_v1; chip = &octeon_irq_chip_ciu; - chip_edge = &octeon_irq_chip_ciu_edge; chip_mbox = &octeon_irq_chip_ciu_mbox; chip_wd = &octeon_irq_chip_ciu_wd; chip_gpio = &octeon_irq_chip_ciu_gpio; @@ -1046,7 +1020,7 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI, 0, 45, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq); for (i = 0; i < 4; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip_edge, handle_edge_irq); + octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI2, 0, 59, chip, handle_level_irq); -- cgit v0.10.2 From ab25383983fb8d7786696f5371e75e79c3e9a405 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:38 +0200 Subject: of/lib: Allow scripts/dtc/libfdt to be used from kernel code libfdt is part of the device tree support in scripts/dtc/libfdt. For some platforms that use the Device Tree, we want to be able to edit the flattened device tree form. We don't want to burden kernel builds that do not require it, so we gate compilation of libfdt files with CONFIG_LIBFDT. So if it is needed, you need to do this in your Kconfig: select LIBFDT And in the Makefile of the code using libfdt something like: ccflags-y := -I$(src)/../../../scripts/dtc/libfdt Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: linux-kernel@vger.kernel.org Acked-by: Rob Herring Signed-off-by: Ralf Baechle diff --git a/include/linux/libfdt.h b/include/linux/libfdt.h new file mode 100644 index 0000000..4c0306c --- /dev/null +++ b/include/linux/libfdt.h @@ -0,0 +1,8 @@ +#ifndef _INCLUDE_LIBFDT_H_ +#define _INCLUDE_LIBFDT_H_ + +#include +#include "../../scripts/dtc/libfdt/fdt.h" +#include "../../scripts/dtc/libfdt/libfdt.h" + +#endif /* _INCLUDE_LIBFDT_H_ */ diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h new file mode 100644 index 0000000..01508c7 --- /dev/null +++ b/include/linux/libfdt_env.h @@ -0,0 +1,13 @@ +#ifndef _LIBFDT_ENV_H +#define _LIBFDT_ENV_H + +#include + +#include + +#define fdt32_to_cpu(x) be32_to_cpu(x) +#define cpu_to_fdt32(x) cpu_to_be32(x) +#define fdt64_to_cpu(x) be64_to_cpu(x) +#define cpu_to_fdt64(x) cpu_to_be64(x) + +#endif /* _LIBFDT_ENV_H */ diff --git a/lib/Kconfig b/lib/Kconfig index a9e1540..e091300 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -395,4 +395,10 @@ config SIGNATURE Digital signature verification. Currently only RSA is supported. Implementation is done using GnuPG MPI library +# +# libfdt files, only selected if needed. +# +config LIBFDT + bool + endmenu diff --git a/lib/Makefile b/lib/Makefile index 8c31a0c..2f2be5a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -130,6 +130,11 @@ obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o obj-$(CONFIG_STMP_DEVICE) += stmp_device.o +libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o +$(foreach file, $(libfdt_files), \ + $(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt)) +lib-$(CONFIG_LIBFDT) += $(libfdt_files) + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/fdt.c b/lib/fdt.c new file mode 100644 index 0000000..97f2006 --- /dev/null +++ b/lib/fdt.c @@ -0,0 +1,2 @@ +#include +#include "../scripts/dtc/libfdt/fdt.c" diff --git a/lib/fdt_ro.c b/lib/fdt_ro.c new file mode 100644 index 0000000..f73c04e --- /dev/null +++ b/lib/fdt_ro.c @@ -0,0 +1,2 @@ +#include +#include "../scripts/dtc/libfdt/fdt_ro.c" diff --git a/lib/fdt_rw.c b/lib/fdt_rw.c new file mode 100644 index 0000000..0c1f0f4 --- /dev/null +++ b/lib/fdt_rw.c @@ -0,0 +1,2 @@ +#include +#include "../scripts/dtc/libfdt/fdt_rw.c" diff --git a/lib/fdt_strerror.c b/lib/fdt_strerror.c new file mode 100644 index 0000000..8713e3f --- /dev/null +++ b/lib/fdt_strerror.c @@ -0,0 +1,2 @@ +#include +#include "../scripts/dtc/libfdt/fdt_strerror.c" diff --git a/lib/fdt_sw.c b/lib/fdt_sw.c new file mode 100644 index 0000000..9ac7e50 --- /dev/null +++ b/lib/fdt_sw.c @@ -0,0 +1,2 @@ +#include +#include "../scripts/dtc/libfdt/fdt_sw.c" diff --git a/lib/fdt_wip.c b/lib/fdt_wip.c new file mode 100644 index 0000000..45b3fc3 --- /dev/null +++ b/lib/fdt_wip.c @@ -0,0 +1,2 @@ +#include +#include "../scripts/dtc/libfdt/fdt_wip.c" -- cgit v0.10.2 From 736b1c9c957e38b80d2e36b2ed196fa1c07468bc Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:38 +0200 Subject: MIPS: Octeon: Add device tree source files. The two device tree files octeon_3xxx.dts and octeon_68xx.dts are trimmed by code in a subsequent patch to reflect the hardware actually present on the board. To this end several properties that are not part of the declared bindings are added to aid in trimming off unwanted nodes. Since the device tree and the code that trims it are bound into the kernel binary, these 'marker' properties never escape into the wild, and are purely an implementation detail of the kernel early boot process. This is done for backwards compatibility with existing boards (identified by a board type enumeration value by their bootloaders). New boards will always pass a device tree from the bootloader, the built-in trees are ignored in this case. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: Rob Herring Cc: linux-kernel@vger.kernel.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/3937/ Signed-off-by: Ralf Baechle diff --git a/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt new file mode 100644 index 0000000..93986a5 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt @@ -0,0 +1,30 @@ +* Compact Flash + +The Cavium Compact Flash device is connected to the Octeon Boot Bus, +and is thus a child of the Boot Bus device. It can read and write +industry standard compact flash devices. + +Properties: +- compatible: "cavium,ebt3000-compact-flash"; + + Compatibility with many Cavium evaluation boards. + +- reg: The base address of the the CF chip select banks. Depending on + the device configuration, there may be one or two banks. + +- cavium,bus-width: The width of the connection to the CF devices. Valid + values are 8 and 16. + +- cavium,true-ide: Optional, if present the CF connection is in True IDE mode. + +- cavium,dma-engine-handle: Optional, a phandle for the DMA Engine connected + to this device. + +Example: + compact-flash@5,0 { + compatible = "cavium,ebt3000-compact-flash"; + reg = <5 0 0x10000>, <6 0 0x10000>; + cavium,bus-width = <16>; + cavium,true-ide; + cavium,dma-engine-handle = <&dma0>; + }; diff --git a/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt b/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt new file mode 100644 index 0000000..9d6dcd3 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt @@ -0,0 +1,49 @@ +* General Purpose Input Output (GPIO) bus. + +Properties: +- compatible: "cavium,octeon-3860-gpio" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the GPIO unit's register bank. + +- gpio-controller: This is a GPIO controller. + +- #gpio-cells: Must be <2>. The first cell is the GPIO pin. + +- interrupt-controller: The GPIO controller is also an interrupt + controller, many of its pins may be configured as an interrupt + source. + +- #interrupt-cells: Must be <2>. The first cell is the GPIO pin + connected to the interrupt source. The second cell is the interrupt + triggering protocol and may have one of four values: + 1 - edge triggered on the rising edge. + 2 - edge triggered on the falling edge + 4 - level triggered active high. + 8 - level triggered active low. + +- interrupts: Interrupt routing for each pin. + +Example: + + gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pin connect to 16 consecutive CUI bits */ + interrupts = <0 16>, <0 17>, <0 18>, <0 19>, + <0 20>, <0 21>, <0 22>, <0 23>, + <0 24>, <0 25>, <0 26>, <0 27>, + <0 28>, <0 29>, <0 30>, <0 31>; + }; diff --git a/Documentation/devicetree/bindings/i2c/cavium-i2c.txt b/Documentation/devicetree/bindings/i2c/cavium-i2c.txt new file mode 100644 index 0000000..dced82e --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/cavium-i2c.txt @@ -0,0 +1,34 @@ +* Two Wire Serial Interface (TWSI) / I2C + +- compatible: "cavium,octeon-3860-twsi" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the TWSI/I2C bus controller register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. I2C addresses have no size component. + +- interrupts: A single interrupt specifier. + +- clock-frequency: The I2C bus clock rate in Hz. + +Example: + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <0 45>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + tmp@4c { + compatible = "ti,tmp421"; + reg = <0x4c>; + }; + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/bootbus.txt b/Documentation/devicetree/bindings/mips/cavium/bootbus.txt new file mode 100644 index 0000000..6581478 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/bootbus.txt @@ -0,0 +1,126 @@ +* Boot Bus + +The Octeon Boot Bus is a configurable parallel bus with 8 chip +selects. Each chip select is independently configurable. + +Properties: +- compatible: "cavium,octeon-3860-bootbus" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the Boot Bus' register bank. + +- #address-cells: Must be <2>. The first cell is the chip select + within the bootbus. The second cell is the offset from the chip select. + +- #size-cells: Must be <1>. + +- ranges: There must be one one triplet of (child-bus-address, + parent-bus-address, length) for each active chip select. If the + length element for any triplet is zero, the chip select is disabled, + making it inactive. + +The configuration parameters for each chip select are stored in child +nodes. + +Configuration Properties: +- compatible: "cavium,octeon-3860-bootbus-config" + +- cavium,cs-index: A single cell indicating the chip select that + corresponds to this configuration. + +- cavium,t-adr: A cell specifying the ADR timing (in nS). + +- cavium,t-ce: A cell specifying the CE timing (in nS). + +- cavium,t-oe: A cell specifying the OE timing (in nS). + +- cavium,t-we: A cell specifying the WE timing (in nS). + +- cavium,t-rd-hld: A cell specifying the RD_HLD timing (in nS). + +- cavium,t-wr-hld: A cell specifying the WR_HLD timing (in nS). + +- cavium,t-pause: A cell specifying the PAUSE timing (in nS). + +- cavium,t-wait: A cell specifying the WAIT timing (in nS). + +- cavium,t-page: A cell specifying the PAGE timing (in nS). + +- cavium,t-rd-dly: A cell specifying the RD_DLY timing (in nS). + +- cavium,pages: A cell specifying the PAGES parameter (0 = 8 bytes, 1 + = 2 bytes, 2 = 4 bytes, 3 = 8 bytes). + +- cavium,wait-mode: Optional. If present, wait mode (WAITM) is selected. + +- cavium,page-mode: Optional. If present, page mode (PAGEM) is selected. + +- cavium,bus-width: A cell specifying the WIDTH parameter (in bits) of + the bus for this chip select. + +- cavium,ale-mode: Optional. If present, ALE mode is selected. + +- cavium,sam-mode: Optional. If present, SAM mode is selected. + +- cavium,or-mode: Optional. If present, OR mode is selected. + +Example: + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0x0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0x0 0x1d020000 0x10000>, + <5 0 0x0 0x1d040000 0x10000>, + <6 0 0x0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <20>; + cavium,t-ce = <60>; + cavium,t-oe = <60>; + cavium,t-we = <45>; + cavium,t-rd-hld = <35>; + cavium,t-wr-hld = <45>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <35>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + . + . + . + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <270>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <70>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + . + . + . + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu.txt b/Documentation/devicetree/bindings/mips/cavium/ciu.txt new file mode 100644 index 0000000..2c2d074 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/ciu.txt @@ -0,0 +1,26 @@ +* Central Interrupt Unit + +Properties: +- compatible: "cavium,octeon-3860-ciu" + + Compatibility with all cn3XXX, cn5XXX and cn63XX SOCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: The base address of the CIU's register bank. + +- #interrupt-cells: Must be <2>. The first cell is the bank within + the CIU and may have a value of 0 or 1. The second cell is the bit + within the bank and may have a value between 0 and 63. + +Example: + interrupt-controller@1070000000000 { + compatible = "cavium,octeon-3860-ciu"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 1) + * 2) Bit within the register (0..63) + */ + #interrupt-cells = <2>; + reg = <0x10700 0x00000000 0x0 0x7000>; + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu2.txt b/Documentation/devicetree/bindings/mips/cavium/ciu2.txt new file mode 100644 index 0000000..0ec7ba8 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/ciu2.txt @@ -0,0 +1,27 @@ +* Central Interrupt Unit + +Properties: +- compatible: "cavium,octeon-6880-ciu2" + + Compatibility with 68XX SOCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: The base address of the CIU's register bank. + +- #interrupt-cells: Must be <2>. The first cell is the bank within + the CIU and may have a value between 0 and 63. The second cell is + the bit within the bank and may also have a value between 0 and 63. + +Example: + interrupt-controller@1070100000000 { + compatible = "cavium,octeon-6880-ciu2"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0..63) + * 2) Bit within the register (0..63) + */ + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x10701 0x00000000 0x0 0x4000000>; + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt new file mode 100644 index 0000000..cb4291e --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt @@ -0,0 +1,21 @@ +* DMA Engine. + +The Octeon DMA Engine transfers between the Boot Bus and main memory. +The DMA Engine will be refered to by phandle by any device that is +connected to it. + +Properties: +- compatible: "cavium,octeon-5750-bootbus-dma" + + Compatibility with all cn52XX, cn56XX and cn6XXX SOCs. + +- reg: The base address of the DMA Engine's register bank. + +- interrupts: A single interrupt specifier. + +Example: + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; diff --git a/Documentation/devicetree/bindings/mips/cavium/uctl.txt b/Documentation/devicetree/bindings/mips/cavium/uctl.txt new file mode 100644 index 0000000..aa66b9b --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/uctl.txt @@ -0,0 +1,46 @@ +* UCTL USB controller glue + +Properties: +- compatible: "cavium,octeon-6335-uctl" + + Compatibility with all cn6XXX SOCs. + +- reg: The base address of the UCTL register bank. + +- #address-cells: Must be <2>. + +- #size-cells: Must be <2>. + +- ranges: Empty to signify direct mapping of the children. + +- refclk-frequency: A single cell containing the reference clock + frequency in Hz. + +- refclk-type: A string describing the reference clock connection + either "crystal" or "external". + +Example: + uctl@118006f000000 { + compatible = "cavium,octeon-6335-uctl"; + reg = <0x11800 0x6f000000 0x0 0x100>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + /* 12MHz, 24MHz and 48MHz allowed */ + refclk-frequency = <24000000>; + /* Either "crystal" or "external" */ + refclk-type = "crystal"; + + ehci@16f0000000000 { + compatible = "cavium,octeon-6335-ehci","usb-ehci"; + reg = <0x16f00 0x00000000 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + ohci@16f0000000400 { + compatible = "cavium,octeon-6335-ohci","usb-ohci"; + reg = <0x16f00 0x00000400 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + }; diff --git a/Documentation/devicetree/bindings/net/cavium-mdio.txt b/Documentation/devicetree/bindings/net/cavium-mdio.txt new file mode 100644 index 0000000..04cb749 --- /dev/null +++ b/Documentation/devicetree/bindings/net/cavium-mdio.txt @@ -0,0 +1,27 @@ +* System Management Interface (SMI) / MDIO + +Properties: +- compatible: "cavium,octeon-3860-mdio" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the MDIO bus controller register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. MDIO addresses have no size component. + +Typically an MDIO bus might have several children. + +Example: + mdio@1180000001800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001800 0x0 0x40>; + + ethernet-phy@0 { + ... + reg = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/cavium-mix.txt b/Documentation/devicetree/bindings/net/cavium-mix.txt new file mode 100644 index 0000000..5da628d --- /dev/null +++ b/Documentation/devicetree/bindings/net/cavium-mix.txt @@ -0,0 +1,39 @@ +* MIX Ethernet controller. + +Properties: +- compatible: "cavium,octeon-5750-mix" + + Compatibility with all cn5XXX and cn6XXX SOCs populated with MIX + devices. + +- reg: The base addresses of four separate register banks. The first + bank contains the MIX registers. The second bank the corresponding + AGL registers. The third bank are the AGL registers shared by all + MIX devices present. The fourth bank is the AGL_PRT_CTL shared by + all MIX devices present. + +- cell-index: A single cell specifying which portion of the shared + register banks corresponds to this MIX device. + +- interrupts: Two interrupt specifiers. The first is the MIX + interrupt routing and the second the routing for the AGL interrupts. + +- mac-address: Optional, the MAC address to assign to the device. + +- local-mac-address: Optional, the MAC address to assign to the device + if mac-address is not specified. + +- phy-handle: Optional, a phandle for the PHY device connected to this device. + +Example: + ethernet@1070000100800 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */ + <0x11800 0xE0000800 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002008 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <1>; + interrupts = <1 18>, < 1 46>; + local-mac-address = [ 00 0f b7 10 63 54 ]; + phy-handle = <&phy1>; + }; diff --git a/Documentation/devicetree/bindings/net/cavium-pip.txt b/Documentation/devicetree/bindings/net/cavium-pip.txt new file mode 100644 index 0000000..d4c53ba --- /dev/null +++ b/Documentation/devicetree/bindings/net/cavium-pip.txt @@ -0,0 +1,98 @@ +* PIP Ethernet nexus. + +The PIP Ethernet nexus can control several data packet input/output +devices. The devices have a two level grouping scheme. There may be +several interfaces, and each interface may have several ports. These +ports might be an individual Ethernet PHY. + + +Properties for the PIP nexus: +- compatible: "cavium,octeon-3860-pip" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the PIP's register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. + +Properties for PIP interfaces which is a child the PIP nexus: +- compatible: "cavium,octeon-3860-pip-interface" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The interface number. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. + +Properties for PIP port which is a child the PIP interface: +- compatible: "cavium,octeon-3860-pip-port" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The port number within the interface group. + +- mac-address: Optional, the MAC address to assign to the device. + +- local-mac-address: Optional, the MAC address to assign to the device + if mac-address is not specified. + +- phy-handle: Optional, a phandle for the PHY device connected to this device. + +Example: + + pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 60 ]; + phy-handle = <&phy2>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 61 ]; + phy-handle = <&phy3>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 62 ]; + phy-handle = <&phy4>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 63 ]; + phy-handle = <&phy5>; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 64 ]; + phy-handle = <&phy6>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/serial/cavium-uart.txt b/Documentation/devicetree/bindings/serial/cavium-uart.txt new file mode 100644 index 0000000..87a6c37 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/cavium-uart.txt @@ -0,0 +1,19 @@ +* Universal Asynchronous Receiver/Transmitter (UART) + +- compatible: "cavium,octeon-3860-uart" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the UART register bank. + +- interrupts: A single interrupt specifier. + +- current-speed: Optional, the current bit rate in bits per second. + +Example: + uart1: serial@1180000000c00 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000c00 0x0 0x400>; + current-speed = <115200>; + interrupts = <0 35>; + }; diff --git a/arch/mips/cavium-octeon/.gitignore b/arch/mips/cavium-octeon/.gitignore new file mode 100644 index 0000000..39c96860 --- /dev/null +++ b/arch/mips/cavium-octeon/.gitignore @@ -0,0 +1,2 @@ +*.dtb.S +*.dtb diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile index 19eb043..1e37522 100644 --- a/arch/mips/cavium-octeon/Makefile +++ b/arch/mips/cavium-octeon/Makefile @@ -15,3 +15,16 @@ obj-y += octeon-memcpy.o obj-y += executive/ obj-$(CONFIG_SMP) += smp.o + +DTS_FILES = octeon_3xxx.dts octeon_68xx.dts +DTB_FILES = $(patsubst %.dts, %.dtb, $(DTS_FILES)) + +obj-y += $(patsubst %.dts, %.dtb.o, $(DTS_FILES)) + +$(obj)/%.dtb: $(src)/%.dts FORCE + $(call if_changed_dep,dtc) + +# Let's keep the .dtb files around in case we want to look at them. +.SECONDARY: $(addprefix $(obj)/, $(DTB_FILES)) + +clean-files += $(DTB_FILES) $(patsubst %.dtb, %.dtb.S, $(DTB_FILES)) diff --git a/arch/mips/cavium-octeon/octeon_3xxx.dts b/arch/mips/cavium-octeon/octeon_3xxx.dts new file mode 100644 index 0000000..f28b2d0 --- /dev/null +++ b/arch/mips/cavium-octeon/octeon_3xxx.dts @@ -0,0 +1,571 @@ +/dts-v1/; +/* + * OCTEON 3XXX, 5XXX, 63XX device tree skeleton. + * + * This device tree is pruned and patched by early boot code before + * use. Because of this, it contains a super-set of the available + * devices and properties. + */ +/ { + compatible = "cavium,octeon-3860"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&ciu>; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; /* Direct mapping */ + + ciu: interrupt-controller@1070000000000 { + compatible = "cavium,octeon-3860-ciu"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 1) + * 2) Bit within the register (0..63) + */ + #interrupt-cells = <2>; + reg = <0x10700 0x00000000 0x0 0x7000>; + }; + + gpio: gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pin connect to 16 consecutive CUI bits */ + interrupts = <0 16>, <0 17>, <0 18>, <0 19>, + <0 20>, <0 21>, <0 22>, <0 23>, + <0 24>, <0 25>, <0 26>, <0 27>, + <0 28>, <0 29>, <0 30>, <0 31>; + }; + + smi0: mdio@1180000001800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001800 0x0 0x40>; + + phy0: ethernet-phy@0 { + compatible = "marvell,88e1118"; + marvell,reg-init = + /* Fix rx and tx clock transition timing */ + <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */ + /* Adjust LED drive. */ + <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */ + /* irq, blink-activity, blink-link */ + <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */ + reg = <0>; + }; + + phy1: ethernet-phy@1 { + compatible = "marvell,88e1118"; + marvell,reg-init = + /* Fix rx and tx clock transition timing */ + <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */ + /* Adjust LED drive. */ + <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */ + /* irq, blink-activity, blink-link */ + <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */ + reg = <1>; + }; + + phy2: ethernet-phy@2 { + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy3: ethernet-phy@3 { + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy4: ethernet-phy@4 { + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy5: ethernet-phy@5 { + reg = <5>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + + phy6: ethernet-phy@6 { + reg = <6>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy7: ethernet-phy@7 { + reg = <7>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy8: ethernet-phy@8 { + reg = <8>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy9: ethernet-phy@9 { + reg = <9>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + smi1: mdio@1180000001900 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001900 0x0 0x40>; + + phy100: ethernet-phy@1 { + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy101: ethernet-phy@2 { + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy102: ethernet-phy@3 { + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy103: ethernet-phy@4 { + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + }; + + mix0: ethernet@1070000100000 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100000 0x0 0x100>, /* MIX */ + <0x11800 0xE0000000 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002000 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <0>; + interrupts = <0 62>, <1 46>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy0>; + }; + + mix1: ethernet@1070000100800 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */ + <0x11800 0xE0000800 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002008 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <1>; + interrupts = <1 18>, < 1 46>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy1>; + }; + + pip: pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy2>; + cavium,alt-phy-handle = <&phy100>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy3>; + cavium,alt-phy-handle = <&phy101>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy4>; + cavium,alt-phy-handle = <&phy102>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy5>; + cavium,alt-phy-handle = <&phy103>; + }; + ethernet@4 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x4>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@5 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x5>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@6 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x6>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@7 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x7>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@8 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x8>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@9 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x9>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@a { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xa>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@b { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xb>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@c { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xc>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@d { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xd>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@e { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xe>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@f { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0xf>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy6>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy7>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy8>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy9>; + }; + }; + }; + + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <0 45>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + tmp@4c { + compatible = "ti,tmp421"; + reg = <0x4c>; + }; + }; + + twsi1: i2c@1180000001200 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001200 0x0 0x200>; + interrupts = <0 59>; + clock-frequency = <100000>; + }; + + uart0: serial@1180000000800 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000800 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <0 34>; + }; + + uart1: serial@1180000000c00 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000c00 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <0 35>; + }; + + uart2: serial@1180000000400 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000400 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <1 16>; + }; + + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0x0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0x0 0x1d020000 0x10000>, + <5 0 0x0 0x1d040000 0x10000>, + <6 0 0x0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <20>; + cavium,t-ce = <60>; + cavium,t-oe = <60>; + cavium,t-we = <45>; + cavium,t-rd-hld = <35>; + cavium,t-wr-hld = <45>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <35>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@4 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <4>; + cavium,t-adr = <320>; + cavium,t-ce = <320>; + cavium,t-oe = <320>; + cavium,t-we = <320>; + cavium,t-rd-hld = <320>; + cavium,t-wr-hld = <320>; + cavium,t-pause = <320>; + cavium,t-wait = <320>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@5 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <5>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <125>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <30>; + cavium,t-pause = <0>; + cavium,t-wait = <30>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <16>; + }; + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <270>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <70>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + + flash0: nor@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + }; + + led0: led-display@4,0 { + compatible = "avago,hdsp-253x"; + reg = <4 0x20 0x20>, <4 0 0x20>; + }; + + cf0: compact-flash@5,0 { + compatible = "cavium,ebt3000-compact-flash"; + reg = <5 0 0x10000>, <6 0 0x10000>; + cavium,bus-width = <16>; + cavium,true-ide; + cavium,dma-engine-handle = <&dma0>; + }; + }; + + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; + dma1: dma-engine@1180000000108 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000108 0x0 0x8>; + interrupts = <0 63>; + }; + + uctl: uctl@118006f000000 { + compatible = "cavium,octeon-6335-uctl"; + reg = <0x11800 0x6f000000 0x0 0x100>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + /* 12MHz, 24MHz and 48MHz allowed */ + refclk-frequency = <12000000>; + /* Either "crystal" or "external" */ + refclk-type = "crystal"; + + ehci@16f0000000000 { + compatible = "cavium,octeon-6335-ehci","usb-ehci"; + reg = <0x16f00 0x00000000 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + ohci@16f0000000400 { + compatible = "cavium,octeon-6335-ohci","usb-ohci"; + reg = <0x16f00 0x00000400 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + }; + }; + + aliases { + mix0 = &mix0; + mix1 = &mix1; + pip = &pip; + smi0 = &smi0; + smi1 = &smi1; + twsi0 = &twsi0; + twsi1 = &twsi1; + uart0 = &uart0; + uart1 = &uart1; + uart2 = &uart2; + flash0 = &flash0; + cf0 = &cf0; + uctl = &uctl; + led0 = &led0; + }; + }; diff --git a/arch/mips/cavium-octeon/octeon_68xx.dts b/arch/mips/cavium-octeon/octeon_68xx.dts new file mode 100644 index 0000000..1839468 --- /dev/null +++ b/arch/mips/cavium-octeon/octeon_68xx.dts @@ -0,0 +1,625 @@ +/dts-v1/; +/* + * OCTEON 68XX device tree skeleton. + * + * This device tree is pruned and patched by early boot code before + * use. Because of this, it contains a super-set of the available + * devices and properties. + */ +/ { + compatible = "cavium,octeon-6880"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&ciu2>; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; /* Direct mapping */ + + ciu2: interrupt-controller@1070100000000 { + compatible = "cavium,octeon-6880-ciu2"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 7) + * 2) Bit within the register (0..63) + */ + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x10701 0x00000000 0x0 0x4000000>; + }; + + gpio: gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pins connect to 16 consecutive CUI bits */ + interrupts = <7 0>, <7 1>, <7 2>, <7 3>, + <7 4>, <7 5>, <7 6>, <7 7>, + <7 8>, <7 9>, <7 10>, <7 11>, + <7 12>, <7 13>, <7 14>, <7 15>; + }; + + smi0: mdio@1180000003800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00003800 0x0 0x40>; + + phy0: ethernet-phy@6 { + compatible = "marvell,88e1118"; + marvell,reg-init = + /* Fix rx and tx clock transition timing */ + <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */ + /* Adjust LED drive. */ + <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */ + /* irq, blink-activity, blink-link */ + <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */ + reg = <6>; + }; + + phy1: ethernet-phy@1 { + cavium,qlm-trim = "4,sgmii"; + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy2: ethernet-phy@2 { + cavium,qlm-trim = "4,sgmii"; + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy3: ethernet-phy@3 { + cavium,qlm-trim = "4,sgmii"; + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy4: ethernet-phy@4 { + cavium,qlm-trim = "4,sgmii"; + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + smi1: mdio@1180000003880 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00003880 0x0 0x40>; + + phy41: ethernet-phy@1 { + cavium,qlm-trim = "0,sgmii"; + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy42: ethernet-phy@2 { + cavium,qlm-trim = "0,sgmii"; + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy43: ethernet-phy@3 { + cavium,qlm-trim = "0,sgmii"; + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy44: ethernet-phy@4 { + cavium,qlm-trim = "0,sgmii"; + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + smi2: mdio@1180000003900 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00003900 0x0 0x40>; + + phy21: ethernet-phy@1 { + cavium,qlm-trim = "2,sgmii"; + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy22: ethernet-phy@2 { + cavium,qlm-trim = "2,sgmii"; + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy23: ethernet-phy@3 { + cavium,qlm-trim = "2,sgmii"; + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy24: ethernet-phy@4 { + cavium,qlm-trim = "2,sgmii"; + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + smi3: mdio@1180000003980 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00003980 0x0 0x40>; + + phy11: ethernet-phy@1 { + cavium,qlm-trim = "3,sgmii"; + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy12: ethernet-phy@2 { + cavium,qlm-trim = "3,sgmii"; + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy13: ethernet-phy@3 { + cavium,qlm-trim = "3,sgmii"; + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + phy14: ethernet-phy@4 { + cavium,qlm-trim = "3,sgmii"; + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + }; + }; + + mix0: ethernet@1070000100000 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100000 0x0 0x100>, /* MIX */ + <0x11800 0xE0000000 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002000 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <0>; + interrupts = <6 40>, <6 32>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy0>; + }; + + pip: pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@4 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy1>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy2>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy3>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy4>; + }; + }; + + interface@3 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy11>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy12>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy13>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy14>; + }; + }; + + interface@2 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy21>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy22>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy23>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy24>; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + }; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy41>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy42>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy43>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-handle = <&phy44>; + }; + }; + }; + + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <3 32>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + tmp@4c { + compatible = "ti,tmp421"; + reg = <0x4c>; + }; + }; + + twsi1: i2c@1180000001200 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001200 0x0 0x200>; + interrupts = <3 33>; + clock-frequency = <100000>; + }; + + uart0: serial@1180000000800 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000800 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <3 36>; + }; + + uart1: serial@1180000000c00 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000c00 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <3 37>; + }; + + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0 0x1d020000 0x10000>, + <5 0 0 0x1d040000 0x10000>, + <6 0 0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <10>; + cavium,t-ce = <50>; + cavium,t-oe = <50>; + cavium,t-we = <35>; + cavium,t-rd-hld = <25>; + cavium,t-wr-hld = <35>; + cavium,t-pause = <0>; + cavium,t-wait = <300>; + cavium,t-page = <25>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@4 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <4>; + cavium,t-adr = <320>; + cavium,t-ce = <320>; + cavium,t-oe = <320>; + cavium,t-we = <320>; + cavium,t-rd-hld = <320>; + cavium,t-wr-hld = <320>; + cavium,t-pause = <320>; + cavium,t-wait = <320>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@5 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <5>; + cavium,t-adr = <0>; + cavium,t-ce = <300>; + cavium,t-oe = <125>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <300>; + cavium,t-pause = <0>; + cavium,t-wait = <300>; + cavium,t-page = <310>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <16>; + }; + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <0>; + cavium,t-ce = <30>; + cavium,t-oe = <125>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <30>; + cavium,t-pause = <0>; + cavium,t-wait = <30>; + cavium,t-page = <310>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + + flash0: nor@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0 0x200000>; + read-only; + }; + partition@200000 { + label = "kernel"; + reg = <0x200000 0x200000>; + }; + partition@400000 { + label = "cramfs"; + reg = <0x400000 0x3fe000>; + }; + partition@7fe000 { + label = "environment"; + reg = <0x7fe000 0x2000>; + read-only; + }; + }; + + led0: led-display@4,0 { + compatible = "avago,hdsp-253x"; + reg = <4 0x20 0x20>, <4 0 0x20>; + }; + + compact-flash@5,0 { + compatible = "cavium,ebt3000-compact-flash"; + reg = <5 0 0x10000>, <6 0 0x10000>; + cavium,bus-width = <16>; + cavium,true-ide; + cavium,dma-engine-handle = <&dma0>; + }; + }; + + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; + dma1: dma-engine@1180000000108 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000108 0x0 0x8>; + interrupts = <0 63>; + }; + + uctl: uctl@118006f000000 { + compatible = "cavium,octeon-6335-uctl"; + reg = <0x11800 0x6f000000 0x0 0x100>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + /* 12MHz, 24MHz and 48MHz allowed */ + refclk-frequency = <12000000>; + /* Either "crystal" or "external" */ + refclk-type = "crystal"; + + ehci@16f0000000000 { + compatible = "cavium,octeon-6335-ehci","usb-ehci"; + reg = <0x16f00 0x00000000 0x0 0x100>; + interrupts = <3 44>; + big-endian-regs; + }; + ohci@16f0000000400 { + compatible = "cavium,octeon-6335-ohci","usb-ohci"; + reg = <0x16f00 0x00000400 0x0 0x100>; + interrupts = <3 44>; + big-endian-regs; + }; + }; + }; + + aliases { + mix0 = &mix0; + pip = &pip; + smi0 = &smi0; + smi1 = &smi1; + smi2 = &smi2; + smi3 = &smi3; + twsi0 = &twsi0; + twsi1 = &twsi1; + uart0 = &uart0; + uart1 = &uart1; + uctl = &uctl; + led0 = &led0; + flash0 = &flash0; + }; + }; -- cgit v0.10.2 From b01da9f130adbf69cfbad2a65f1327f1382bf4ae Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:38 +0200 Subject: MIPS: Prune some target specific code out of prom.c This code is not common enough to be in a shared file. It is also not used by any existing boards, so just remove it. [ralf@linux-mips.org: Dropped removal of irq_create_of_mapping which was already removed by abd2363f6a5f1030b935e0bdc15cf917313b3b10 [irq_domain/mips: Allow irq_domain on MIPS]. Moved device_tree_init() and dependencies to its sole user, the XLP code.] Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: grant.likely@secretlab.ca Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2946/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/prom.h b/arch/mips/include/asm/prom.h index 7206d44..8808bf5 100644 --- a/arch/mips/include/asm/prom.h +++ b/arch/mips/include/asm/prom.h @@ -20,9 +20,6 @@ extern int early_init_dt_scan_memory_arch(unsigned long node, const char *uname, int depth, void *data); -extern int reserve_mem_mach(unsigned long addr, unsigned long size); -extern void free_mem_mach(unsigned long addr, unsigned long size); - extern void device_tree_init(void); static inline unsigned long pci_address_to_pio(phys_addr_t address) diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index f11b2bb..028f6f8 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -35,16 +35,6 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) return add_memory_region(base, size, BOOT_MEM_RAM); } -int __init reserve_mem_mach(unsigned long addr, unsigned long size) -{ - return reserve_bootmem(addr, size, BOOTMEM_DEFAULT); -} - -void __init free_mem_mach(unsigned long addr, unsigned long size) -{ - return free_bootmem(addr, size); -} - void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)); @@ -77,25 +67,6 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_memory_arch, NULL); } -void __init device_tree_init(void) -{ - unsigned long base, size; - - if (!initial_boot_params) - return; - - base = virt_to_phys((void *)initial_boot_params); - size = be32_to_cpu(initial_boot_params->totalsize); - - /* Before we do anything, lets reserve the dt blob */ - reserve_mem_mach(base, size); - - unflatten_device_tree(); - - /* free the space reserved for the dt blob */ - free_mem_mach(base, size); -} - void __init __dt_setup_arch(struct boot_param_header *bph) { if (be32_to_cpu(bph->magic) != OF_DT_HEADER) { diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile index b93ed83..9007ef0 100644 --- a/arch/mips/netlogic/xlp/Makefile +++ b/arch/mips/netlogic/xlp/Makefile @@ -1,2 +1,3 @@ obj-y += setup.o platform.o nlm_hal.o +obj-$(CONFIG_OF) += of.o obj-$(CONFIG_SMP) += wakeup.o diff --git a/arch/mips/netlogic/xlp/of.c b/arch/mips/netlogic/xlp/of.c new file mode 100644 index 0000000..8e3921c --- /dev/null +++ b/arch/mips/netlogic/xlp/of.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include + +static int __init reserve_mem_mach(unsigned long addr, unsigned long size) +{ + return reserve_bootmem(addr, size, BOOTMEM_DEFAULT); +} + +void __init free_mem_mach(unsigned long addr, unsigned long size) +{ + return free_bootmem(addr, size); +} + +void __init device_tree_init(void) +{ + unsigned long base, size; + + if (!initial_boot_params) + return; + + base = virt_to_phys((void *)initial_boot_params); + size = be32_to_cpu(initial_boot_params->totalsize); + + /* Before we do anything, lets reserve the dt blob */ + reserve_mem_mach(base, size); + + unflatten_device_tree(); + + /* free the space reserved for the dt blob */ + free_mem_mach(base, size); +} -- cgit v0.10.2 From 7ed1815296498e9d1bfa1f13e94b743364b14caf Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:38 +0200 Subject: MIPS: Octeon: Initialize and fixup device tree. If a compiled in device tree template is used, trim out unwanted parts based on legacy platform probing. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: Rob Herring Cc: linux-kernel@vger.kernel.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/3935/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b3e10fd..00045d6 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1432,6 +1432,8 @@ config CPU_CAVIUM_OCTEON select WEAK_ORDERING select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_HUGEPAGES + select LIBFDT + select USE_OF help The Cavium Octeon processor is a highly integrated chip containing many ethernet hardware widgets for networking tasks. The processor diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile index 1e37522..bc96e29 100644 --- a/arch/mips/cavium-octeon/Makefile +++ b/arch/mips/cavium-octeon/Makefile @@ -9,6 +9,9 @@ # Copyright (C) 2005-2009 Cavium Networks # +CFLAGS_octeon-platform.o = -I$(src)/../../../scripts/dtc/libfdt +CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt + obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o obj-y += dma-octeon.o flash_setup.o obj-y += octeon-memcpy.o diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index cd61d72..2754bc2 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2004-2010 Cavium Networks + * Copyright (C) 2004-2011 Cavium Networks * Copyright (C) 2008 Wind River Systems */ @@ -13,10 +13,16 @@ #include #include #include +#include #include +#include +#include +#include #include #include +#include +#include static struct octeon_cf_data octeon_cf_data; @@ -440,6 +446,521 @@ device_initcall(octeon_ohci_device_init); #endif /* CONFIG_USB */ +static struct of_device_id __initdata octeon_ids[] = { + { .compatible = "simple-bus", }, + { .compatible = "cavium,octeon-6335-uctl", }, + { .compatible = "cavium,octeon-3860-bootbus", }, + { .compatible = "cavium,mdio-mux", }, + { .compatible = "gpio-leds", }, + {}, +}; + +static bool __init octeon_has_88e1145(void) +{ + return !OCTEON_IS_MODEL(OCTEON_CN52XX) && + !OCTEON_IS_MODEL(OCTEON_CN6XXX) && + !OCTEON_IS_MODEL(OCTEON_CN56XX); +} + +static void __init octeon_fdt_set_phy(int eth, int phy_addr) +{ + const __be32 *phy_handle; + const __be32 *alt_phy_handle; + const __be32 *reg; + u32 phandle; + int phy; + int alt_phy; + const char *p; + int current_len; + char new_name[20]; + + phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL); + if (!phy_handle) + return; + + phandle = be32_to_cpup(phy_handle); + phy = fdt_node_offset_by_phandle(initial_boot_params, phandle); + + alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); + if (alt_phy_handle) { + u32 alt_phandle = be32_to_cpup(alt_phy_handle); + alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle); + } else { + alt_phy = -1; + } + + if (phy_addr < 0 || phy < 0) { + /* Delete the PHY things */ + fdt_nop_property(initial_boot_params, eth, "phy-handle"); + /* This one may fail */ + fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle"); + if (phy >= 0) + fdt_nop_node(initial_boot_params, phy); + if (alt_phy >= 0) + fdt_nop_node(initial_boot_params, alt_phy); + return; + } + + if (phy_addr >= 256 && alt_phy > 0) { + const struct fdt_property *phy_prop; + struct fdt_property *alt_prop; + u32 phy_handle_name; + + /* Use the alt phy node instead.*/ + phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL); + phy_handle_name = phy_prop->nameoff; + fdt_nop_node(initial_boot_params, phy); + fdt_nop_property(initial_boot_params, eth, "phy-handle"); + alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); + alt_prop->nameoff = phy_handle_name; + phy = alt_phy; + } + + phy_addr &= 0xff; + + if (octeon_has_88e1145()) { + fdt_nop_property(initial_boot_params, phy, "marvell,reg-init"); + memset(new_name, 0, sizeof(new_name)); + strcpy(new_name, "marvell,88e1145"); + p = fdt_getprop(initial_boot_params, phy, "compatible", + ¤t_len); + if (p && current_len >= strlen(new_name)) + fdt_setprop_inplace(initial_boot_params, phy, + "compatible", new_name, current_len); + } + + reg = fdt_getprop(initial_boot_params, phy, "reg", NULL); + if (phy_addr == be32_to_cpup(reg)) + return; + + fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr); + + snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr); + + p = fdt_get_name(initial_boot_params, phy, ¤t_len); + if (p && current_len == strlen(new_name)) + fdt_set_name(initial_boot_params, phy, new_name); + else + pr_err("Error: could not rename ethernet phy: <%s>", p); +} + +static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac) +{ + u8 new_mac[6]; + u64 mac = *pmac; + int r; + + new_mac[0] = (mac >> 40) & 0xff; + new_mac[1] = (mac >> 32) & 0xff; + new_mac[2] = (mac >> 24) & 0xff; + new_mac[3] = (mac >> 16) & 0xff; + new_mac[4] = (mac >> 8) & 0xff; + new_mac[5] = mac & 0xff; + + r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address", + new_mac, sizeof(new_mac)); + + if (r) { + pr_err("Setting \"local-mac-address\" failed %d", r); + return; + } + *pmac = mac + 1; +} + +static void __init octeon_fdt_rm_ethernet(int node) +{ + const __be32 *phy_handle; + + phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL); + if (phy_handle) { + u32 ph = be32_to_cpup(phy_handle); + int p = fdt_node_offset_by_phandle(initial_boot_params, ph); + if (p >= 0) + fdt_nop_node(initial_boot_params, p); + } + fdt_nop_node(initial_boot_params, node); +} + +static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pmac) +{ + char name_buffer[20]; + int eth; + int phy_addr; + int ipd_port; + + snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p); + eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer); + if (eth < 0) + return; + if (p > max) { + pr_debug("Deleting port %x:%x\n", i, p); + octeon_fdt_rm_ethernet(eth); + return; + } + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + ipd_port = (0x100 * i) + (0x10 * p) + 0x800; + else + ipd_port = 16 * i + p; + + phy_addr = cvmx_helper_board_get_mii_address(ipd_port); + octeon_fdt_set_phy(eth, phy_addr); + octeon_fdt_set_mac_addr(eth, pmac); +} + +static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac) +{ + char name_buffer[20]; + int iface; + int p; + int count; + + count = cvmx_helper_interface_enumerate(idx); + + snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx); + iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer); + if (iface < 0) + return; + + for (p = 0; p < 16; p++) + octeon_fdt_pip_port(iface, idx, p, count - 1, pmac); +} + +int __init octeon_prune_device_tree(void) +{ + int i, max_port, uart_mask; + const char *pip_path; + const char *alias_prop; + char name_buffer[20]; + int aliases; + u64 mac_addr_base; + + if (fdt_check_header(initial_boot_params)) + panic("Corrupt Device Tree."); + + aliases = fdt_path_offset(initial_boot_params, "/aliases"); + if (aliases < 0) { + pr_err("Error: No /aliases node in device tree."); + return -EINVAL; + } + + + mac_addr_base = + ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | + ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | + ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | + ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | + ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | + (octeon_bootinfo->mac_addr_base[5] & 0xffull); + + if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) + max_port = 2; + else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) + max_port = 1; + else + max_port = 0; + + if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E) + max_port = 0; + + for (i = 0; i < 2; i++) { + int mgmt; + snprintf(name_buffer, sizeof(name_buffer), + "mix%d", i); + alias_prop = fdt_getprop(initial_boot_params, aliases, + name_buffer, NULL); + if (alias_prop) { + mgmt = fdt_path_offset(initial_boot_params, alias_prop); + if (mgmt < 0) + continue; + if (i >= max_port) { + pr_debug("Deleting mix%d\n", i); + octeon_fdt_rm_ethernet(mgmt); + fdt_nop_property(initial_boot_params, aliases, + name_buffer); + } else { + int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i); + octeon_fdt_set_phy(mgmt, phy_addr); + octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); + } + } + } + + pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL); + if (pip_path) { + int pip = fdt_path_offset(initial_boot_params, pip_path); + if (pip >= 0) + for (i = 0; i <= 4; i++) + octeon_fdt_pip_iface(pip, i, &mac_addr_base); + } + + /* I2C */ + if (OCTEON_IS_MODEL(OCTEON_CN52XX) || + OCTEON_IS_MODEL(OCTEON_CN63XX) || + OCTEON_IS_MODEL(OCTEON_CN68XX) || + OCTEON_IS_MODEL(OCTEON_CN56XX)) + max_port = 2; + else + max_port = 1; + + for (i = 0; i < 2; i++) { + int i2c; + snprintf(name_buffer, sizeof(name_buffer), + "twsi%d", i); + alias_prop = fdt_getprop(initial_boot_params, aliases, + name_buffer, NULL); + + if (alias_prop) { + i2c = fdt_path_offset(initial_boot_params, alias_prop); + if (i2c < 0) + continue; + if (i >= max_port) { + pr_debug("Deleting twsi%d\n", i); + fdt_nop_node(initial_boot_params, i2c); + fdt_nop_property(initial_boot_params, aliases, + name_buffer); + } + } + } + + /* SMI/MDIO */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + max_port = 4; + else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || + OCTEON_IS_MODEL(OCTEON_CN63XX) || + OCTEON_IS_MODEL(OCTEON_CN56XX)) + max_port = 2; + else + max_port = 1; + + for (i = 0; i < 2; i++) { + int i2c; + snprintf(name_buffer, sizeof(name_buffer), + "smi%d", i); + alias_prop = fdt_getprop(initial_boot_params, aliases, + name_buffer, NULL); + + if (alias_prop) { + i2c = fdt_path_offset(initial_boot_params, alias_prop); + if (i2c < 0) + continue; + if (i >= max_port) { + pr_debug("Deleting smi%d\n", i); + fdt_nop_node(initial_boot_params, i2c); + fdt_nop_property(initial_boot_params, aliases, + name_buffer); + } + } + } + + /* Serial */ + uart_mask = 3; + + /* Right now CN52XX is the only chip with a third uart */ + if (OCTEON_IS_MODEL(OCTEON_CN52XX)) + uart_mask |= 4; /* uart2 */ + + for (i = 0; i < 3; i++) { + int uart; + snprintf(name_buffer, sizeof(name_buffer), + "uart%d", i); + alias_prop = fdt_getprop(initial_boot_params, aliases, + name_buffer, NULL); + + if (alias_prop) { + uart = fdt_path_offset(initial_boot_params, alias_prop); + if (uart_mask & (1 << i)) + continue; + pr_debug("Deleting uart%d\n", i); + fdt_nop_node(initial_boot_params, uart); + fdt_nop_property(initial_boot_params, aliases, + name_buffer); + } + } + + /* Compact Flash */ + alias_prop = fdt_getprop(initial_boot_params, aliases, + "cf0", NULL); + if (alias_prop) { + union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; + unsigned long base_ptr, region_base, region_size; + unsigned long region1_base = 0; + unsigned long region1_size = 0; + int cs, bootbus; + bool is_16bit = false; + bool is_true_ide = false; + __be32 new_reg[6]; + __be32 *ranges; + int len; + + int cf = fdt_path_offset(initial_boot_params, alias_prop); + base_ptr = 0; + if (octeon_bootinfo->major_version == 1 + && octeon_bootinfo->minor_version >= 1) { + if (octeon_bootinfo->compact_flash_common_base_addr) + base_ptr = octeon_bootinfo->compact_flash_common_base_addr; + } else { + base_ptr = 0x1d000800; + } + + if (!base_ptr) + goto no_cf; + + /* Find CS0 region. */ + for (cs = 0; cs < 8; cs++) { + mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); + region_base = mio_boot_reg_cfg.s.base << 16; + region_size = (mio_boot_reg_cfg.s.size + 1) << 16; + if (mio_boot_reg_cfg.s.en && base_ptr >= region_base + && base_ptr < region_base + region_size) { + is_16bit = mio_boot_reg_cfg.s.width; + break; + } + } + if (cs >= 7) { + /* cs and cs + 1 are CS0 and CS1, both must be less than 8. */ + goto no_cf; + } + + if (!(base_ptr & 0xfffful)) { + /* + * Boot loader signals availability of DMA (true_ide + * mode) by setting low order bits of base_ptr to + * zero. + */ + + /* Asume that CS1 immediately follows. */ + mio_boot_reg_cfg.u64 = + cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1)); + region1_base = mio_boot_reg_cfg.s.base << 16; + region1_size = (mio_boot_reg_cfg.s.size + 1) << 16; + if (!mio_boot_reg_cfg.s.en) + goto no_cf; + is_true_ide = true; + + } else { + fdt_nop_property(initial_boot_params, cf, "cavium,true-ide"); + fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle"); + if (!is_16bit) { + __be32 width = cpu_to_be32(8); + fdt_setprop_inplace(initial_boot_params, cf, + "cavium,bus-width", &width, sizeof(width)); + } + } + new_reg[0] = cpu_to_be32(cs); + new_reg[1] = cpu_to_be32(0); + new_reg[2] = cpu_to_be32(0x10000); + new_reg[3] = cpu_to_be32(cs + 1); + new_reg[4] = cpu_to_be32(0); + new_reg[5] = cpu_to_be32(0x10000); + fdt_setprop_inplace(initial_boot_params, cf, + "reg", new_reg, sizeof(new_reg)); + + bootbus = fdt_parent_offset(initial_boot_params, cf); + if (bootbus < 0) + goto no_cf; + ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); + if (!ranges || len < (5 * 8 * sizeof(__be32))) + goto no_cf; + + ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); + ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); + ranges[(cs * 5) + 4] = cpu_to_be32(region_size); + if (is_true_ide) { + cs++; + ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32); + ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff); + ranges[(cs * 5) + 4] = cpu_to_be32(region1_size); + } + goto end_cf; +no_cf: + fdt_nop_node(initial_boot_params, cf); + +end_cf: + ; + } + + /* 8 char LED */ + alias_prop = fdt_getprop(initial_boot_params, aliases, + "led0", NULL); + if (alias_prop) { + union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; + unsigned long base_ptr, region_base, region_size; + int cs, bootbus; + __be32 new_reg[6]; + __be32 *ranges; + int len; + int led = fdt_path_offset(initial_boot_params, alias_prop); + + base_ptr = octeon_bootinfo->led_display_base_addr; + if (base_ptr == 0) + goto no_led; + /* Find CS0 region. */ + for (cs = 0; cs < 8; cs++) { + mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); + region_base = mio_boot_reg_cfg.s.base << 16; + region_size = (mio_boot_reg_cfg.s.size + 1) << 16; + if (mio_boot_reg_cfg.s.en && base_ptr >= region_base + && base_ptr < region_base + region_size) + break; + } + + if (cs > 7) + goto no_led; + + new_reg[0] = cpu_to_be32(cs); + new_reg[1] = cpu_to_be32(0x20); + new_reg[2] = cpu_to_be32(0x20); + new_reg[3] = cpu_to_be32(cs); + new_reg[4] = cpu_to_be32(0); + new_reg[5] = cpu_to_be32(0x20); + fdt_setprop_inplace(initial_boot_params, led, + "reg", new_reg, sizeof(new_reg)); + + bootbus = fdt_parent_offset(initial_boot_params, led); + if (bootbus < 0) + goto no_led; + ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); + if (!ranges || len < (5 * 8 * sizeof(__be32))) + goto no_led; + + ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); + ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); + ranges[(cs * 5) + 4] = cpu_to_be32(region_size); + goto end_led; + +no_led: + fdt_nop_node(initial_boot_params, led); +end_led: + ; + } + + /* OHCI/UHCI USB */ + alias_prop = fdt_getprop(initial_boot_params, aliases, + "uctl", NULL); + if (alias_prop) { + int uctl = fdt_path_offset(initial_boot_params, alias_prop); + + if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) || + octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) { + pr_debug("Deleting uctl\n"); + fdt_nop_node(initial_boot_params, uctl); + fdt_nop_property(initial_boot_params, aliases, "uctl"); + } else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E || + octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) { + /* Missing "refclk-type" defaults to crystal. */ + fdt_nop_property(initial_boot_params, uctl, "refclk-type"); + } + } + + return 0; +} + +static int __init octeon_publish_devices(void) +{ + return of_platform_bus_probe(NULL, octeon_ids, NULL); +} +device_initcall(octeon_publish_devices); + MODULE_AUTHOR("David Daney "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Platform driver for Octeon SOC"); diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 260dc24..919b0fb 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -775,3 +777,46 @@ void prom_free_prom_memory(void) } #endif } + +int octeon_prune_device_tree(void); + +extern const char __dtb_octeon_3xxx_begin; +extern const char __dtb_octeon_3xxx_end; +extern const char __dtb_octeon_68xx_begin; +extern const char __dtb_octeon_68xx_end; +void __init device_tree_init(void) +{ + int dt_size; + struct boot_param_header *fdt; + bool do_prune; + + if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) { + fdt = phys_to_virt(octeon_bootinfo->fdt_addr); + if (fdt_check_header(fdt)) + panic("Corrupt Device Tree passed to kernel."); + dt_size = be32_to_cpu(fdt->totalsize); + do_prune = false; + } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + fdt = (struct boot_param_header *)&__dtb_octeon_68xx_begin; + dt_size = &__dtb_octeon_68xx_end - &__dtb_octeon_68xx_begin; + do_prune = true; + } else { + fdt = (struct boot_param_header *)&__dtb_octeon_3xxx_begin; + dt_size = &__dtb_octeon_3xxx_end - &__dtb_octeon_3xxx_begin; + do_prune = true; + } + + /* Copy the default tree from init memory. */ + initial_boot_params = early_init_dt_alloc_memory_arch(dt_size, 8); + if (initial_boot_params == NULL) + panic("Could not allocate initial_boot_params\n"); + memcpy(initial_boot_params, fdt, dt_size); + + if (do_prune) { + octeon_prune_device_tree(); + pr_info("Using internal Device Tree.\n"); + } else { + pr_info("Using passed Device Tree.\n"); + } + unflatten_device_tree(); +} -- cgit v0.10.2 From a0c16582b5b50792b0fd3e07d23c537936fafcb7 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:39 +0200 Subject: MIPS: Octeon: Setup irq_domains for interrupts. Create two domains. One for the GPIO lines, and the other for on-chip sources. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: Rob Herring Cc: linux-kernel@vger.kernel.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/3936/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index fac22a8..52610ce 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -3,14 +3,17 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2004-2008, 2009, 2010, 2011 Cavium Networks + * Copyright (C) 2004-2012 Cavium, Inc. */ #include +#include #include #include +#include #include #include +#include #include @@ -42,9 +45,9 @@ struct octeon_core_chip_data { static struct octeon_core_chip_data octeon_irq_core_chip_data[MIPS_CORE_IRQ_LINES]; -static void __init octeon_irq_set_ciu_mapping(int irq, int line, int bit, - struct irq_chip *chip, - irq_flow_handler_t handler) +static void octeon_irq_set_ciu_mapping(int irq, int line, int bit, + struct irq_chip *chip, + irq_flow_handler_t handler) { union octeon_ciu_chip_data cd; @@ -847,6 +850,178 @@ static struct irq_chip octeon_irq_chip_ciu_wd = { .irq_mask = octeon_irq_dummy_mask, }; +static bool octeon_irq_ciu_is_edge(unsigned int line, unsigned int bit) +{ + bool edge = false; + + if (line == 0) + switch (bit) { + case 48 ... 49: /* GMX DRP */ + case 50: /* IPD_DRP */ + case 52 ... 55: /* Timers */ + case 58: /* MPI */ + edge = true; + break; + default: + break; + } + else /* line == 1 */ + switch (bit) { + case 47: /* PTP */ + edge = true; + break; + default: + break; + } + return edge; +} + +struct octeon_irq_gpio_domain_data { + unsigned int base_hwirq; +}; + +static int octeon_irq_gpio_xlat(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + unsigned int type; + unsigned int pin; + unsigned int trigger; + struct octeon_irq_gpio_domain_data *gpiod; + + if (d->of_node != node) + return -EINVAL; + + if (intsize < 2) + return -EINVAL; + + pin = intspec[0]; + if (pin >= 16) + return -EINVAL; + + trigger = intspec[1]; + + switch (trigger) { + case 1: + type = IRQ_TYPE_EDGE_RISING; + break; + case 2: + type = IRQ_TYPE_EDGE_FALLING; + break; + case 4: + type = IRQ_TYPE_LEVEL_HIGH; + break; + case 8: + type = IRQ_TYPE_LEVEL_LOW; + break; + default: + pr_err("Error: (%s) Invalid irq trigger specification: %x\n", + node->name, + trigger); + type = IRQ_TYPE_LEVEL_LOW; + break; + } + *out_type = type; + gpiod = d->host_data; + *out_hwirq = gpiod->base_hwirq + pin; + + return 0; +} + +static int octeon_irq_ciu_xlat(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + unsigned int ciu, bit; + + ciu = intspec[0]; + bit = intspec[1]; + + if (ciu > 1 || bit > 63) + return -EINVAL; + + /* These are the GPIO lines */ + if (ciu == 0 && bit >= 16 && bit < 32) + return -EINVAL; + + *out_hwirq = (ciu << 6) | bit; + *out_type = 0; + + return 0; +} + +static struct irq_chip *octeon_irq_ciu_chip; +static struct irq_chip *octeon_irq_gpio_chip; + +static bool octeon_irq_virq_in_range(unsigned int virq) +{ + /* We cannot let it overflow the mapping array. */ + if (virq < (1ul << 8 * sizeof(octeon_irq_ciu_to_irq[0][0]))) + return true; + + WARN_ONCE(true, "virq out of range %u.\n", virq); + return false; +} + +static int octeon_irq_ciu_map(struct irq_domain *d, + unsigned int virq, irq_hw_number_t hw) +{ + unsigned int line = hw >> 6; + unsigned int bit = hw & 63; + + if (!octeon_irq_virq_in_range(virq)) + return -EINVAL; + + if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0) + return -EINVAL; + + if (octeon_irq_ciu_is_edge(line, bit)) + octeon_irq_set_ciu_mapping(virq, line, bit, + octeon_irq_ciu_chip, + handle_edge_irq); + else + octeon_irq_set_ciu_mapping(virq, line, bit, + octeon_irq_ciu_chip, + handle_level_irq); + + return 0; +} + +static int octeon_irq_gpio_map(struct irq_domain *d, + unsigned int virq, irq_hw_number_t hw) +{ + unsigned int line = hw >> 6; + unsigned int bit = hw & 63; + + if (!octeon_irq_virq_in_range(virq)) + return -EINVAL; + + if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0) + return -EINVAL; + + octeon_irq_set_ciu_mapping(virq, line, bit, + octeon_irq_gpio_chip, + octeon_irq_handle_gpio); + + return 0; +} + +static struct irq_domain_ops octeon_irq_domain_ciu_ops = { + .map = octeon_irq_ciu_map, + .xlate = octeon_irq_ciu_xlat, +}; + +static struct irq_domain_ops octeon_irq_domain_gpio_ops = { + .map = octeon_irq_gpio_map, + .xlate = octeon_irq_gpio_xlat, +}; + static void octeon_irq_ip2_v1(void) { const unsigned long core_id = cvmx_get_core_num(); @@ -972,7 +1147,8 @@ static void __init octeon_irq_init_ciu(void) struct irq_chip *chip; struct irq_chip *chip_mbox; struct irq_chip *chip_wd; - struct irq_chip *chip_gpio; + struct device_node *gpio_node; + struct device_node *ciu_node; octeon_irq_init_ciu_percpu(); octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu; @@ -986,15 +1162,16 @@ static void __init octeon_irq_init_ciu(void) chip = &octeon_irq_chip_ciu_v2; chip_mbox = &octeon_irq_chip_ciu_mbox_v2; chip_wd = &octeon_irq_chip_ciu_wd_v2; - chip_gpio = &octeon_irq_chip_ciu_gpio_v2; + octeon_irq_gpio_chip = &octeon_irq_chip_ciu_gpio_v2; } else { octeon_irq_ip2 = octeon_irq_ip2_v1; octeon_irq_ip3 = octeon_irq_ip3_v1; chip = &octeon_irq_chip_ciu; chip_mbox = &octeon_irq_chip_ciu_mbox; chip_wd = &octeon_irq_chip_ciu_wd; - chip_gpio = &octeon_irq_chip_ciu_gpio; + octeon_irq_gpio_chip = &octeon_irq_chip_ciu_gpio; } + octeon_irq_ciu_chip = chip; octeon_irq_ip4 = octeon_irq_ip4_mask; /* Mips internal */ @@ -1003,8 +1180,6 @@ static void __init octeon_irq_init_ciu(void) /* CIU_0 */ for (i = 0; i < 16; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq); - for (i = 0; i < 16; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip_gpio, octeon_irq_handle_gpio); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq); @@ -1035,6 +1210,28 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII1, 1, 18, chip, handle_level_irq); + gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio"); + if (gpio_node) { + struct octeon_irq_gpio_domain_data *gpiod; + + gpiod = kzalloc(sizeof(*gpiod), GFP_KERNEL); + if (gpiod) { + /* gpio domain host_data is the base hwirq number. */ + gpiod->base_hwirq = 16; + irq_domain_add_linear(gpio_node, 16, &octeon_irq_domain_gpio_ops, gpiod); + of_node_put(gpio_node); + } else + pr_warn("Cannot allocate memory for GPIO irq_domain.\n"); + } else + pr_warn("Cannot find device node for cavium,octeon-3860-gpio.\n"); + + ciu_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-ciu"); + if (ciu_node) { + irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL); + of_node_put(ciu_node); + } else + pr_warn("Cannot find device node for cavium,octeon-3860-ciu.\n"); + /* Enable the CIU lines */ set_c0_status(STATUSF_IP3 | STATUSF_IP2); clear_c0_status(STATUSF_IP4); -- cgit v0.10.2 From f353a218de6393fb43a5e81c3adbe1aac1a871ab Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:39 +0200 Subject: i2c: Convert i2c-octeon.c to use device tree. There are three parts to this: 1) Remove the definitions of OCTEON_IRQ_TWSI and OCTEON_IRQ_TWSI2. The interrupts are specified by the device tree and these hard coded irq numbers block the used of the irq lines by the irq_domain code. 2) Remove platform device setup code from octeon-platform.c, it is now unused. 3) Convert i2c-octeon.c to use device tree. Part of this includes using the devm_* functions instead of the raw counterparts, thus simplifying error handling. No functionality is changed. Signed-off-by: David Daney Acked-by: Rob Herring Acked-by: Wolfram Sang Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/3939/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 52610ce..2a661ad 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -1192,13 +1192,11 @@ static void __init octeon_irq_init_ciu(void) for (i = 0; i < 4; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_MSI0, 0, i + 40, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI, 0, 45, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq); for (i = 0; i < 4; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI2, 0, 59, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII0, 0, 62, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq); diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 2754bc2..f62a40f 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -168,90 +168,6 @@ out: } device_initcall(octeon_rng_device_init); -static struct i2c_board_info __initdata octeon_i2c_devices[] = { - { - I2C_BOARD_INFO("ds1337", 0x68), - }, -}; - -static int __init octeon_i2c_devices_init(void) -{ - return i2c_register_board_info(0, octeon_i2c_devices, - ARRAY_SIZE(octeon_i2c_devices)); -} -arch_initcall(octeon_i2c_devices_init); - -#define OCTEON_I2C_IO_BASE 0x1180000001000ull -#define OCTEON_I2C_IO_UNIT_OFFSET 0x200 - -static struct octeon_i2c_data octeon_i2c_data[2]; - -static int __init octeon_i2c_device_init(void) -{ - struct platform_device *pd; - int ret = 0; - int port, num_ports; - - struct resource i2c_resources[] = { - { - .flags = IORESOURCE_MEM, - }, { - .flags = IORESOURCE_IRQ, - } - }; - - if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) - num_ports = 2; - else - num_ports = 1; - - for (port = 0; port < num_ports; port++) { - octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate(); - /*FIXME: should be examined. At the moment is set for 100Khz */ - octeon_i2c_data[port].i2c_freq = 100000; - - pd = platform_device_alloc("i2c-octeon", port); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - pd->dev.platform_data = octeon_i2c_data + port; - - i2c_resources[0].start = - OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET); - i2c_resources[0].end = i2c_resources[0].start + 0x1f; - switch (port) { - case 0: - i2c_resources[1].start = OCTEON_IRQ_TWSI; - i2c_resources[1].end = OCTEON_IRQ_TWSI; - break; - case 1: - i2c_resources[1].start = OCTEON_IRQ_TWSI2; - i2c_resources[1].end = OCTEON_IRQ_TWSI2; - break; - default: - BUG(); - } - - ret = platform_device_add_resources(pd, - i2c_resources, - ARRAY_SIZE(i2c_resources)); - if (ret) - goto fail; - - ret = platform_device_add(pd); - if (ret) - goto fail; - } - return ret; -fail: - platform_device_put(pd); -out: - return ret; -} -device_initcall(octeon_i2c_device_init); - /* Octeon SMI/MDIO interface. */ static int __init octeon_mdiobus_device_init(void) { diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index f72f768..1e2486e 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h @@ -215,11 +215,6 @@ struct octeon_cf_data { int dma_engine; /* -1 for no DMA */ }; -struct octeon_i2c_data { - unsigned int sys_freq; - unsigned int i2c_freq; -}; - extern void octeon_write_lcd(const char *s); extern void octeon_check_cpu_bist(void); extern int octeon_get_boot_debug_flag(void); diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index ee139a5..f44c835 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -2,7 +2,7 @@ * (C) Copyright 2009-2010 * Nokia Siemens Networks, michael.lawnick.ext@nsn.com * - * Portions Copyright (C) 2010 Cavium Networks, Inc. + * Portions Copyright (C) 2010, 2011 Cavium Networks, Inc. * * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. * @@ -11,17 +11,18 @@ * warranty of any kind, whether express or implied. */ +#include +#include #include #include +#include +#include #include #include #include - -#include #include -#include -#include -#include +#include +#include #include @@ -65,7 +66,7 @@ struct octeon_i2c { wait_queue_head_t queue; struct i2c_adapter adap; int irq; - int twsi_freq; + u32 twsi_freq; int sys_freq; resource_size_t twsi_phys; void __iomem *twsi_base; @@ -121,10 +122,8 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg) */ static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) { - u64 tmp; - __raw_writeq(data, i2c->twsi_base + TWSI_INT); - tmp = __raw_readq(i2c->twsi_base + TWSI_INT); + __raw_readq(i2c->twsi_base + TWSI_INT); } /** @@ -515,7 +514,6 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev) { int irq, result = 0; struct octeon_i2c *i2c; - struct octeon_i2c_data *i2c_data; struct resource *res_mem; /* All adaptors have an irq. */ @@ -523,86 +521,90 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev) if (irq < 0) return irq; - i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) { dev_err(&pdev->dev, "kzalloc failed\n"); result = -ENOMEM; goto out; } i2c->dev = &pdev->dev; - i2c_data = pdev->dev.platform_data; res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res_mem == NULL) { dev_err(i2c->dev, "found no memory resource\n"); result = -ENXIO; - goto fail_region; + goto out; } + i2c->twsi_phys = res_mem->start; + i2c->regsize = resource_size(res_mem); - if (i2c_data == NULL) { - dev_err(i2c->dev, "no I2C frequency data\n"); + /* + * "clock-rate" is a legacy binding, the official binding is + * "clock-frequency". Try the official one first and then + * fall back if it doesn't exist. + */ + if (of_property_read_u32(pdev->dev.of_node, + "clock-frequency", &i2c->twsi_freq) && + of_property_read_u32(pdev->dev.of_node, + "clock-rate", &i2c->twsi_freq)) { + dev_err(i2c->dev, + "no I2C 'clock-rate' or 'clock-frequency' property\n"); result = -ENXIO; - goto fail_region; + goto out; } - i2c->twsi_phys = res_mem->start; - i2c->regsize = resource_size(res_mem); - i2c->twsi_freq = i2c_data->i2c_freq; - i2c->sys_freq = i2c_data->sys_freq; + i2c->sys_freq = octeon_get_io_clock_rate(); - if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) { + if (!devm_request_mem_region(&pdev->dev, i2c->twsi_phys, i2c->regsize, + res_mem->name)) { dev_err(i2c->dev, "request_mem_region failed\n"); - goto fail_region; + goto out; } - i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize); + i2c->twsi_base = devm_ioremap(&pdev->dev, i2c->twsi_phys, i2c->regsize); init_waitqueue_head(&i2c->queue); i2c->irq = irq; - result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c); + result = devm_request_irq(&pdev->dev, i2c->irq, + octeon_i2c_isr, 0, DRV_NAME, i2c); if (result < 0) { dev_err(i2c->dev, "failed to attach interrupt\n"); - goto fail_irq; + goto out; } result = octeon_i2c_initlowlevel(i2c); if (result) { dev_err(i2c->dev, "init low level failed\n"); - goto fail_add; + goto out; } result = octeon_i2c_setclock(i2c); if (result) { dev_err(i2c->dev, "clock init failed\n"); - goto fail_add; + goto out; } i2c->adap = octeon_i2c_ops; i2c->adap.dev.parent = &pdev->dev; - i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; + i2c->adap.dev.of_node = pdev->dev.of_node; i2c_set_adapdata(&i2c->adap, i2c); platform_set_drvdata(pdev, i2c); - result = i2c_add_numbered_adapter(&i2c->adap); + result = i2c_add_adapter(&i2c->adap); if (result < 0) { dev_err(i2c->dev, "failed to add adapter\n"); goto fail_add; } - dev_info(i2c->dev, "version %s\n", DRV_VERSION); - return result; + of_i2c_register_devices(&i2c->adap); + + return 0; fail_add: platform_set_drvdata(pdev, NULL); - free_irq(i2c->irq, i2c); -fail_irq: - iounmap(i2c->twsi_base); - release_mem_region(i2c->twsi_phys, i2c->regsize); -fail_region: - kfree(i2c); out: return result; }; @@ -613,19 +615,24 @@ static int __devexit octeon_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); platform_set_drvdata(pdev, NULL); - free_irq(i2c->irq, i2c); - iounmap(i2c->twsi_base); - release_mem_region(i2c->twsi_phys, i2c->regsize); - kfree(i2c); return 0; }; +static struct of_device_id octeon_i2c_match[] = { + { + .compatible = "cavium,octeon-3860-twsi", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_i2c_match); + static struct platform_driver octeon_i2c_driver = { .probe = octeon_i2c_probe, .remove = __devexit_p(octeon_i2c_remove), .driver = { .owner = THIS_MODULE, .name = DRV_NAME, + .of_match_table = octeon_i2c_match, }, }; @@ -635,4 +642,3 @@ MODULE_AUTHOR("Michael Lawnick "); MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -MODULE_ALIAS("platform:" DRV_NAME); -- cgit v0.10.2 From 2fd46f47be0f96be700053d6caa8dcb14453a520 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:39 +0200 Subject: netdev: mdio-octeon.c: Convert to use device tree. Get the MDIO bus controller addresses from the device tree, small clean up in use of devm_* Remove, now unused, platform device setup code. Signed-off-by: David Daney Acked-by: David S. Miller Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: Rob Herring Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/3938/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index f62a40f..66cabc2 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -168,36 +168,6 @@ out: } device_initcall(octeon_rng_device_init); -/* Octeon SMI/MDIO interface. */ -static int __init octeon_mdiobus_device_init(void) -{ - struct platform_device *pd; - int ret = 0; - - if (octeon_is_simulation()) - return 0; /* No mdio in the simulator. */ - - /* The bus number is the platform_device id. */ - pd = platform_device_alloc("mdio-octeon", 0); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - ret = platform_device_add(pd); - if (ret) - goto fail; - - return ret; -fail: - platform_device_put(pd); - -out: - return ret; - -} -device_initcall(octeon_mdiobus_device_init); - /* Octeon mgmt port Ethernet interface. */ static int __init octeon_mgmt_device_init(void) { diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index 826d961..d4015aa 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c @@ -3,14 +3,17 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2009 Cavium Networks + * Copyright (C) 2009,2011 Cavium, Inc. */ -#include -#include -#include #include +#include +#include +#include +#include +#include #include +#include #include #include @@ -18,9 +21,17 @@ #define DRV_VERSION "1.0" #define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver" +#define SMI_CMD 0x0 +#define SMI_WR_DAT 0x8 +#define SMI_RD_DAT 0x10 +#define SMI_CLK 0x18 +#define SMI_EN 0x20 + struct octeon_mdiobus { struct mii_bus *mii_bus; - int unit; + u64 register_base; + resource_size_t mdio_phys; + resource_size_t regsize; int phy_irq[PHY_MAX_ADDR]; }; @@ -35,15 +46,15 @@ static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */ smi_cmd.s.phy_adr = phy_id; smi_cmd.s.reg_adr = regnum; - cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64); + cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); do { /* * Wait 1000 clocks so we don't saturate the RSL bus * doing reads. */ - cvmx_wait(1000); - smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(p->unit)); + __delay(1000); + smi_rd.u64 = cvmx_read_csr(p->register_base + SMI_RD_DAT); } while (smi_rd.s.pending && --timeout); if (smi_rd.s.val) @@ -62,21 +73,21 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id, smi_wr.u64 = 0; smi_wr.s.dat = val; - cvmx_write_csr(CVMX_SMIX_WR_DAT(p->unit), smi_wr.u64); + cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64); smi_cmd.u64 = 0; smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */ smi_cmd.s.phy_adr = phy_id; smi_cmd.s.reg_adr = regnum; - cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64); + cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); do { /* * Wait 1000 clocks so we don't saturate the RSL bus * doing reads. */ - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(p->unit)); + __delay(1000); + smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT); } while (smi_wr.s.pending && --timeout); if (timeout <= 0) @@ -88,38 +99,44 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id, static int __devinit octeon_mdiobus_probe(struct platform_device *pdev) { struct octeon_mdiobus *bus; + struct resource *res_mem; union cvmx_smix_en smi_en; - int i; int err = -ENOENT; bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); if (!bus) return -ENOMEM; - /* The platform_device id is our unit number. */ - bus->unit = pdev->id; + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (res_mem == NULL) { + dev_err(&pdev->dev, "found no memory resource\n"); + err = -ENXIO; + goto fail; + } + bus->mdio_phys = res_mem->start; + bus->regsize = resource_size(res_mem); + if (!devm_request_mem_region(&pdev->dev, bus->mdio_phys, bus->regsize, + res_mem->name)) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + goto fail; + } + bus->register_base = + (u64)devm_ioremap(&pdev->dev, bus->mdio_phys, bus->regsize); bus->mii_bus = mdiobus_alloc(); if (!bus->mii_bus) - goto err; + goto fail; smi_en.u64 = 0; smi_en.s.en = 1; - cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64); - - /* - * Standard Octeon evaluation boards don't support phy - * interrupts, we need to poll. - */ - for (i = 0; i < PHY_MAX_ADDR; i++) - bus->phy_irq[i] = PHY_POLL; + cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); bus->mii_bus->priv = bus; bus->mii_bus->irq = bus->phy_irq; bus->mii_bus->name = "mdio-octeon"; - snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", - bus->mii_bus->name, bus->unit); + snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base); bus->mii_bus->parent = &pdev->dev; bus->mii_bus->read = octeon_mdiobus_read; @@ -127,20 +144,18 @@ static int __devinit octeon_mdiobus_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, bus); - err = mdiobus_register(bus->mii_bus); + err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node); if (err) - goto err_register; + goto fail_register; dev_info(&pdev->dev, "Version " DRV_VERSION "\n"); return 0; -err_register: +fail_register: mdiobus_free(bus->mii_bus); - -err: - devm_kfree(&pdev->dev, bus); +fail: smi_en.u64 = 0; - cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64); + cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); return err; } @@ -154,14 +169,23 @@ static int __devexit octeon_mdiobus_remove(struct platform_device *pdev) mdiobus_unregister(bus->mii_bus); mdiobus_free(bus->mii_bus); smi_en.u64 = 0; - cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64); + cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); return 0; } +static struct of_device_id octeon_mdiobus_match[] = { + { + .compatible = "cavium,octeon-3860-mdio", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_mdiobus_match); + static struct platform_driver octeon_mdiobus_driver = { .driver = { .name = "mdio-octeon", .owner = THIS_MODULE, + .of_match_table = octeon_mdiobus_match, }, .probe = octeon_mdiobus_probe, .remove = __devexit_p(octeon_mdiobus_remove), -- cgit v0.10.2 From 368bec0d4a84f78f8c2be8441916d905a8da73c2 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:39 +0200 Subject: netdev: octeon_mgmt: Convert to use device tree. The device tree will supply the register bank base addresses, make register addressing relative to those. PHY connection is now described by the device tree. The OCTEON_IRQ_MII{0,1} symbols are also removed as they are now unused and interfere with the irq_domain used for device tree irq mapping. Signed-off-by: David Daney Acked-by: David S. Miller Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely Cc: Rob Herring Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/3941/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 2a661ad..5fb76aa 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -1197,7 +1197,6 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII0, 0, 62, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq); /* CIU_1 */ @@ -1206,7 +1205,6 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART2, 1, 16, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII1, 1, 18, chip, handle_level_irq); gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio"); if (gpio_node) { diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 66cabc2..0938df1 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -168,68 +168,6 @@ out: } device_initcall(octeon_rng_device_init); -/* Octeon mgmt port Ethernet interface. */ -static int __init octeon_mgmt_device_init(void) -{ - struct platform_device *pd; - int ret = 0; - int port, num_ports; - - struct resource mgmt_port_resource = { - .flags = IORESOURCE_IRQ, - .start = -1, - .end = -1 - }; - - if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX)) - return 0; - - if (OCTEON_IS_MODEL(OCTEON_CN56XX)) - num_ports = 1; - else - num_ports = 2; - - for (port = 0; port < num_ports; port++) { - pd = platform_device_alloc("octeon_mgmt", port); - if (!pd) { - ret = -ENOMEM; - goto out; - } - /* No DMA restrictions */ - pd->dev.coherent_dma_mask = DMA_BIT_MASK(64); - pd->dev.dma_mask = &pd->dev.coherent_dma_mask; - - switch (port) { - case 0: - mgmt_port_resource.start = OCTEON_IRQ_MII0; - break; - case 1: - mgmt_port_resource.start = OCTEON_IRQ_MII1; - break; - default: - BUG(); - } - mgmt_port_resource.end = mgmt_port_resource.start; - - ret = platform_device_add_resources(pd, &mgmt_port_resource, 1); - - if (ret) - goto fail; - - ret = platform_device_add(pd); - if (ret) - goto fail; - } - return ret; -fail: - platform_device_put(pd); - -out: - return ret; - -} -device_initcall(octeon_mgmt_device_init); - #ifdef CONFIG_USB static int __init octeon_ehci_device_init(void) diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c index cd827ff..c42bbb1 100644 --- a/drivers/net/ethernet/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/octeon/octeon_mgmt.c @@ -6,19 +6,21 @@ * Copyright (C) 2009 Cavium Networks */ -#include +#include #include -#include -#include +#include +#include #include -#include #include -#include -#include +#include #include +#include +#include +#include +#include #include #include -#include +#include #include #include @@ -58,8 +60,56 @@ union mgmt_port_ring_entry { } s; }; +#define MIX_ORING1 0x0 +#define MIX_ORING2 0x8 +#define MIX_IRING1 0x10 +#define MIX_IRING2 0x18 +#define MIX_CTL 0x20 +#define MIX_IRHWM 0x28 +#define MIX_IRCNT 0x30 +#define MIX_ORHWM 0x38 +#define MIX_ORCNT 0x40 +#define MIX_ISR 0x48 +#define MIX_INTENA 0x50 +#define MIX_REMCNT 0x58 +#define MIX_BIST 0x78 + +#define AGL_GMX_PRT_CFG 0x10 +#define AGL_GMX_RX_FRM_CTL 0x18 +#define AGL_GMX_RX_FRM_MAX 0x30 +#define AGL_GMX_RX_JABBER 0x38 +#define AGL_GMX_RX_STATS_CTL 0x50 + +#define AGL_GMX_RX_STATS_PKTS_DRP 0xb0 +#define AGL_GMX_RX_STATS_OCTS_DRP 0xb8 +#define AGL_GMX_RX_STATS_PKTS_BAD 0xc0 + +#define AGL_GMX_RX_ADR_CTL 0x100 +#define AGL_GMX_RX_ADR_CAM_EN 0x108 +#define AGL_GMX_RX_ADR_CAM0 0x180 +#define AGL_GMX_RX_ADR_CAM1 0x188 +#define AGL_GMX_RX_ADR_CAM2 0x190 +#define AGL_GMX_RX_ADR_CAM3 0x198 +#define AGL_GMX_RX_ADR_CAM4 0x1a0 +#define AGL_GMX_RX_ADR_CAM5 0x1a8 + +#define AGL_GMX_TX_STATS_CTL 0x268 +#define AGL_GMX_TX_CTL 0x270 +#define AGL_GMX_TX_STAT0 0x280 +#define AGL_GMX_TX_STAT1 0x288 +#define AGL_GMX_TX_STAT2 0x290 +#define AGL_GMX_TX_STAT3 0x298 +#define AGL_GMX_TX_STAT4 0x2a0 +#define AGL_GMX_TX_STAT5 0x2a8 +#define AGL_GMX_TX_STAT6 0x2b0 +#define AGL_GMX_TX_STAT7 0x2b8 +#define AGL_GMX_TX_STAT8 0x2c0 +#define AGL_GMX_TX_STAT9 0x2c8 + struct octeon_mgmt { struct net_device *netdev; + u64 mix; + u64 agl; int port; int irq; u64 *tx_ring; @@ -85,31 +135,34 @@ struct octeon_mgmt { struct napi_struct napi; struct tasklet_struct tx_clean_tasklet; struct phy_device *phydev; + struct device_node *phy_np; + resource_size_t mix_phys; + resource_size_t mix_size; + resource_size_t agl_phys; + resource_size_t agl_size; }; static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable) { - int port = p->port; union cvmx_mixx_intena mix_intena; unsigned long flags; spin_lock_irqsave(&p->lock, flags); - mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port)); + mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA); mix_intena.s.ithena = enable ? 1 : 0; - cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64); + cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); spin_unlock_irqrestore(&p->lock, flags); } static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable) { - int port = p->port; union cvmx_mixx_intena mix_intena; unsigned long flags; spin_lock_irqsave(&p->lock, flags); - mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port)); + mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA); mix_intena.s.othena = enable ? 1 : 0; - cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64); + cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); spin_unlock_irqrestore(&p->lock, flags); } @@ -146,7 +199,6 @@ static unsigned int ring_size_to_bytes(unsigned int ring_size) static void octeon_mgmt_rx_fill_ring(struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; while (p->rx_current_fill < ring_max_fill(OCTEON_MGMT_RX_RING_SIZE)) { unsigned int size; @@ -177,24 +229,23 @@ static void octeon_mgmt_rx_fill_ring(struct net_device *netdev) (p->rx_next_fill + 1) % OCTEON_MGMT_RX_RING_SIZE; p->rx_current_fill++; /* Ring the bell. */ - cvmx_write_csr(CVMX_MIXX_IRING2(port), 1); + cvmx_write_csr(p->mix + MIX_IRING2, 1); } } static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) { - int port = p->port; union cvmx_mixx_orcnt mix_orcnt; union mgmt_port_ring_entry re; struct sk_buff *skb; int cleaned = 0; unsigned long flags; - mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port)); + mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); while (mix_orcnt.s.orcnt) { spin_lock_irqsave(&p->tx_list.lock, flags); - mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port)); + mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); if (mix_orcnt.s.orcnt == 0) { spin_unlock_irqrestore(&p->tx_list.lock, flags); @@ -214,7 +265,7 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) mix_orcnt.s.orcnt = 1; /* Acknowledge to hardware that we have the buffer. */ - cvmx_write_csr(CVMX_MIXX_ORCNT(port), mix_orcnt.u64); + cvmx_write_csr(p->mix + MIX_ORCNT, mix_orcnt.u64); p->tx_current_fill--; spin_unlock_irqrestore(&p->tx_list.lock, flags); @@ -224,7 +275,7 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) dev_kfree_skb_any(skb); cleaned++; - mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port)); + mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); } if (cleaned && netif_queue_stopped(p->netdev)) @@ -241,13 +292,12 @@ static void octeon_mgmt_clean_tx_tasklet(unsigned long arg) static void octeon_mgmt_update_rx_stats(struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; unsigned long flags; u64 drop, bad; /* These reads also clear the count registers. */ - drop = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port)); - bad = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port)); + drop = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP); + bad = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_BAD); if (drop || bad) { /* Do an atomic update. */ @@ -261,15 +311,14 @@ static void octeon_mgmt_update_rx_stats(struct net_device *netdev) static void octeon_mgmt_update_tx_stats(struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; unsigned long flags; union cvmx_agl_gmx_txx_stat0 s0; union cvmx_agl_gmx_txx_stat1 s1; /* These reads also clear the count registers. */ - s0.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT0(port)); - s1.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT1(port)); + s0.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_STAT0); + s1.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_STAT1); if (s0.s.xsdef || s0.s.xscol || s1.s.scol || s1.s.mcol) { /* Do an atomic update. */ @@ -308,7 +357,6 @@ static u64 octeon_mgmt_dequeue_rx_buffer(struct octeon_mgmt *p, static int octeon_mgmt_receive_one(struct octeon_mgmt *p) { - int port = p->port; struct net_device *netdev = p->netdev; union cvmx_mixx_ircnt mix_ircnt; union mgmt_port_ring_entry re; @@ -381,18 +429,17 @@ done: /* Tell the hardware we processed a packet. */ mix_ircnt.u64 = 0; mix_ircnt.s.ircnt = 1; - cvmx_write_csr(CVMX_MIXX_IRCNT(port), mix_ircnt.u64); + cvmx_write_csr(p->mix + MIX_IRCNT, mix_ircnt.u64); return rc; } static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget) { - int port = p->port; unsigned int work_done = 0; union cvmx_mixx_ircnt mix_ircnt; int rc; - mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port)); + mix_ircnt.u64 = cvmx_read_csr(p->mix + MIX_IRCNT); while (work_done < budget && mix_ircnt.s.ircnt) { rc = octeon_mgmt_receive_one(p); @@ -400,7 +447,7 @@ static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget) work_done++; /* Check for more packets. */ - mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port)); + mix_ircnt.u64 = cvmx_read_csr(p->mix + MIX_IRCNT); } octeon_mgmt_rx_fill_ring(p->netdev); @@ -434,16 +481,16 @@ static void octeon_mgmt_reset_hw(struct octeon_mgmt *p) union cvmx_agl_gmx_bist agl_gmx_bist; mix_ctl.u64 = 0; - cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64); + cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); do { - mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(p->port)); + mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL); } while (mix_ctl.s.busy); mix_ctl.s.reset = 1; - cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64); - cvmx_read_csr(CVMX_MIXX_CTL(p->port)); + cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); + cvmx_read_csr(p->mix + MIX_CTL); cvmx_wait(64); - mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(p->port)); + mix_bist.u64 = cvmx_read_csr(p->mix + MIX_BIST); if (mix_bist.u64) dev_warn(p->dev, "MIX failed BIST (0x%016llx)\n", (unsigned long long)mix_bist.u64); @@ -474,7 +521,6 @@ static void octeon_mgmt_cam_state_add(struct octeon_mgmt_cam_state *cs, static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; union cvmx_agl_gmx_rxx_adr_ctl adr_ctl; union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx; unsigned long flags; @@ -520,29 +566,29 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) spin_lock_irqsave(&p->lock, flags); /* Disable packet I/O. */ - agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); + agl_gmx_prtx.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); prev_packet_enable = agl_gmx_prtx.s.en; agl_gmx_prtx.s.en = 0; - cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); + cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, agl_gmx_prtx.u64); adr_ctl.u64 = 0; adr_ctl.s.cam_mode = cam_mode; adr_ctl.s.mcst = multicast_mode; adr_ctl.s.bcst = 1; /* Allow broadcast */ - cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), adr_ctl.u64); + cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CTL, adr_ctl.u64); - cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM0(port), cam_state.cam[0]); - cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM1(port), cam_state.cam[1]); - cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM2(port), cam_state.cam[2]); - cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM3(port), cam_state.cam[3]); - cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM4(port), cam_state.cam[4]); - cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM5(port), cam_state.cam[5]); - cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), cam_state.cam_mask); + cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM0, cam_state.cam[0]); + cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM1, cam_state.cam[1]); + cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM2, cam_state.cam[2]); + cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM3, cam_state.cam[3]); + cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM4, cam_state.cam[4]); + cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM5, cam_state.cam[5]); + cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM_EN, cam_state.cam_mask); /* Restore packet I/O. */ agl_gmx_prtx.s.en = prev_packet_enable; - cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); + cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, agl_gmx_prtx.u64); spin_unlock_irqrestore(&p->lock, flags); } @@ -564,7 +610,6 @@ static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr) static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM; /* @@ -580,8 +625,8 @@ static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu) netdev->mtu = new_mtu; - cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_MAX(port), size_without_fcs); - cvmx_write_csr(CVMX_AGL_GMX_RXX_JABBER(port), + cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_MAX, size_without_fcs); + cvmx_write_csr(p->agl + AGL_GMX_RX_JABBER, (size_without_fcs + 7) & 0xfff8); return 0; @@ -591,14 +636,13 @@ static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id) { struct net_device *netdev = dev_id; struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; union cvmx_mixx_isr mixx_isr; - mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(port)); + mixx_isr.u64 = cvmx_read_csr(p->mix + MIX_ISR); /* Clear any pending interrupts */ - cvmx_write_csr(CVMX_MIXX_ISR(port), mixx_isr.u64); - cvmx_read_csr(CVMX_MIXX_ISR(port)); + cvmx_write_csr(p->mix + MIX_ISR, mixx_isr.u64); + cvmx_read_csr(p->mix + MIX_ISR); if (mixx_isr.s.irthresh) { octeon_mgmt_disable_rx_irq(p); @@ -629,7 +673,6 @@ static int octeon_mgmt_ioctl(struct net_device *netdev, static void octeon_mgmt_adjust_link(struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; union cvmx_agl_gmx_prtx_cfg prtx_cfg; unsigned long flags; int link_changed = 0; @@ -640,11 +683,9 @@ static void octeon_mgmt_adjust_link(struct net_device *netdev) link_changed = 1; if (p->last_duplex != p->phydev->duplex) { p->last_duplex = p->phydev->duplex; - prtx_cfg.u64 = - cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); + prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); prtx_cfg.s.duplex = p->phydev->duplex; - cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), - prtx_cfg.u64); + cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); } } else { if (p->last_link) @@ -670,18 +711,16 @@ static void octeon_mgmt_adjust_link(struct net_device *netdev) static int octeon_mgmt_init_phy(struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - char phy_id[MII_BUS_ID_SIZE + 3]; - if (octeon_is_simulation()) { + if (octeon_is_simulation() || p->phy_np == NULL) { /* No PHYs in the simulator. */ netif_carrier_on(netdev); return 0; } - snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", p->port); - - p->phydev = phy_connect(netdev, phy_id, octeon_mgmt_adjust_link, 0, - PHY_INTERFACE_MODE_MII); + p->phydev = of_phy_connect(netdev, p->phy_np, + octeon_mgmt_adjust_link, 0, + PHY_INTERFACE_MODE_MII); if (IS_ERR(p->phydev)) { p->phydev = NULL; @@ -737,14 +776,14 @@ static int octeon_mgmt_open(struct net_device *netdev) octeon_mgmt_reset_hw(p); - mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); + mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL); /* Bring it out of reset if needed. */ if (mix_ctl.s.reset) { mix_ctl.s.reset = 0; - cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); + cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); do { - mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); + mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL); } while (mix_ctl.s.reset); } @@ -755,17 +794,17 @@ static int octeon_mgmt_open(struct net_device *netdev) oring1.u64 = 0; oring1.s.obase = p->tx_ring_handle >> 3; oring1.s.osize = OCTEON_MGMT_TX_RING_SIZE; - cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64); + cvmx_write_csr(p->mix + MIX_ORING1, oring1.u64); iring1.u64 = 0; iring1.s.ibase = p->rx_ring_handle >> 3; iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE; - cvmx_write_csr(CVMX_MIXX_IRING1(port), iring1.u64); + cvmx_write_csr(p->mix + MIX_IRING1, iring1.u64); /* Disable packet I/O. */ - prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); + prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); prtx_cfg.s.en = 0; - cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64); + cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN); octeon_mgmt_set_mac_address(netdev, &sa); @@ -782,7 +821,7 @@ static int octeon_mgmt_open(struct net_device *netdev) mix_ctl.s.nbtarb = 0; /* Arbitration mode */ /* MII CB-request FIFO programmable high watermark */ mix_ctl.s.mrq_hwm = 1; - cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); + cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { @@ -809,16 +848,16 @@ static int octeon_mgmt_open(struct net_device *netdev) /* Clear statistics. */ /* Clear on read. */ - cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_CTL(port), 1); - cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port), 0); - cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port), 0); + cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_CTL, 1); + cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP, 0); + cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_PKTS_BAD, 0); - cvmx_write_csr(CVMX_AGL_GMX_TXX_STATS_CTL(port), 1); - cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT0(port), 0); - cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT1(port), 0); + cvmx_write_csr(p->agl + AGL_GMX_TX_STATS_CTL, 1); + cvmx_write_csr(p->agl + AGL_GMX_TX_STAT0, 0); + cvmx_write_csr(p->agl + AGL_GMX_TX_STAT1, 0); /* Clear any pending interrupts */ - cvmx_write_csr(CVMX_MIXX_ISR(port), cvmx_read_csr(CVMX_MIXX_ISR(port))); + cvmx_write_csr(p->mix + MIX_ISR, cvmx_read_csr(p->mix + MIX_ISR)); if (request_irq(p->irq, octeon_mgmt_interrupt, 0, netdev->name, netdev)) { @@ -829,18 +868,18 @@ static int octeon_mgmt_open(struct net_device *netdev) /* Interrupt every single RX packet */ mix_irhwm.u64 = 0; mix_irhwm.s.irhwm = 0; - cvmx_write_csr(CVMX_MIXX_IRHWM(port), mix_irhwm.u64); + cvmx_write_csr(p->mix + MIX_IRHWM, mix_irhwm.u64); /* Interrupt when we have 1 or more packets to clean. */ mix_orhwm.u64 = 0; mix_orhwm.s.orhwm = 1; - cvmx_write_csr(CVMX_MIXX_ORHWM(port), mix_orhwm.u64); + cvmx_write_csr(p->mix + MIX_ORHWM, mix_orhwm.u64); /* Enable receive and transmit interrupts */ mix_intena.u64 = 0; mix_intena.s.ithena = 1; mix_intena.s.othena = 1; - cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64); + cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); /* Enable packet I/O. */ @@ -871,7 +910,7 @@ static int octeon_mgmt_open(struct net_device *netdev) * frame. GMX checks that the PREAMBLE is sent correctly. */ rxx_frm_ctl.s.pre_chk = 1; - cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64); + cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64); /* Enable the AGL block */ agl_gmx_inf_mode.u64 = 0; @@ -879,13 +918,13 @@ static int octeon_mgmt_open(struct net_device *netdev) cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64); /* Configure the port duplex and enables */ - prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); + prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); prtx_cfg.s.tx_en = 1; prtx_cfg.s.rx_en = 1; prtx_cfg.s.en = 1; p->last_duplex = 1; prtx_cfg.s.duplex = p->last_duplex; - cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64); + cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); p->last_link = 0; netif_carrier_off(netdev); @@ -949,7 +988,6 @@ static int octeon_mgmt_stop(struct net_device *netdev) static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; union mgmt_port_ring_entry re; unsigned long flags; int rv = NETDEV_TX_BUSY; @@ -993,7 +1031,7 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev) netdev->stats.tx_bytes += skb->len; /* Ring the bell. */ - cvmx_write_csr(CVMX_MIXX_ORING2(port), 1); + cvmx_write_csr(p->mix + MIX_ORING2, 1); rv = NETDEV_TX_OK; out: @@ -1071,10 +1109,14 @@ static const struct net_device_ops octeon_mgmt_ops = { static int __devinit octeon_mgmt_probe(struct platform_device *pdev) { - struct resource *res_irq; struct net_device *netdev; struct octeon_mgmt *p; - int i; + const __be32 *data; + const u8 *mac; + struct resource *res_mix; + struct resource *res_agl; + int len; + int result; netdev = alloc_etherdev(sizeof(struct octeon_mgmt)); if (netdev == NULL) @@ -1088,14 +1130,63 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev) p->netdev = netdev; p->dev = &pdev->dev; - p->port = pdev->id; + data = of_get_property(pdev->dev.of_node, "cell-index", &len); + if (data && len == sizeof(*data)) { + p->port = be32_to_cpup(data); + } else { + dev_err(&pdev->dev, "no 'cell-index' property\n"); + result = -ENXIO; + goto err; + } + snprintf(netdev->name, IFNAMSIZ, "mgmt%d", p->port); - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_irq) + result = platform_get_irq(pdev, 0); + if (result < 0) + goto err; + + p->irq = result; + + res_mix = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mix == NULL) { + dev_err(&pdev->dev, "no 'reg' resource\n"); + result = -ENXIO; + goto err; + } + + res_agl = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res_agl == NULL) { + dev_err(&pdev->dev, "no 'reg' resource\n"); + result = -ENXIO; + goto err; + } + + p->mix_phys = res_mix->start; + p->mix_size = resource_size(res_mix); + p->agl_phys = res_agl->start; + p->agl_size = resource_size(res_agl); + + + if (!devm_request_mem_region(&pdev->dev, p->mix_phys, p->mix_size, + res_mix->name)) { + dev_err(&pdev->dev, "request_mem_region (%s) failed\n", + res_mix->name); + result = -ENXIO; + goto err; + } + + if (!devm_request_mem_region(&pdev->dev, p->agl_phys, p->agl_size, + res_agl->name)) { + result = -ENXIO; + dev_err(&pdev->dev, "request_mem_region (%s) failed\n", + res_agl->name); goto err; + } + + + p->mix = (u64)devm_ioremap(&pdev->dev, p->mix_phys, p->mix_size); + p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size); - p->irq = res_irq->start; spin_lock_init(&p->lock); skb_queue_head_init(&p->tx_list); @@ -1108,24 +1199,26 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev) netdev->netdev_ops = &octeon_mgmt_ops; netdev->ethtool_ops = &octeon_mgmt_ethtool_ops; - /* The mgmt ports get the first N MACs. */ - for (i = 0; i < 6; i++) - netdev->dev_addr[i] = octeon_bootinfo->mac_addr_base[i]; - netdev->dev_addr[5] += p->port; + mac = of_get_mac_address(pdev->dev.of_node); + + if (mac) + memcpy(netdev->dev_addr, mac, 6); - if (p->port >= octeon_bootinfo->mac_addr_count) - dev_err(&pdev->dev, - "Error %s: Using MAC outside of the assigned range: %pM\n", - netdev->name, netdev->dev_addr); + p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); - if (register_netdev(netdev)) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + + result = register_netdev(netdev); + if (result) goto err; dev_info(&pdev->dev, "Version " DRV_VERSION "\n"); return 0; + err: free_netdev(netdev); - return -ENOENT; + return result; } static int __devexit octeon_mgmt_remove(struct platform_device *pdev) @@ -1137,10 +1230,19 @@ static int __devexit octeon_mgmt_remove(struct platform_device *pdev) return 0; } +static struct of_device_id octeon_mgmt_match[] = { + { + .compatible = "cavium,octeon-5750-mix", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_mgmt_match); + static struct platform_driver octeon_mgmt_driver = { .driver = { .name = "octeon_mgmt", .owner = THIS_MODULE, + .of_match_table = octeon_mgmt_match, }, .probe = octeon_mgmt_probe, .remove = __devexit_p(octeon_mgmt_remove), -- cgit v0.10.2 From df9244c5365c12d0cd1452323d3dc3ef91d80173 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:40 +0200 Subject: staging: octeon_ethernet: Convert to use device tree. Get MAC address and PHY connection from the device tree. The driver is converted to a platform driver. Signed-off-by: David Daney Acked-by: Grant Likely Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/3940/ Signed-off-by: Ralf Baechle diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c index e31949c..f15b31b 100644 --- a/drivers/staging/octeon/ethernet-mdio.c +++ b/drivers/staging/octeon/ethernet-mdio.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -161,22 +162,23 @@ static void cvm_oct_adjust_link(struct net_device *dev) int cvm_oct_phy_setup_device(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); + struct device_node *phy_node; - int phy_addr = cvmx_helper_board_get_mii_address(priv->port); - if (phy_addr != -1) { - char phy_id[MII_BUS_ID_SIZE + 3]; + if (!priv->of_node) + return 0; - snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", phy_addr); + phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0); + if (!phy_node) + return 0; - priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0, - PHY_INTERFACE_MODE_GMII); + priv->phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0, + PHY_INTERFACE_MODE_GMII); + + if (priv->phydev == NULL) + return -ENODEV; + + priv->last_link = 0; + phy_start_aneg(priv->phydev); - if (IS_ERR(priv->phydev)) { - priv->phydev = NULL; - return -1; - } - priv->last_link = 0; - phy_start_aneg(priv->phydev); - } return 0; } diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 18f7a79..683bedc 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -24,6 +24,7 @@ * This file may also be available under a different license from Cavium. * Contact Cavium Networks for more information **********************************************************************/ +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include @@ -113,15 +115,6 @@ int rx_napi_weight = 32; module_param(rx_napi_weight, int, 0444); MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter."); -/* - * The offset from mac_addr_base that should be used for the next port - * that is configured. By convention, if any mgmt ports exist on the - * chip, they get the first mac addresses, The ports controlled by - * this driver are numbered sequencially following any mgmt addresses - * that may exist. - */ -static unsigned int cvm_oct_mac_addr_offset; - /** * cvm_oct_poll_queue - Workqueue for polling operations. */ @@ -176,7 +169,7 @@ static void cvm_oct_periodic_worker(struct work_struct *work) queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ); } -static __init void cvm_oct_configure_common_hw(void) +static __devinit void cvm_oct_configure_common_hw(void) { /* Setup the FPA */ cvmx_fpa_enable(); @@ -396,23 +389,21 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev) * Returns Zero on success */ -static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr) +static int cvm_oct_set_mac_filter(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); union cvmx_gmxx_prtx_cfg gmx_cfg; int interface = INTERFACE(priv->port); int index = INDEX(priv->port); - memcpy(dev->dev_addr, addr + 2, 6); - if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) { int i; - uint8_t *ptr = addr; + uint8_t *ptr = dev->dev_addr; uint64_t mac = 0; for (i = 0; i < 6; i++) - mac = (mac << 8) | (uint64_t) (ptr[i + 2]); + mac = (mac << 8) | (uint64_t)ptr[i]; gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); @@ -421,17 +412,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr) cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac); cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), - ptr[2]); + ptr[0]); cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), - ptr[3]); + ptr[1]); cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), - ptr[4]); + ptr[2]); cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), - ptr[5]); + ptr[3]); cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), - ptr[6]); + ptr[4]); cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), - ptr[7]); + ptr[5]); cvm_oct_common_set_multicast_list(dev); cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); @@ -439,6 +430,15 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr) return 0; } +static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr) +{ + int r = eth_mac_addr(dev, addr); + + if (r) + return r; + return cvm_oct_set_mac_filter(dev); +} + /** * cvm_oct_common_init - per network device initialization * @dev: Device to initialize @@ -448,26 +448,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr) int cvm_oct_common_init(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); - struct sockaddr sa; - u64 mac = ((u64)(octeon_bootinfo->mac_addr_base[0] & 0xff) << 40) | - ((u64)(octeon_bootinfo->mac_addr_base[1] & 0xff) << 32) | - ((u64)(octeon_bootinfo->mac_addr_base[2] & 0xff) << 24) | - ((u64)(octeon_bootinfo->mac_addr_base[3] & 0xff) << 16) | - ((u64)(octeon_bootinfo->mac_addr_base[4] & 0xff) << 8) | - (u64)(octeon_bootinfo->mac_addr_base[5] & 0xff); - - mac += cvm_oct_mac_addr_offset; - sa.sa_data[0] = (mac >> 40) & 0xff; - sa.sa_data[1] = (mac >> 32) & 0xff; - sa.sa_data[2] = (mac >> 24) & 0xff; - sa.sa_data[3] = (mac >> 16) & 0xff; - sa.sa_data[4] = (mac >> 8) & 0xff; - sa.sa_data[5] = mac & 0xff; - - if (cvm_oct_mac_addr_offset >= octeon_bootinfo->mac_addr_count) - printk(KERN_DEBUG "%s: Using MAC outside of the assigned range:" - " %pM\n", dev->name, sa.sa_data); - cvm_oct_mac_addr_offset++; + const u8 *mac = NULL; + + if (priv->of_node) + mac = of_get_mac_address(priv->of_node); + + if (mac && is_valid_ether_addr(mac)) { + memcpy(dev->dev_addr, mac, ETH_ALEN); + dev->addr_assign_type &= ~NET_ADDR_RANDOM; + } else { + eth_hw_addr_random(dev); + } /* * Force the interface to use the POW send if always_use_pow @@ -488,7 +479,7 @@ int cvm_oct_common_init(struct net_device *dev) SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops); cvm_oct_phy_setup_device(dev); - dev->netdev_ops->ndo_set_mac_address(dev, &sa); + cvm_oct_set_mac_filter(dev); dev->netdev_ops->ndo_change_mtu(dev, dev->mtu); /* @@ -595,22 +586,55 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = { extern void octeon_mdiobus_force_mod_depencency(void); -static int __init cvm_oct_init_module(void) +static struct device_node * __devinit cvm_oct_of_get_child(const struct device_node *parent, + int reg_val) +{ + struct device_node *node = NULL; + int size; + const __be32 *addr; + + for (;;) { + node = of_get_next_child(parent, node); + if (!node) + break; + addr = of_get_property(node, "reg", &size); + if (addr && (be32_to_cpu(*addr) == reg_val)) + break; + } + return node; +} + +static struct device_node * __devinit cvm_oct_node_for_port(struct device_node *pip, + int interface, int port) +{ + struct device_node *ni, *np; + + ni = cvm_oct_of_get_child(pip, interface); + if (!ni) + return NULL; + + np = cvm_oct_of_get_child(ni, port); + of_node_put(ni); + + return np; +} + +static int __devinit cvm_oct_probe(struct platform_device *pdev) { int num_interfaces; int interface; int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE; int qos; + struct device_node *pip; octeon_mdiobus_force_mod_depencency(); pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION); - if (OCTEON_IS_MODEL(OCTEON_CN52XX)) - cvm_oct_mac_addr_offset = 2; /* First two are the mgmt ports. */ - else if (OCTEON_IS_MODEL(OCTEON_CN56XX)) - cvm_oct_mac_addr_offset = 1; /* First one is the mgmt port. */ - else - cvm_oct_mac_addr_offset = 0; + pip = pdev->dev.of_node; + if (!pip) { + pr_err("Error: No 'pip' in /aliases\n"); + return -EINVAL; + } cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet"); if (cvm_oct_poll_queue == NULL) { @@ -689,10 +713,11 @@ static int __init cvm_oct_init_module(void) cvmx_helper_interface_get_mode(interface); int num_ports = cvmx_helper_ports_on_interface(interface); int port; + int port_index; - for (port = cvmx_helper_get_ipd_port(interface, 0); + for (port_index = 0, port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); - port++) { + port_index++, port++) { struct octeon_ethernet *priv; struct net_device *dev = alloc_etherdev(sizeof(struct octeon_ethernet)); @@ -703,6 +728,7 @@ static int __init cvm_oct_init_module(void) /* Initialize the device private structure. */ priv = netdev_priv(dev); + priv->of_node = cvm_oct_node_for_port(pip, interface, port_index); INIT_DELAYED_WORK(&priv->port_periodic_work, cvm_oct_periodic_worker); @@ -787,7 +813,7 @@ static int __init cvm_oct_init_module(void) return 0; } -static void __exit cvm_oct_cleanup_module(void) +static int __devexit cvm_oct_remove(struct platform_device *pdev) { int port; @@ -835,10 +861,29 @@ static void __exit cvm_oct_cleanup_module(void) if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); + return 0; } +static struct of_device_id cvm_oct_match[] = { + { + .compatible = "cavium,octeon-3860-pip", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cvm_oct_match); + +static struct platform_driver cvm_oct_driver = { + .probe = cvm_oct_probe, + .remove = __devexit_p(cvm_oct_remove), + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .of_match_table = cvm_oct_match, + }, +}; + +module_platform_driver(cvm_oct_driver); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Cavium Networks "); MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver."); -module_init(cvm_oct_init_module); -module_exit(cvm_oct_cleanup_module); diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h index d581925..9360e22 100644 --- a/drivers/staging/octeon/octeon-ethernet.h +++ b/drivers/staging/octeon/octeon-ethernet.h @@ -31,6 +31,8 @@ #ifndef OCTEON_ETHERNET_H #define OCTEON_ETHERNET_H +#include + /** * This is the definition of the Ethernet driver's private * driver state stored in netdev_priv(dev). @@ -59,6 +61,7 @@ struct octeon_ethernet { void (*poll) (struct net_device *dev); struct delayed_work port_periodic_work; struct work_struct port_work; /* may be unused. */ + struct device_node *of_node; }; int cvm_oct_free_work(void *work_queue_entry); -- cgit v0.10.2 From b59b284101454823c77c9635f3ee8cd4f979fe6e Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Jul 2012 18:12:40 +0200 Subject: MIPS: Octeon: Use device tree to register serial ports. Switch to using the device tree to register serial ports. Add all the ports with compatible = "cavium,octeon-3860-uart". Octeon serial ports have their own device type, required port flags, and I/O functions, so using of_serial.c is not indicated. We need to do this as late_initcall, as the 8250 driver must be initialized before we add any ports. 8250 initialization is done at device_initcall time. The OCTEON_IRQ_UART{0,1,2} symbols are removed as they are now unused and interfere with irq_domain used by the device tree code. Signed-off-by: David Daney Acked-by: Grant Likely Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: linux-kernel@vger.kernel.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/3942/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 5fb76aa..7fb1f22 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -1184,9 +1184,6 @@ static void __init octeon_irq_init_ciu(void) octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART0, 0, 34, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART1, 0, 35, chip, handle_level_irq); - for (i = 0; i < 4; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_INT0, 0, i + 36, chip, handle_level_irq); for (i = 0; i < 4; i++) @@ -1203,7 +1200,6 @@ static void __init octeon_irq_init_ciu(void) for (i = 0; i < 16; i++) octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART2, 1, 16, chip, handle_level_irq); octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq); gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio"); diff --git a/arch/mips/cavium-octeon/serial.c b/arch/mips/cavium-octeon/serial.c index 057f0ae..138b221 100644 --- a/arch/mips/cavium-octeon/serial.c +++ b/arch/mips/cavium-octeon/serial.c @@ -43,95 +43,67 @@ void octeon_serial_out(struct uart_port *up, int offset, int value) cvmx_write_csr((uint64_t)(up->membase + (offset << 3)), (u8)value); } -/* - * Allocated in .bss, so it is all zeroed. - */ -#define OCTEON_MAX_UARTS 3 -static struct plat_serial8250_port octeon_uart8250_data[OCTEON_MAX_UARTS + 1]; -static struct platform_device octeon_uart8250_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = octeon_uart8250_data, - }, -}; - -static void __init octeon_uart_set_common(struct plat_serial8250_port *p) +static int __devinit octeon_serial_probe(struct platform_device *pdev) { - p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; - p->type = PORT_OCTEON; - p->iotype = UPIO_MEM; - p->regshift = 3; /* I/O addresses are every 8 bytes */ + int irq, res; + struct resource *res_mem; + struct uart_port port; + + /* All adaptors have an irq. */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + memset(&port, 0, sizeof(port)); + + port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; + port.type = PORT_OCTEON; + port.iotype = UPIO_MEM; + port.regshift = 3; + port.dev = &pdev->dev; + if (octeon_is_simulation()) /* Make simulator output fast*/ - p->uartclk = 115200 * 16; + port.uartclk = 115200 * 16; else - p->uartclk = octeon_get_io_clock_rate(); - p->serial_in = octeon_serial_in; - p->serial_out = octeon_serial_out; -} + port.uartclk = octeon_get_io_clock_rate(); -static int __init octeon_serial_init(void) -{ - int enable_uart0; - int enable_uart1; - int enable_uart2; - struct plat_serial8250_port *p; - -#ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL - /* - * If we are configured to run as the second of two kernels, - * disable uart0 and enable uart1. Uart0 is owned by the first - * kernel - */ - enable_uart0 = 0; - enable_uart1 = 1; -#else - /* - * We are configured for the first kernel. We'll enable uart0 - * if the bootloader told us to use 0, otherwise will enable - * uart 1. - */ - enable_uart0 = (octeon_get_boot_uart() == 0); - enable_uart1 = (octeon_get_boot_uart() == 1); -#ifdef CONFIG_KGDB - enable_uart1 = 1; -#endif -#endif - - /* Right now CN52XX is the only chip with a third uart */ - enable_uart2 = OCTEON_IS_MODEL(OCTEON_CN52XX); - - p = octeon_uart8250_data; - if (enable_uart0) { - /* Add a ttyS device for hardware uart 0 */ - octeon_uart_set_common(p); - p->membase = (void *) CVMX_MIO_UARTX_RBR(0); - p->mapbase = CVMX_MIO_UARTX_RBR(0) & ((1ull << 49) - 1); - p->irq = OCTEON_IRQ_UART0; - p++; - } + port.serial_in = octeon_serial_in; + port.serial_out = octeon_serial_out; + port.irq = irq; - if (enable_uart1) { - /* Add a ttyS device for hardware uart 1 */ - octeon_uart_set_common(p); - p->membase = (void *) CVMX_MIO_UARTX_RBR(1); - p->mapbase = CVMX_MIO_UARTX_RBR(1) & ((1ull << 49) - 1); - p->irq = OCTEON_IRQ_UART1; - p++; - } - if (enable_uart2) { - /* Add a ttyS device for hardware uart 2 */ - octeon_uart_set_common(p); - p->membase = (void *) CVMX_MIO_UART2_RBR; - p->mapbase = CVMX_MIO_UART2_RBR & ((1ull << 49) - 1); - p->irq = OCTEON_IRQ_UART2; - p++; + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem == NULL) { + dev_err(&pdev->dev, "found no memory resource\n"); + return -ENXIO; } + port.mapbase = res_mem->start; + port.membase = ioremap(res_mem->start, resource_size(res_mem)); - BUG_ON(p > &octeon_uart8250_data[OCTEON_MAX_UARTS]); + res = serial8250_register_port(&port); - return platform_device_register(&octeon_uart8250_device); + return res >= 0 ? 0 : res; } -device_initcall(octeon_serial_init); +static struct of_device_id octeon_serial_match[] = { + { + .compatible = "cavium,octeon-3860-uart", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_serial_match); + +static struct platform_driver octeon_serial_driver = { + .probe = octeon_serial_probe, + .driver = { + .owner = THIS_MODULE, + .name = "octeon_serial", + .of_match_table = octeon_serial_match, + }, +}; + +static int __init octeon_serial_init(void) +{ + return platform_driver_register(&octeon_serial_driver); +} +late_initcall(octeon_serial_init); -- cgit v0.10.2 From 2244f1286509673c0b40fb9504a9be0b7b633aeb Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Mon, 21 May 2012 10:33:16 -0500 Subject: MIPS: Remove dead code related to 1004K oprofile support. Signed-off-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3854/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 4d80a85..52da646 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -339,12 +339,6 @@ static int __init mipsxx_init(void) break; case CPU_1004K: -#if 0 - /* FIXME: report as 34K for now */ - op_model_mipsxx_ops.cpu_type = "mips/1004K"; - break; -#endif - case CPU_34K: op_model_mipsxx_ops.cpu_type = "mips/34K"; break; -- cgit v0.10.2 From 889a4c7b33607bf03c04b8f2d5607fd4274f47f3 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Mon, 9 Apr 2012 10:58:39 -0500 Subject: MIPS: SMTC: Support for Multi-threaded FPUs Signed-off-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3603/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h index e71ff4c..5b3cb85 100644 --- a/arch/mips/include/asm/mipsmtregs.h +++ b/arch/mips/include/asm/mipsmtregs.h @@ -28,6 +28,9 @@ #define read_c0_vpeconf0() __read_32bit_c0_register($1, 2) #define write_c0_vpeconf0(val) __write_32bit_c0_register($1, 2, val) +#define read_c0_vpeconf1() __read_32bit_c0_register($1, 3) +#define write_c0_vpeconf1(val) __write_32bit_c0_register($1, 3, val) + #define read_c0_tcstatus() __read_32bit_c0_register($2, 1) #define write_c0_tcstatus(val) __write_32bit_c0_register($2, 1, val) @@ -124,6 +127,14 @@ #define VPECONF0_XTC_SHIFT 21 #define VPECONF0_XTC (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT) +/* VPEConf1 fields (per VPE) */ +#define VPECONF1_NCP1_SHIFT 0 +#define VPECONF1_NCP1 (_ULCAST_(0xff) << VPECONF1_NCP1_SHIFT) +#define VPECONF1_NCP2_SHIFT 10 +#define VPECONF1_NCP2 (_ULCAST_(0xff) << VPECONF1_NCP2_SHIFT) +#define VPECONF1_NCX_SHIFT 20 +#define VPECONF1_NCX (_ULCAST_(0xff) << VPECONF1_NCX_SHIFT) + /* TCStatus fields (per TC) */ #define TCSTATUS_TASID (_ULCAST_(0xff)) #define TCSTATUS_IXMT_SHIFT 10 @@ -350,6 +361,8 @@ do { \ #define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val) #define read_vpe_c0_vpeconf0() mftc0(1, 2) #define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val) +#define read_vpe_c0_vpeconf1() mftc0(1, 3) +#define write_vpe_c0_vpeconf1(val) mttc0(1, 3, val) #define read_vpe_c0_count() mftc0(9, 0) #define write_vpe_c0_count(val) mttc0(9, 0, val) #define read_vpe_c0_status() mftc0(12, 0) diff --git a/arch/mips/include/asm/smtc.h b/arch/mips/include/asm/smtc.h index c9736fc..8935426 100644 --- a/arch/mips/include/asm/smtc.h +++ b/arch/mips/include/asm/smtc.h @@ -33,6 +33,12 @@ typedef long asiduse; #endif #endif +/* + * VPE Management information + */ + +#define MAX_SMTC_VPES MAX_SMTC_TLBS /* FIXME: May not always be true. */ + extern asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; struct mm_struct; diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 1268392..31637d8 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -102,7 +102,9 @@ asmlinkage __cpuinit void start_secondary(void) #ifdef CONFIG_MIPS_MT_SMTC /* Only do cpu_probe for first TC of CPU */ - if ((read_c0_tcbind() & TCBIND_CURTC) == 0) + if ((read_c0_tcbind() & TCBIND_CURTC) != 0) + __cpu_name[smp_processor_id()] = __cpu_name[0]; + else #endif /* CONFIG_MIPS_MT_SMTC */ cpu_probe(); cpu_report(); diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 15b5f3c..1d47843 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -86,6 +86,13 @@ struct smtc_ipi_q IPIQ[NR_CPUS]; static struct smtc_ipi_q freeIPIq; +/* + * Number of FPU contexts for each VPE + */ + +static int smtc_nconf1[MAX_SMTC_VPES]; + + /* Forward declarations */ void ipi_decode(struct smtc_ipi *); @@ -174,9 +181,9 @@ static int __init tintq(char *str) __setup("tintq=", tintq); -static int imstuckcount[2][8]; +static int imstuckcount[MAX_SMTC_VPES][8]; /* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */ -static int vpemask[2][8] = { +static int vpemask[MAX_SMTC_VPES][8] = { {0, 0, 1, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1} }; @@ -331,6 +338,22 @@ int __init smtc_build_cpu_map(int start_cpu_slot) static void smtc_tc_setup(int vpe, int tc, int cpu) { + static int cp1contexts[MAX_SMTC_VPES]; + + /* + * Make a local copy of the available FPU contexts in order + * to keep track of TCs that can have one. + */ + if (tc == 1) + { + /* + * FIXME: Multi-core SMTC hasn't been tested and the + * maximum number of VPEs may change. + */ + cp1contexts[0] = smtc_nconf1[0] - 1; + cp1contexts[1] = smtc_nconf1[1]; + } + settc(tc); write_tc_c0_tchalt(TCHALT_H); mips_ihb(); @@ -343,22 +366,29 @@ static void smtc_tc_setup(int vpe, int tc, int cpu) * an active IPI queue. */ write_tc_c0_tccontext((sizeof(struct smtc_ipi_q) * cpu) << 16); - /* Bind tc to vpe */ + + /* Bind TC to VPE. */ write_tc_c0_tcbind(vpe); + /* In general, all TCs should have the same cpu_data indications. */ memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips)); - /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */ - if (cpu_data[0].cputype == CPU_34K || - cpu_data[0].cputype == CPU_1004K) + + /* Check to see if there is a FPU context available for this TC. */ + if (!cp1contexts[vpe]) cpu_data[cpu].options &= ~MIPS_CPU_FPU; + else + cp1contexts[vpe]--; + + /* Store the TC and VPE into the cpu_data structure. */ cpu_data[cpu].vpe_id = vpe; cpu_data[cpu].tc_id = tc; - /* Multi-core SMTC hasn't been tested, but be prepared */ + + /* FIXME: Multi-core SMTC hasn't been tested, but be prepared. */ cpu_data[cpu].core = (read_vpe_c0_ebase() >> 1) & 0xff; } /* - * Tweak to get Count registes in as close a sync as possible. The + * Tweak to get Count registers synced as closely as possible. The * value seems good for 34K-class cores. */ @@ -466,6 +496,24 @@ void smtc_prepare_cpus(int cpus) smtc_configure_tlb(); for (tc = 0, vpe = 0 ; (vpe < nvpe) && (tc < ntc) ; vpe++) { + /* Get number of CP1 contexts for each VPE. */ + if (tc == 0) + { + /* + * Do not call settc() for TC0 or the FPU context + * value will be incorrect. Besides, we know that + * we are TC0 anyway. + */ + smtc_nconf1[0] = ((read_vpe_c0_vpeconf1() & + VPECONF1_NCP1) >> VPECONF1_NCP1_SHIFT); + if (nvpe == 2) + { + settc(1); + smtc_nconf1[1] = ((read_vpe_c0_vpeconf1() & + VPECONF1_NCP1) >> VPECONF1_NCP1_SHIFT); + settc(0); + } + } if (tcpervpe[vpe] == 0) continue; if (vpe != 0) @@ -479,6 +527,18 @@ void smtc_prepare_cpus(int cpus) */ if (tc != 0) { smtc_tc_setup(vpe, tc, cpu); + if (vpe != 0) { + /* + * Set MVP bit (possibly again). Do it + * here to catch CPUs that have no TCs + * bound to the VPE at reset. In that + * case, a TC must be bound to the VPE + * before we can set VPEControl[MVP] + */ + write_vpe_c0_vpeconf0( + read_vpe_c0_vpeconf0() | + VPECONF0_MVP); + } cpu++; } printk(" %d", tc); -- cgit v0.10.2 From 4bd5a5740e9cb20b63763b8b5dd04a51fba09029 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 31 Jan 2012 18:19:03 +0100 Subject: MIPS: Alchemy: use IS_ENABLED() macro Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3331/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c index 295f1a9..9996948 100644 --- a/arch/mips/alchemy/board-mtx1.c +++ b/arch/mips/alchemy/board-mtx1.c @@ -81,10 +81,10 @@ static void mtx1_power_off(void) void __init board_setup(void) { -#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +#if IS_ENABLED(CONFIG_USB_OHCI_HCD) /* Enable USB power switch */ alchemy_gpio_direction_output(204, 0); -#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ +#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */ /* Initialize sys_pinfunc */ au_writel(SYS_PF_NI2, SYS_PINFUNC); diff --git a/arch/mips/alchemy/devboards/pb1100.c b/arch/mips/alchemy/devboards/pb1100.c index cff50d0..78c77a4 100644 --- a/arch/mips/alchemy/devboards/pb1100.c +++ b/arch/mips/alchemy/devboards/pb1100.c @@ -46,7 +46,7 @@ void __init board_setup(void) alchemy_gpio1_input_enable(); udelay(100); -#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +#if IS_ENABLED(CONFIG_USB_OHCI_HCD) { u32 pin_func, sys_freqctrl, sys_clksrc; @@ -93,7 +93,7 @@ void __init board_setup(void) pin_func |= SYS_PF_USB; au_writel(pin_func, SYS_PINFUNC); } -#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ +#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */ /* Enable sys bus clock divider when IDLE state or no bus activity. */ au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); diff --git a/arch/mips/alchemy/devboards/pb1500.c b/arch/mips/alchemy/devboards/pb1500.c index e7b807b..232fee9 100644 --- a/arch/mips/alchemy/devboards/pb1500.c +++ b/arch/mips/alchemy/devboards/pb1500.c @@ -53,7 +53,7 @@ void __init board_setup(void) alchemy_gpio_direction_input(201); alchemy_gpio_direction_input(203); -#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +#if IS_ENABLED(CONFIG_USB_OHCI_HCD) /* Zero and disable FREQ2 */ sys_freqctrl = au_readl(SYS_FREQCTRL0); @@ -87,7 +87,7 @@ void __init board_setup(void) /* 2nd USB port is USB host */ pin_func |= SYS_PF_USB; au_writel(pin_func, SYS_PINFUNC); -#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ +#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */ #ifdef CONFIG_PCI { -- cgit v0.10.2 From c1d7f41cfefc0977433b5ed65c6fb71df8ee046b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 31 Jan 2012 18:19:04 +0100 Subject: MIPS: PNX833x: use IS_ENABLED() macro Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3332/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/pnx833x/stb22x/board.c b/arch/mips/pnx833x/stb22x/board.c index 644eb7c..4b328ac 100644 --- a/arch/mips/pnx833x/stb22x/board.c +++ b/arch/mips/pnx833x/stb22x/board.c @@ -91,7 +91,7 @@ void __init pnx833x_board_setup(void) pnx833x_gpio_select_function_alt(32); pnx833x_gpio_select_function_alt(33); -#if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE) +#if IS_ENABLED(CONFIG_MTD_NAND_PLATFORM) /* Setup MIU for NAND access on CS0... * * (it seems that we must also configure CS1 for reliable operation, @@ -117,7 +117,7 @@ void __init pnx833x_board_setup(void) pnx833x_gpio_select_output(5); pnx833x_gpio_write(1, 5); -#elif defined(CONFIG_MTD_CFI) || defined(CONFIG_MTD_CFI_MODULE) +#elif IS_ENABLED(CONFIG_MTD_CFI) /* Set up MIU for 16-bit NOR access on CS0 and CS1... */ -- cgit v0.10.2 From b33b44073734842ec0c75d376c40d0471d6113ff Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 31 Jan 2012 18:19:05 +0100 Subject: MIPS: TXX9: use IS_ENABLED() macro Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3334/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index ae77a79..560fe899 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -632,7 +632,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr, unsigned long size, const struct physmap_flash_data *pdata) { -#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE) +#if IS_ENABLED(CONFIG_MTD_PHYSMAP) struct resource res = { .start = addr, .end = addr + size - 1, @@ -670,8 +670,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr, void __init txx9_ndfmc_init(unsigned long baseaddr, const struct txx9ndfmc_platform_data *pdata) { -#if defined(CONFIG_MTD_NAND_TXX9NDFMC) || \ - defined(CONFIG_MTD_NAND_TXX9NDFMC_MODULE) +#if IS_ENABLED(CONFIG_MTD_NAND_TXX9NDFMC) struct resource res = { .start = baseaddr, .end = baseaddr + 0x1000 - 1, @@ -687,7 +686,7 @@ void __init txx9_ndfmc_init(unsigned long baseaddr, #endif } -#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +#if IS_ENABLED(CONFIG_LEDS_GPIO) static DEFINE_SPINLOCK(txx9_iocled_lock); #define TXX9_IOCLED_MAXLEDS 8 @@ -810,7 +809,7 @@ void __init txx9_iocled_init(unsigned long baseaddr, void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq, const struct txx9dmac_platform_data *pdata) { -#if defined(CONFIG_TXX9_DMAC) || defined(CONFIG_TXX9_DMAC_MODULE) +#if IS_ENABLED(CONFIG_TXX9_DMAC) struct resource res[] = { { .start = baseaddr, @@ -866,8 +865,7 @@ void __init txx9_aclc_init(unsigned long baseaddr, int irq, unsigned int dma_chan_out, unsigned int dma_chan_in) { -#if defined(CONFIG_SND_SOC_TXX9ACLC) || \ - defined(CONFIG_SND_SOC_TXX9ACLC_MODULE) +#if IS_ENABLED(CONFIG_SND_SOC_TXX9ACLC) unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS; struct resource res[] = { { diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c index 6567895..5ff7a95 100644 --- a/arch/mips/txx9/generic/setup_tx4939.c +++ b/arch/mips/txx9/generic/setup_tx4939.c @@ -317,7 +317,7 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask) } } -#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE) +#if IS_ENABLED(CONFIG_TC35815) static u32 tx4939_get_eth_speed(struct net_device *dev) { struct ethtool_cmd cmd; diff --git a/arch/mips/txx9/rbtx4939/setup.c b/arch/mips/txx9/rbtx4939/setup.c index 2ad8973..e15641d 100644 --- a/arch/mips/txx9/rbtx4939/setup.c +++ b/arch/mips/txx9/rbtx4939/setup.c @@ -40,8 +40,7 @@ static void __init rbtx4939_time_init(void) tx4939_time_init(0); } -#if defined(__BIG_ENDIAN) && \ - (defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)) +#if defined(__BIG_ENDIAN) && IS_ENABLED(CONFIG_SMC91X) #define HAVE_RBTX4939_IOSWAB #define IS_CE1_ADDR(addr) \ ((((unsigned long)(addr) - IO_BASE) & 0xfff00000) == TXX9_CE(1)) @@ -187,7 +186,7 @@ static void __init rbtx4939_update_ioc_pen(void) #define RBTX4939_MAX_7SEGLEDS 8 -#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +#if IS_ENABLED(CONFIG_LEDS_CLASS) static u8 led_val[RBTX4939_MAX_7SEGLEDS]; struct rbtx4939_led_data { struct led_classdev cdev; @@ -263,7 +262,7 @@ static inline void rbtx4939_led_setup(void) static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val) { -#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +#if IS_ENABLED(CONFIG_LEDS_CLASS) unsigned long flags; local_irq_save(flags); /* bit7: reserved for LED class */ @@ -287,7 +286,7 @@ static void rbtx4939_7segled_putc(unsigned int pos, unsigned char val) __rbtx4939_7segled_putc(pos, val); } -#if defined(CONFIG_MTD_RBTX4939) || defined(CONFIG_MTD_RBTX4939_MODULE) +#if IS_ENABLED(CONFIG_MTD_RBTX4939) /* special mapping for boot rom */ static unsigned long rbtx4939_flash_fixup_ofs(unsigned long ofs) { @@ -463,7 +462,7 @@ static void __init rbtx4939_device_init(void) .flags = SMC91X_USE_16BIT, }; struct platform_device *pdev; -#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE) +#if IS_ENABLED(CONFIG_TC35815) int i, j; unsigned char ethaddr[2][6]; u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f; -- cgit v0.10.2 From dbebd6b1c50f564c1eaac890ee1bebfbde5d9318 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 31 Jan 2012 18:19:06 +0100 Subject: MIPS: TX49XX: use IS_ENABLED() Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3335/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-tx49xx/mangle-port.h b/arch/mips/include/asm/mach-tx49xx/mangle-port.h index 5e6912f..490867b 100644 --- a/arch/mips/include/asm/mach-tx49xx/mangle-port.h +++ b/arch/mips/include/asm/mach-tx49xx/mangle-port.h @@ -9,7 +9,7 @@ #define ioswabb(a, x) (x) #define __mem_ioswabb(a, x) (x) #if defined(CONFIG_TOSHIBA_RBTX4939) && \ - (defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)) && \ + IS_ENABLED(CONFIG_SMC91X) && \ defined(__BIG_ENDIAN) #define NEEDS_TXX9_IOSWABW extern u16 (*ioswabw)(volatile u16 *a, u16 x); -- cgit v0.10.2 From baf69e275317602bb1f2c87e40d1e03c90b31e38 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 31 Jan 2012 18:19:07 +0100 Subject: MIPS: DEC: use IS_ENABLED() Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3333/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c index e95ff30..8c62316 100644 --- a/arch/mips/dec/prom/memory.c +++ b/arch/mips/dec/prom/memory.c @@ -101,7 +101,7 @@ void __init prom_free_prom_memory(void) * the first page reserved for the exception handlers. */ -#if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE) +#if IS_ENABLED(CONFIG_DECLANCE) /* * Leave 128 KB reserved for Lance memory for * IOASIC DECstations. -- cgit v0.10.2 From a551fafba2bd3c395bf56e4fafc828a13e994588 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 31 Jan 2012 18:19:08 +0100 Subject: MIPS: loongson: use IS_ENABLED() Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3336/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h index 1e29b9d..06367c3 100644 --- a/arch/mips/include/asm/mach-loongson/loongson.h +++ b/arch/mips/include/asm/mach-loongson/loongson.h @@ -14,6 +14,7 @@ #include #include #include +#include /* loongson internal northbridge initialization */ extern void bonito_irq_init(void); @@ -66,7 +67,7 @@ extern int mach_i8259_irq(void); #include static inline void do_perfcnt_IRQ(void) { -#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) +#if IS_ENABLED(CONFIG_OPROFILE) do_IRQ(LOONGSON2_PERFCNT_IRQ); #endif } -- cgit v0.10.2 From a6196bab646537f594ef269bf9e1c92fe0e165a6 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Thu, 17 Nov 2011 23:43:40 +0100 Subject: MIPS: Alchemy: Use kmemdup rather than duplicating its implementation The semantic patch that makes this change is available in scripts/coccinelle/api/memdup.cocci. Signed-off-by: Thomas Meyer Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/3058/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index 95cb911..c0f3ce6 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -334,13 +334,12 @@ static void __init alchemy_setup_macs(int ctype) if (alchemy_get_macs(ctype) < 1) return; - macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); + macres = kmemdup(au1xxx_eth0_resources[ctype], + sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); if (!macres) { printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n"); return; } - memcpy(macres, au1xxx_eth0_resources[ctype], - sizeof(struct resource) * MAC_RES_COUNT); au1xxx_eth0_device.resource = macres; i = prom_get_ethernet_addr(ethaddr); @@ -356,13 +355,12 @@ static void __init alchemy_setup_macs(int ctype) if (alchemy_get_macs(ctype) < 2) return; - macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); + macres = kmemdup(au1xxx_eth1_resources[ctype], + sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); if (!macres) { printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n"); return; } - memcpy(macres, au1xxx_eth1_resources[ctype], - sizeof(struct resource) * MAC_RES_COUNT); au1xxx_eth1_device.resource = macres; ethaddr[5] += 1; /* next addr for 2nd MAC */ -- cgit v0.10.2 From f7257d38ebb1bd3b8f80662c67ec7d502ac67421 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 4 Jun 2012 04:42:04 +0100 Subject: MIPS: PCI: Add missing __devinit attributions to fixup functions. Signed-off-by: Ralf Baechle diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c index 9553b14..3e7ce65 100644 --- a/arch/mips/pci/fixup-cobalt.c +++ b/arch/mips/pci/fixup-cobalt.c @@ -37,7 +37,7 @@ #define VIA_COBALT_BRD_ID_REG 0x94 #define VIA_COBALT_BRD_REG_to_ID(reg) ((unsigned char)(reg) >> 4) -static void qube_raq_galileo_early_fixup(struct pci_dev *dev) +static void __devinit qube_raq_galileo_early_fixup(struct pci_dev *dev) { if (dev->devfn == PCI_DEVFN(0, 0) && (dev->class >> 8) == PCI_CLASS_MEMORY_OTHER) { @@ -51,7 +51,7 @@ static void qube_raq_galileo_early_fixup(struct pci_dev *dev) DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111, qube_raq_galileo_early_fixup); -static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev) +static void __devinit qube_raq_via_bmIDE_fixup(struct pci_dev *dev) { unsigned short cfgword; unsigned char lt; @@ -74,7 +74,7 @@ static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, qube_raq_via_bmIDE_fixup); -static void qube_raq_galileo_fixup(struct pci_dev *dev) +static void __devinit qube_raq_galileo_fixup(struct pci_dev *dev) { if (dev->devfn != PCI_DEVFN(0, 0)) return; @@ -129,7 +129,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111, int cobalt_board_id; -static void qube_raq_via_board_id_fixup(struct pci_dev *dev) +static void __devinit qube_raq_via_board_id_fixup(struct pci_dev *dev) { u8 id; int retval; diff --git a/arch/mips/pci/fixup-rc32434.c b/arch/mips/pci/fixup-rc32434.c index 3d86823..76bb1be 100644 --- a/arch/mips/pci/fixup-rc32434.c +++ b/arch/mips/pci/fixup-rc32434.c @@ -47,7 +47,7 @@ int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) return irq + GROUP4_IRQ_BASE + 4; } -static void rc32434_pci_early_fixup(struct pci_dev *dev) +static void __devinit rc32434_pci_early_fixup(struct pci_dev *dev) { if (PCI_SLOT(dev->devfn) == 6 && dev->bus->number == 0) { /* disable prefetched memory range */ diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index 822ae17..097239b 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c @@ -411,7 +411,7 @@ struct pci_ops bcm63xx_cb_ops = { * only one IO window, so it cannot be shared by PCI and cardbus, use * fixup to choose and detect unhandled configuration */ -static void bcm63xx_fixup(struct pci_dev *dev) +static void __devinit bcm63xx_fixup(struct pci_dev *dev) { static int io_window = -1; int i, found, new_io_window; diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 64eb71b..bab4953 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c @@ -304,7 +304,7 @@ static void __devinit quirk_slc90e66_bridge(struct pci_dev *dev) smsc_fdc37m81x_config_end(); } -static void quirk_slc90e66_ide(struct pci_dev *dev) +static void __devinit quirk_slc90e66_ide(struct pci_dev *dev) { unsigned char dat; int regs[2] = {0x41, 0x43}; @@ -339,7 +339,7 @@ static void quirk_slc90e66_ide(struct pci_dev *dev) } #endif /* CONFIG_TOSHIBA_FPCIB0 */ -static void tc35815_fixup(struct pci_dev *dev) +static void __devinit tc35815_fixup(struct pci_dev *dev) { /* This device may have PM registers but not they are not suported. */ if (dev->pm_cap) { @@ -348,7 +348,7 @@ static void tc35815_fixup(struct pci_dev *dev) } } -static void final_fixup(struct pci_dev *dev) +static void __devinit final_fixup(struct pci_dev *dev) { unsigned char bist; -- cgit v0.10.2 From 497e5ff03f58583ada469db8a1aa34eced9dd63e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 6 Jun 2012 11:14:08 +0100 Subject: MIPS: Malta: Move PIIX4 PCI fixup to where it belongs. Signed-off-by: Ralf Baechle diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c index 70073c9..819622f 100644 --- a/arch/mips/pci/fixup-malta.c +++ b/arch/mips/pci/fixup-malta.c @@ -101,3 +101,17 @@ static void __devinit malta_piix_func1_fixup(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, malta_piix_func1_fixup); + +/* Enable PCI 2.1 compatibility in PIIX4 */ +static void __devinit quirk_dlcsetup(struct pci_dev *dev) +{ + u8 odlc, ndlc; + + (void) pci_read_config_byte(dev, 0x82, &odlc); + /* Enable passive releases and delayed transaction */ + ndlc = odlc | 7; + (void) pci_write_config_byte(dev, 0x82, ndlc); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, + quirk_dlcsetup); -- cgit v0.10.2 From 914f848077fb2ec0ec9c041af9ae1101ed0320f3 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 6 Jun 2012 14:50:17 -0700 Subject: MIPS: Octeon: Implement Octeon specific __copy_user_inatomic The generic version seems to prefetch past the end of memory. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3929/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S index 88e0cdd..db478db 100644 --- a/arch/mips/cavium-octeon/octeon-memcpy.S +++ b/arch/mips/cavium-octeon/octeon-memcpy.S @@ -164,6 +164,14 @@ .set noat /* + * t7 is used as a flag to note inatomic mode. + */ +LEAF(__copy_user_inatomic) + b __copy_user_common + li t7, 1 + END(__copy_user_inatomic) + +/* * A combined memcpy/__copy_user * __copy_user sets len to 0 for success; else to an upper bound of * the number of uncopied bytes. @@ -174,6 +182,8 @@ LEAF(memcpy) /* a0=dst a1=src a2=len */ move v0, dst /* return value */ __memcpy: FEXPORT(__copy_user) + li t7, 0 /* not inatomic */ +__copy_user_common: /* * Note: dst & src may be unaligned, len may be 0 * Temps @@ -412,7 +422,6 @@ l_exc_copy: * Assumes src < THREAD_BUADDR($28) */ LOAD t0, TI_TASK($28) - nop LOAD t0, THREAD_BUADDR(t0) 1: EXC( lb t1, 0(src), l_exc) @@ -422,10 +431,9 @@ EXC( lb t1, 0(src), l_exc) ADD dst, dst, 1 l_exc: LOAD t0, TI_TASK($28) - nop LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address - nop SUB len, AT, t0 # len number of uncopied bytes + bnez t7, 2f /* Skip the zeroing out part if inatomic */ /* * Here's where we rely on src and dst being incremented in tandem, * See (3) above. @@ -443,7 +451,7 @@ l_exc: ADD dst, dst, 1 bnez src, 1b SUB src, src, 1 - jr ra +2: jr ra nop -- cgit v0.10.2 From bb0757ebb929d5d6ba484b4313976847285ba280 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 6 Jun 2012 23:00:31 +0100 Subject: MIPS: Unify memcpy.S and memcpy-inatomic.S We can save the 451 lines of code that comprise memcpy-inatomic.S at the expense of a single instruction in the memcpy prolog. We also use an additional register (t6), so this may cause increased register pressure in some places as well. But I think the reduced maintenance burden, of not having two nearly identical implementations, makes it worth it. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index 653a412..3b92efe 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h @@ -687,7 +687,7 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n); __MODULE_JAL(__copy_user) \ : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \ : \ - : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31", \ + : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", \ DADDI_SCRATCH, "memory"); \ __cu_len_r; \ }) @@ -797,7 +797,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); ".set\treorder" \ : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \ : \ - : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31", \ + : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", \ DADDI_SCRATCH, "memory"); \ __cu_len_r; \ }) @@ -820,7 +820,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n); ".set\treorder" \ : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \ : \ - : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31", \ + : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", \ DADDI_SCRATCH, "memory"); \ __cu_len_r; \ }) diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 2a7c74f..399a50a 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for MIPS-specific library files.. # -lib-y += csum_partial.o delay.o memcpy.o memcpy-inatomic.o memset.o \ +lib-y += csum_partial.o delay.o memcpy.o memset.o \ strlen_user.o strncpy_user.o strnlen_user.o uncached.o obj-y += iomap.o diff --git a/arch/mips/lib/memcpy-inatomic.S b/arch/mips/lib/memcpy-inatomic.S deleted file mode 100644 index 68853a0..0000000 --- a/arch/mips/lib/memcpy-inatomic.S +++ /dev/null @@ -1,451 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Unified implementation of memcpy, memmove and the __copy_user backend. - * - * Copyright (C) 1998, 99, 2000, 01, 2002 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc. - * Copyright (C) 2002 Broadcom, Inc. - * memcpy/copy_user author: Mark Vandevoorde - * Copyright (C) 2007 Maciej W. Rozycki - * - * Mnemonic names for arguments to memcpy/__copy_user - */ - -/* - * Hack to resolve longstanding prefetch issue - * - * Prefetching may be fatal on some systems if we're prefetching beyond the - * end of memory on some systems. It's also a seriously bad idea on non - * dma-coherent systems. - */ -#ifdef CONFIG_DMA_NONCOHERENT -#undef CONFIG_CPU_HAS_PREFETCH -#endif -#ifdef CONFIG_MIPS_MALTA -#undef CONFIG_CPU_HAS_PREFETCH -#endif - -#include -#include -#include - -#define dst a0 -#define src a1 -#define len a2 - -/* - * Spec - * - * memcpy copies len bytes from src to dst and sets v0 to dst. - * It assumes that - * - src and dst don't overlap - * - src is readable - * - dst is writable - * memcpy uses the standard calling convention - * - * __copy_user copies up to len bytes from src to dst and sets a2 (len) to - * the number of uncopied bytes due to an exception caused by a read or write. - * __copy_user assumes that src and dst don't overlap, and that the call is - * implementing one of the following: - * copy_to_user - * - src is readable (no exceptions when reading src) - * copy_from_user - * - dst is writable (no exceptions when writing dst) - * __copy_user uses a non-standard calling convention; see - * include/asm-mips/uaccess.h - * - * When an exception happens on a load, the handler must - # ensure that all of the destination buffer is overwritten to prevent - * leaking information to user mode programs. - */ - -/* - * Implementation - */ - -/* - * The exception handler for loads requires that: - * 1- AT contain the address of the byte just past the end of the source - * of the copy, - * 2- src_entry <= src < AT, and - * 3- (dst - src) == (dst_entry - src_entry), - * The _entry suffix denotes values when __copy_user was called. - * - * (1) is set up up by uaccess.h and maintained by not writing AT in copy_user - * (2) is met by incrementing src by the number of bytes copied - * (3) is met by not doing loads between a pair of increments of dst and src - * - * The exception handlers for stores adjust len (if necessary) and return. - * These handlers do not need to overwrite any data. - * - * For __rmemcpy and memmove an exception is always a kernel bug, therefore - * they're not protected. - */ - -#define EXC(inst_reg,addr,handler) \ -9: inst_reg, addr; \ - .section __ex_table,"a"; \ - PTR 9b, handler; \ - .previous - -/* - * Only on the 64-bit kernel we can made use of 64-bit registers. - */ -#ifdef CONFIG_64BIT -#define USE_DOUBLE -#endif - -#ifdef USE_DOUBLE - -#define LOAD ld -#define LOADL ldl -#define LOADR ldr -#define STOREL sdl -#define STORER sdr -#define STORE sd -#define ADD daddu -#define SUB dsubu -#define SRL dsrl -#define SRA dsra -#define SLL dsll -#define SLLV dsllv -#define SRLV dsrlv -#define NBYTES 8 -#define LOG_NBYTES 3 - -/* - * As we are sharing code base with the mips32 tree (which use the o32 ABI - * register definitions). We need to redefine the register definitions from - * the n64 ABI register naming to the o32 ABI register naming. - */ -#undef t0 -#undef t1 -#undef t2 -#undef t3 -#define t0 $8 -#define t1 $9 -#define t2 $10 -#define t3 $11 -#define t4 $12 -#define t5 $13 -#define t6 $14 -#define t7 $15 - -#else - -#define LOAD lw -#define LOADL lwl -#define LOADR lwr -#define STOREL swl -#define STORER swr -#define STORE sw -#define ADD addu -#define SUB subu -#define SRL srl -#define SLL sll -#define SRA sra -#define SLLV sllv -#define SRLV srlv -#define NBYTES 4 -#define LOG_NBYTES 2 - -#endif /* USE_DOUBLE */ - -#ifdef CONFIG_CPU_LITTLE_ENDIAN -#define LDFIRST LOADR -#define LDREST LOADL -#define STFIRST STORER -#define STREST STOREL -#define SHIFT_DISCARD SLLV -#else -#define LDFIRST LOADL -#define LDREST LOADR -#define STFIRST STOREL -#define STREST STORER -#define SHIFT_DISCARD SRLV -#endif - -#define FIRST(unit) ((unit)*NBYTES) -#define REST(unit) (FIRST(unit)+NBYTES-1) -#define UNIT(unit) FIRST(unit) - -#define ADDRMASK (NBYTES-1) - - .text - .set noreorder -#ifndef CONFIG_CPU_DADDI_WORKAROUNDS - .set noat -#else - .set at=v1 -#endif - -/* - * A combined memcpy/__copy_user - * __copy_user sets len to 0 for success; else to an upper bound of - * the number of uncopied bytes. - * memcpy sets v0 to dst. - */ - .align 5 -LEAF(__copy_user_inatomic) - /* - * Note: dst & src may be unaligned, len may be 0 - * Temps - */ -#define rem t8 - - /* - * The "issue break"s below are very approximate. - * Issue delays for dcache fills will perturb the schedule, as will - * load queue full replay traps, etc. - * - * If len < NBYTES use byte operations. - */ - PREF( 0, 0(src) ) - PREF( 1, 0(dst) ) - sltu t2, len, NBYTES - and t1, dst, ADDRMASK - PREF( 0, 1*32(src) ) - PREF( 1, 1*32(dst) ) - bnez t2, .Lcopy_bytes_checklen - and t0, src, ADDRMASK - PREF( 0, 2*32(src) ) - PREF( 1, 2*32(dst) ) - bnez t1, .Ldst_unaligned - nop - bnez t0, .Lsrc_unaligned_dst_aligned - /* - * use delay slot for fall-through - * src and dst are aligned; need to compute rem - */ -.Lboth_aligned: - SRL t0, len, LOG_NBYTES+3 # +3 for 8 units/iter - beqz t0, .Lcleanup_both_aligned # len < 8*NBYTES - and rem, len, (8*NBYTES-1) # rem = len % (8*NBYTES) - PREF( 0, 3*32(src) ) - PREF( 1, 3*32(dst) ) - .align 4 -1: -EXC( LOAD t0, UNIT(0)(src), .Ll_exc) -EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy) -EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy) -EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy) - SUB len, len, 8*NBYTES -EXC( LOAD t4, UNIT(4)(src), .Ll_exc_copy) -EXC( LOAD t7, UNIT(5)(src), .Ll_exc_copy) - STORE t0, UNIT(0)(dst) - STORE t1, UNIT(1)(dst) -EXC( LOAD t0, UNIT(6)(src), .Ll_exc_copy) -EXC( LOAD t1, UNIT(7)(src), .Ll_exc_copy) - ADD src, src, 8*NBYTES - ADD dst, dst, 8*NBYTES - STORE t2, UNIT(-6)(dst) - STORE t3, UNIT(-5)(dst) - STORE t4, UNIT(-4)(dst) - STORE t7, UNIT(-3)(dst) - STORE t0, UNIT(-2)(dst) - STORE t1, UNIT(-1)(dst) - PREF( 0, 8*32(src) ) - PREF( 1, 8*32(dst) ) - bne len, rem, 1b - nop - - /* - * len == rem == the number of bytes left to copy < 8*NBYTES - */ -.Lcleanup_both_aligned: - beqz len, .Ldone - sltu t0, len, 4*NBYTES - bnez t0, .Lless_than_4units - and rem, len, (NBYTES-1) # rem = len % NBYTES - /* - * len >= 4*NBYTES - */ -EXC( LOAD t0, UNIT(0)(src), .Ll_exc) -EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy) -EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy) -EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy) - SUB len, len, 4*NBYTES - ADD src, src, 4*NBYTES - STORE t0, UNIT(0)(dst) - STORE t1, UNIT(1)(dst) - STORE t2, UNIT(2)(dst) - STORE t3, UNIT(3)(dst) - .set reorder /* DADDI_WAR */ - ADD dst, dst, 4*NBYTES - beqz len, .Ldone - .set noreorder -.Lless_than_4units: - /* - * rem = len % NBYTES - */ - beq rem, len, .Lcopy_bytes - nop -1: -EXC( LOAD t0, 0(src), .Ll_exc) - ADD src, src, NBYTES - SUB len, len, NBYTES - STORE t0, 0(dst) - .set reorder /* DADDI_WAR */ - ADD dst, dst, NBYTES - bne rem, len, 1b - .set noreorder - - /* - * src and dst are aligned, need to copy rem bytes (rem < NBYTES) - * A loop would do only a byte at a time with possible branch - * mispredicts. Can't do an explicit LOAD dst,mask,or,STORE - * because can't assume read-access to dst. Instead, use - * STREST dst, which doesn't require read access to dst. - * - * This code should perform better than a simple loop on modern, - * wide-issue mips processors because the code has fewer branches and - * more instruction-level parallelism. - */ -#define bits t2 - beqz len, .Ldone - ADD t1, dst, len # t1 is just past last byte of dst - li bits, 8*NBYTES - SLL rem, len, 3 # rem = number of bits to keep -EXC( LOAD t0, 0(src), .Ll_exc) - SUB bits, bits, rem # bits = number of bits to discard - SHIFT_DISCARD t0, t0, bits - STREST t0, -1(t1) - jr ra - move len, zero -.Ldst_unaligned: - /* - * dst is unaligned - * t0 = src & ADDRMASK - * t1 = dst & ADDRMASK; T1 > 0 - * len >= NBYTES - * - * Copy enough bytes to align dst - * Set match = (src and dst have same alignment) - */ -#define match rem -EXC( LDFIRST t3, FIRST(0)(src), .Ll_exc) - ADD t2, zero, NBYTES -EXC( LDREST t3, REST(0)(src), .Ll_exc_copy) - SUB t2, t2, t1 # t2 = number of bytes copied - xor match, t0, t1 - STFIRST t3, FIRST(0)(dst) - beq len, t2, .Ldone - SUB len, len, t2 - ADD dst, dst, t2 - beqz match, .Lboth_aligned - ADD src, src, t2 - -.Lsrc_unaligned_dst_aligned: - SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter - PREF( 0, 3*32(src) ) - beqz t0, .Lcleanup_src_unaligned - and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES - PREF( 1, 3*32(dst) ) -1: -/* - * Avoid consecutive LD*'s to the same register since some mips - * implementations can't issue them in the same cycle. - * It's OK to load FIRST(N+1) before REST(N) because the two addresses - * are to the same unit (unless src is aligned, but it's not). - */ -EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc) -EXC( LDFIRST t1, FIRST(1)(src), .Ll_exc_copy) - SUB len, len, 4*NBYTES -EXC( LDREST t0, REST(0)(src), .Ll_exc_copy) -EXC( LDREST t1, REST(1)(src), .Ll_exc_copy) -EXC( LDFIRST t2, FIRST(2)(src), .Ll_exc_copy) -EXC( LDFIRST t3, FIRST(3)(src), .Ll_exc_copy) -EXC( LDREST t2, REST(2)(src), .Ll_exc_copy) -EXC( LDREST t3, REST(3)(src), .Ll_exc_copy) - PREF( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed) - ADD src, src, 4*NBYTES -#ifdef CONFIG_CPU_SB1 - nop # improves slotting -#endif - STORE t0, UNIT(0)(dst) - STORE t1, UNIT(1)(dst) - STORE t2, UNIT(2)(dst) - STORE t3, UNIT(3)(dst) - PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed) - .set reorder /* DADDI_WAR */ - ADD dst, dst, 4*NBYTES - bne len, rem, 1b - .set noreorder - -.Lcleanup_src_unaligned: - beqz len, .Ldone - and rem, len, NBYTES-1 # rem = len % NBYTES - beq rem, len, .Lcopy_bytes - nop -1: -EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc) -EXC( LDREST t0, REST(0)(src), .Ll_exc_copy) - ADD src, src, NBYTES - SUB len, len, NBYTES - STORE t0, 0(dst) - .set reorder /* DADDI_WAR */ - ADD dst, dst, NBYTES - bne len, rem, 1b - .set noreorder - -.Lcopy_bytes_checklen: - beqz len, .Ldone - nop -.Lcopy_bytes: - /* 0 < len < NBYTES */ -#define COPY_BYTE(N) \ -EXC( lb t0, N(src), .Ll_exc); \ - SUB len, len, 1; \ - beqz len, .Ldone; \ - sb t0, N(dst) - - COPY_BYTE(0) - COPY_BYTE(1) -#ifdef USE_DOUBLE - COPY_BYTE(2) - COPY_BYTE(3) - COPY_BYTE(4) - COPY_BYTE(5) -#endif -EXC( lb t0, NBYTES-2(src), .Ll_exc) - SUB len, len, 1 - jr ra - sb t0, NBYTES-2(dst) -.Ldone: - jr ra - nop - END(__copy_user_inatomic) - -.Ll_exc_copy: - /* - * Copy bytes from src until faulting load address (or until a - * lb faults) - * - * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28) - * may be more than a byte beyond the last address. - * Hence, the lb below may get an exception. - * - * Assumes src < THREAD_BUADDR($28) - */ - LOAD t0, TI_TASK($28) - nop - LOAD t0, THREAD_BUADDR(t0) -1: -EXC( lb t1, 0(src), .Ll_exc) - ADD src, src, 1 - sb t1, 0(dst) # can't fault -- we're copy_from_user - .set reorder /* DADDI_WAR */ - ADD dst, dst, 1 - bne src, t0, 1b - .set noreorder -.Ll_exc: - LOAD t0, TI_TASK($28) - nop - LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address - nop - SUB len, AT, t0 # len number of uncopied bytes - jr ra - nop diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S index 56a1f85..65192c0 100644 --- a/arch/mips/lib/memcpy.S +++ b/arch/mips/lib/memcpy.S @@ -183,6 +183,14 @@ #endif /* + * t6 is used as a flag to note inatomic mode. + */ +LEAF(__copy_user_inatomic) + b __copy_user_common + li t6, 1 + END(__copy_user_inatomic) + +/* * A combined memcpy/__copy_user * __copy_user sets len to 0 for success; else to an upper bound of * the number of uncopied bytes. @@ -193,6 +201,8 @@ LEAF(memcpy) /* a0=dst a1=src a2=len */ move v0, dst /* return value */ .L__memcpy: FEXPORT(__copy_user) + li t6, 0 /* not inatomic */ +__copy_user_common: /* * Note: dst & src may be unaligned, len may be 0 * Temps @@ -458,6 +468,7 @@ EXC( lb t1, 0(src), .Ll_exc) LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address nop SUB len, AT, t0 # len number of uncopied bytes + bnez t6, .Ldone /* Skip the zeroing part if inatomic */ /* * Here's where we rely on src and dst being incremented in tandem, * See (3) above. -- cgit v0.10.2 From 71a1c776d51a12d064d2b824753d259b0f5050e7 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Tue, 19 Jun 2012 19:59:29 +0100 Subject: MIPS: Fixup ordering of micro assembler instructions. A number of new instructions have been added to the micro assembler causing the list to no longer be in alphabetical order. This patch fixes up the name ordering. Signed-off-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3789/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index 440a21d..3d9f75f 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h @@ -6,6 +6,7 @@ * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer * Copyright (C) 2005 Maciej W. Rozycki * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2012 MIPS Technologies, Inc. */ #include @@ -62,8 +63,10 @@ void __uasminit uasm_i##op(u32 **buf, unsigned int a, signed int b) Ip_u2u1s3(_addiu); Ip_u3u1u2(_addu); -Ip_u2u1u3(_andi); Ip_u3u1u2(_and); +Ip_u2u1u3(_andi); +Ip_u1u2s3(_bbit0); +Ip_u1u2s3(_bbit1); Ip_u1u2s3(_beq); Ip_u1u2s3(_beql); Ip_u1s2(_bgez); @@ -72,55 +75,54 @@ Ip_u1s2(_bltz); Ip_u1s2(_bltzl); Ip_u1u2s3(_bne); Ip_u2s3u1(_cache); -Ip_u1u2u3(_dmfc0); -Ip_u1u2u3(_dmtc0); Ip_u2u1s3(_daddiu); Ip_u3u1u2(_daddu); +Ip_u2u1msbu3(_dins); +Ip_u2u1msbu3(_dinsm); +Ip_u1u2u3(_dmfc0); +Ip_u1u2u3(_dmtc0); +Ip_u2u1u3(_drotr); +Ip_u2u1u3(_drotr32); Ip_u2u1u3(_dsll); Ip_u2u1u3(_dsll32); Ip_u2u1u3(_dsra); Ip_u2u1u3(_dsrl); Ip_u2u1u3(_dsrl32); -Ip_u2u1u3(_drotr); -Ip_u2u1u3(_drotr32); Ip_u3u1u2(_dsubu); Ip_0(_eret); Ip_u1(_j); Ip_u1(_jal); Ip_u1(_jr); Ip_u2s3u1(_ld); +Ip_u3u1u2(_ldx); Ip_u2s3u1(_ll); Ip_u2s3u1(_lld); Ip_u1s2(_lui); Ip_u2s3u1(_lw); +Ip_u3u1u2(_lwx); Ip_u1u2u3(_mfc0); Ip_u1u2u3(_mtc0); -Ip_u2u1u3(_ori); Ip_u3u1u2(_or); +Ip_u2u1u3(_ori); Ip_u2s3u1(_pref); Ip_0(_rfe); +Ip_u2u1u3(_rotr); Ip_u2s3u1(_sc); Ip_u2s3u1(_scd); Ip_u2s3u1(_sd); Ip_u2u1u3(_sll); Ip_u2u1u3(_sra); Ip_u2u1u3(_srl); -Ip_u2u1u3(_rotr); Ip_u3u1u2(_subu); Ip_u2s3u1(_sw); +Ip_u1(_syscall); Ip_0(_tlbp); Ip_0(_tlbr); Ip_0(_tlbwi); Ip_0(_tlbwr); Ip_u3u1u2(_xor); Ip_u2u1u3(_xori); -Ip_u2u1msbu3(_dins); -Ip_u2u1msbu3(_dinsm); -Ip_u1(_syscall); -Ip_u1u2s3(_bbit0); -Ip_u1u2s3(_bbit1); -Ip_u3u1u2(_lwx); -Ip_u3u1u2(_ldx); + /* Handle labels. */ struct uasm_label { @@ -145,37 +147,37 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ /* convenience macros for instructions */ #ifdef CONFIG_64BIT +# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val) +# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd) +# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off) # define UASM_i_LW(buf, rs, rt, off) uasm_i_ld(buf, rs, rt, off) -# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off) +# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd) +# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd) +# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd) +# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_drotr(buf, rs, rt, sh) +# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off) # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh) # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh) # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh) # define UASM_i_SRL_SAFE(buf, rs, rt, sh) uasm_i_dsrl_safe(buf, rs, rt, sh) -# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_drotr(buf, rs, rt, sh) -# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd) -# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd) -# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val) -# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd) # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd) -# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off) -# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off) -# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd) +# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off) #else +# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val) +# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd) +# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off) # define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off) -# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off) +# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd) +# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd) +# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd) +# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_rotr(buf, rs, rt, sh) +# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off) # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh) # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh) # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh) # define UASM_i_SRL_SAFE(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh) -# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_rotr(buf, rs, rt, sh) -# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd) -# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd) -# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val) -# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd) # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd) -# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off) -# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off) -# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd) +# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off) #endif #define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off) @@ -183,19 +185,10 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \ #define uasm_i_beqzl(buf, rs, off) uasm_i_beql(buf, rs, 0, off) #define uasm_i_bnez(buf, rs, off) uasm_i_bne(buf, rs, 0, off) #define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off) +#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3) #define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b) #define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0) #define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1) -#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3) - -static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1, - unsigned int a2, unsigned int a3) -{ - if (a3 < 32) - uasm_i_dsrl(p, a1, a2, a3); - else - uasm_i_dsrl32(p, a1, a2, a3 - 32); -} static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1, unsigned int a2, unsigned int a3) @@ -215,6 +208,15 @@ static inline void uasm_i_dsll_safe(u32 **p, unsigned int a1, uasm_i_dsll32(p, a1, a2, a3 - 32); } +static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1, + unsigned int a2, unsigned int a3) +{ + if (a3 < 32) + uasm_i_dsrl(p, a1, a2, a3); + else + uasm_i_dsrl32(p, a1, a2, a3 - 32); +} + /* Handle relocations. */ struct uasm_reloc { u32 *addr; @@ -234,16 +236,16 @@ void uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, int uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr); /* Convenience functions for labeled branches. */ -void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_b(u32 **p, struct uasm_reloc **r, int lid); +void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg, + unsigned int bit, int lid); +void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, + unsigned int bit, int lid); void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); +void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); +void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); +void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, unsigned int reg2, int lid); void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); -void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg, - unsigned int bit, int lid); -void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg, - unsigned int bit, int lid); diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 5fa1851..64a28e8 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -58,18 +58,16 @@ enum fields { enum opcode { insn_invalid, - insn_addu, insn_addiu, insn_and, insn_andi, insn_beq, - insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, - insn_bne, insn_cache, insn_daddu, insn_daddiu, insn_dmfc0, - insn_dmtc0, insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, - insn_dsrl32, insn_drotr, insn_drotr32, insn_dsubu, insn_eret, - insn_j, insn_jal, insn_jr, insn_ld, insn_ll, insn_lld, - insn_lui, insn_lw, insn_mfc0, insn_mtc0, insn_or, insn_ori, - insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, - insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp, + insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1, + insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, + insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm, + insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll, + insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret, + insn_j, insn_jal, insn_jr, insn_ld, insn_ldx, insn_ll, insn_lld, + insn_lui, insn_lw, insn_lwx, insn_mfc0, insn_mtc0, insn_or, insn_ori, + insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll, + insn_sra, insn_srl, insn_subu, insn_sw, insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, - insn_dins, insn_dinsm, insn_syscall, insn_bbit0, insn_bbit1, - insn_lwx, insn_ldx }; struct insn { @@ -90,65 +88,65 @@ struct insn { static struct insn insn_table[] __uasminitdata = { { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD }, - { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD }, { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, - { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, + { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD }, + { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, + { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, - { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM }, + { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM }, - { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM }, + { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM }, { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM }, + { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM }, { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, { insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, + { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE }, + { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET}, { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET}, - { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE }, + { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE }, + { insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE }, { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE }, + { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE }, { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE }, - { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE }, { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE }, - { insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE }, - { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE }, + { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE }, { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD }, { insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 }, - { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM }, + { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM }, { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS }, { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, - { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD }, { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM }, { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET}, { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET}, - { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD }, { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, + { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD }, { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 }, - { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE }, { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE }, { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE }, { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE }, - { insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE }, { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD }, { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, + { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 }, { insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 }, { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 }, { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 }, - { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, - { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE }, - { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE }, - { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM}, - { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, - { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, - { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, - { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD }, + { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, { insn_invalid, 0, 0 } }; -- cgit v0.10.2 From 1471d41a5bdfdf83ed1e5c2148a9763e64b1f53b Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Thu, 29 Mar 2012 19:17:01 +0200 Subject: MTD: NAND: JZ4740: Multi-bank support with autodetection The platform data can now specify which external memory banks to probe for NAND chips, and in which order. Banks that contain a NAND are used and the other banks are freed. Squashed version of development done in jz-2.6.38 branch. Original patch by Lars-Peter Clausen with some bug fixes from me. Thanks to Paul Cercueil for the initial autodetection patch. Signed-off-by: Maarten ter Huurne Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3560/ Acked-By: David Woodhouse Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h index bb5b9a4..986982d 100644 --- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h +++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h @@ -19,6 +19,8 @@ #include #include +#define JZ_NAND_NUM_BANKS 4 + struct jz_nand_platform_data { int num_partitions; struct mtd_partition *partitions; @@ -27,6 +29,8 @@ struct jz_nand_platform_data { unsigned int busy_gpio; + unsigned char banks[JZ_NAND_NUM_BANKS]; + void (*ident_callback)(struct platform_device *, struct nand_chip *, struct mtd_partition **, int *num_partitions); }; diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c index 10929e2..e342ed4 100644 --- a/arch/mips/jz4740/platform.c +++ b/arch/mips/jz4740/platform.c @@ -157,11 +157,29 @@ static struct resource jz4740_nand_resources[] = { .flags = IORESOURCE_MEM, }, { - .name = "bank", + .name = "bank1", .start = 0x18000000, .end = 0x180C0000 - 1, .flags = IORESOURCE_MEM, }, + { + .name = "bank2", + .start = 0x14000000, + .end = 0x140C0000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "bank3", + .start = 0x0C000000, + .end = 0x0C0C0000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "bank4", + .start = 0x08000000, + .end = 0x080C0000 - 1, + .flags = IORESOURCE_MEM, + }, }; struct platform_device jz4740_nand_device = { diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index a6fa884..100b677 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -52,9 +52,10 @@ #define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) #define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) +#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa -#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 #define JZ_NAND_MEM_CMD_OFFSET 0x08000 +#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 struct jz_nand { struct mtd_info mtd; @@ -62,8 +63,11 @@ struct jz_nand { void __iomem *base; struct resource *mem; - void __iomem *bank_base; - struct resource *bank_mem; + unsigned char banks[JZ_NAND_NUM_BANKS]; + void __iomem *bank_base[JZ_NAND_NUM_BANKS]; + struct resource *bank_mem[JZ_NAND_NUM_BANKS]; + + int selected_bank; struct jz_nand_platform_data *pdata; bool is_reading; @@ -74,26 +78,50 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) return container_of(mtd, struct jz_nand, mtd); } +static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + struct nand_chip *chip = mtd->priv; + uint32_t ctrl; + int banknr; + + ctrl = readl(nand->base + JZ_REG_NAND_CTRL); + ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK; + + if (chipnr == -1) { + banknr = -1; + } else { + banknr = nand->banks[chipnr] - 1; + chip->IO_ADDR_R = nand->bank_base[banknr]; + chip->IO_ADDR_W = nand->bank_base[banknr]; + } + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + + nand->selected_bank = banknr; +} + static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) { struct jz_nand *nand = mtd_to_jz_nand(mtd); struct nand_chip *chip = mtd->priv; uint32_t reg; + void __iomem *bank_base = nand->bank_base[nand->selected_bank]; + + BUG_ON(nand->selected_bank < 0); if (ctrl & NAND_CTRL_CHANGE) { BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); if (ctrl & NAND_ALE) - chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET; + bank_base += JZ_NAND_MEM_ADDR_OFFSET; else if (ctrl & NAND_CLE) - chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET; - else - chip->IO_ADDR_W = nand->bank_base; + bank_base += JZ_NAND_MEM_CMD_OFFSET; + chip->IO_ADDR_W = bank_base; reg = readl(nand->base + JZ_REG_NAND_CTRL); if (ctrl & NAND_NCE) - reg |= JZ_NAND_CTRL_ASSERT_CHIP(0); + reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); else - reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0); + reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); writel(reg, nand->base + JZ_REG_NAND_CTRL); } if (dat != NAND_CMD_NONE) @@ -252,7 +280,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, } static int jz_nand_ioremap_resource(struct platform_device *pdev, - const char *name, struct resource **res, void __iomem **base) + const char *name, struct resource **res, void *__iomem *base) { int ret; @@ -288,6 +316,90 @@ err: return ret; } +static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base) +{ + iounmap(base); + release_mem_region(res->start, resource_size(res)); +} + +static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { + int ret; + int gpio; + char gpio_name[9]; + char res_name[6]; + uint32_t ctrl; + struct mtd_info *mtd = &nand->mtd; + struct nand_chip *chip = &nand->chip; + + /* Request GPIO port. */ + gpio = JZ_GPIO_MEM_CS0 + bank - 1; + sprintf(gpio_name, "NAND CS%d", bank); + ret = gpio_request(gpio, gpio_name); + if (ret) { + dev_warn(&pdev->dev, + "Failed to request %s gpio %d: %d\n", + gpio_name, gpio, ret); + goto notfound_gpio; + } + + /* Request I/O resource. */ + sprintf(res_name, "bank%d", bank); + ret = jz_nand_ioremap_resource(pdev, res_name, + &nand->bank_mem[bank - 1], + &nand->bank_base[bank - 1]); + if (ret) + goto notfound_resource; + + /* Enable chip in bank. */ + jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0); + ctrl = readl(nand->base + JZ_REG_NAND_CTRL); + ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + + if (chipnr == 0) { + /* Detect first chip. */ + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + goto notfound_id; + + /* Retrieve the IDs from the first chip. */ + chip->select_chip(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + *nand_maf_id = chip->read_byte(mtd); + *nand_dev_id = chip->read_byte(mtd); + } else { + /* Detect additional chip. */ + chip->select_chip(mtd, chipnr); + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + if (*nand_maf_id != chip->read_byte(mtd) + || *nand_dev_id != chip->read_byte(mtd)) { + ret = -ENODEV; + goto notfound_id; + } + + /* Update size of the MTD. */ + chip->numchips++; + mtd->size += chip->chipsize; + } + + dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank); + return 0; + +notfound_id: + dev_info(&pdev->dev, "No chip found on bank %i\n", bank); + ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE); + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); +notfound_resource: + gpio_free(gpio); +notfound_gpio: + return ret; +} + static int __devinit jz_nand_probe(struct platform_device *pdev) { int ret; @@ -295,6 +407,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) struct nand_chip *chip; struct mtd_info *mtd; struct jz_nand_platform_data *pdata = pdev->dev.platform_data; + size_t chipnr, bank_idx; + uint8_t nand_maf_id = 0, nand_dev_id = 0; nand = kzalloc(sizeof(*nand), GFP_KERNEL); if (!nand) { @@ -305,10 +419,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); if (ret) goto err_free; - ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem, - &nand->bank_base); - if (ret) - goto err_iounmap_mmio; if (pdata && gpio_is_valid(pdata->busy_gpio)) { ret = gpio_request(pdata->busy_gpio, "NAND busy pin"); @@ -316,7 +426,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to request busy gpio %d: %d\n", pdata->busy_gpio, ret); - goto err_iounmap_mem; + goto err_iounmap_mmio; } } @@ -339,22 +449,51 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) chip->chip_delay = 50; chip->cmd_ctrl = jz_nand_cmd_ctrl; + chip->select_chip = jz_nand_select_chip; if (pdata && gpio_is_valid(pdata->busy_gpio)) chip->dev_ready = jz_nand_dev_ready; - chip->IO_ADDR_R = nand->bank_base; - chip->IO_ADDR_W = nand->bank_base; - nand->pdata = pdata; platform_set_drvdata(pdev, nand); - writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL); - - ret = nand_scan_ident(mtd, 1, NULL); - if (ret) { - dev_err(&pdev->dev, "Failed to scan nand\n"); - goto err_gpio_free; + /* We are going to autodetect NAND chips in the banks specified in the + * platform data. Although nand_scan_ident() can detect multiple chips, + * it requires those chips to be numbered consecuitively, which is not + * always the case for external memory banks. And a fixed chip-to-bank + * mapping is not practical either, since for example Dingoo units + * produced at different times have NAND chips in different banks. + */ + chipnr = 0; + for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) { + unsigned char bank; + + /* If there is no platform data, look for NAND in bank 1, + * which is the most likely bank since it is the only one + * that can be booted from. + */ + bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1; + if (bank == 0) + break; + if (bank > JZ_NAND_NUM_BANKS) { + dev_warn(&pdev->dev, + "Skipping non-existing bank: %d\n", bank); + continue; + } + /* The detection routine will directly or indirectly call + * jz_nand_select_chip(), so nand->banks has to contain the + * bank we're checking. + */ + nand->banks[chipnr] = bank; + if (jz_nand_detect_bank(pdev, nand, bank, chipnr, + &nand_maf_id, &nand_dev_id) == 0) + chipnr++; + else + nand->banks[chipnr] = 0; + } + if (chipnr == 0) { + dev_err(&pdev->dev, "No NAND chips found\n"); + goto err_gpio_busy; } if (pdata && pdata->ident_callback) { @@ -364,8 +503,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) ret = nand_scan_tail(mtd); if (ret) { - dev_err(&pdev->dev, "Failed to scan nand\n"); - goto err_gpio_free; + dev_err(&pdev->dev, "Failed to scan NAND\n"); + goto err_unclaim_banks; } ret = mtd_device_parse_register(mtd, NULL, NULL, @@ -382,14 +521,21 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) return 0; err_nand_release: - nand_release(&nand->mtd); -err_gpio_free: + nand_release(mtd); +err_unclaim_banks: + while (chipnr--) { + unsigned char bank = nand->banks[chipnr]; + gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); + } + writel(0, nand->base + JZ_REG_NAND_CTRL); +err_gpio_busy: + if (pdata && gpio_is_valid(pdata->busy_gpio)) + gpio_free(pdata->busy_gpio); platform_set_drvdata(pdev, NULL); - gpio_free(pdata->busy_gpio); -err_iounmap_mem: - iounmap(nand->bank_base); err_iounmap_mmio: - iounmap(nand->base); + jz_nand_iounmap_resource(nand->mem, nand->base); err_free: kfree(nand); return ret; @@ -398,16 +544,26 @@ err_free: static int __devexit jz_nand_remove(struct platform_device *pdev) { struct jz_nand *nand = platform_get_drvdata(pdev); + struct jz_nand_platform_data *pdata = pdev->dev.platform_data; + size_t i; nand_release(&nand->mtd); /* Deassert and disable all chips */ writel(0, nand->base + JZ_REG_NAND_CTRL); - iounmap(nand->bank_base); - release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem)); - iounmap(nand->base); - release_mem_region(nand->mem->start, resource_size(nand->mem)); + for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) { + unsigned char bank = nand->banks[i]; + if (bank != 0) { + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); + gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); + } + } + if (pdata && gpio_is_valid(pdata->busy_gpio)) + gpio_free(pdata->busy_gpio); + + jz_nand_iounmap_resource(nand->mem, nand->base); platform_set_drvdata(pdev, NULL); kfree(nand); -- cgit v0.10.2 From 56635d79932c805f6eb2a775ad1cdf9ace12c2b5 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Thu, 29 Mar 2012 19:17:02 +0200 Subject: MIPS: JZ4740: qi_lb60: Look for NAND chip in bank 1. All NanoNotes have their NAND in bank 1. Specifying the bank is required since multi-bank support was introduced. Signed-off-by: Maarten ter Huurne Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3561/ Acked-By: David Woodhouse Signed-off-by: Ralf Baechle diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 9a91fe9..9a3d9de 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -140,6 +140,7 @@ static void qi_lb60_nand_ident(struct platform_device *pdev, static struct jz_nand_platform_data qi_lb60_nand_pdata = { .ident_callback = qi_lb60_nand_ident, .busy_gpio = 94, + .banks = { 1 }, }; /* Keyboard*/ -- cgit v0.10.2 From ea3952e01c47ac76d71857099cbfc2f487f507d2 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 30 Mar 2012 16:18:57 +0200 Subject: MIPS: JZ4740: reset: Initialize hibernate wakeup counters. In hibernation mode only the wakeup logic and the RTC are left running, so this is what users perceive as power down. If the counters are not initialized, the corresponding pin (typically connected to the power button) has to be asserted for two seconds before the device wakes up. Most users expect a shorter wakeup time. I took the timing values of 100 ms and 60 ms from BouKiCHi's patch for the Dingoo A320 kernel. Signed-off-by: Maarten ter Huurne Cc: Sergei Shtylyov Cc: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3563/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c index 5f1fb95..6c0da5a 100644 --- a/arch/mips/jz4740/reset.c +++ b/arch/mips/jz4740/reset.c @@ -21,6 +21,9 @@ #include #include +#include "reset.h" +#include "clock.h" + static void jz4740_halt(void) { while (1) { @@ -53,21 +56,57 @@ static void jz4740_restart(char *command) jz4740_halt(); } -#define JZ_REG_RTC_CTRL 0x00 -#define JZ_REG_RTC_HIBERNATE 0x20 +#define JZ_REG_RTC_CTRL 0x00 +#define JZ_REG_RTC_HIBERNATE 0x20 +#define JZ_REG_RTC_WAKEUP_FILTER 0x24 +#define JZ_REG_RTC_RESET_COUNTER 0x28 -#define JZ_RTC_CTRL_WRDY BIT(7) +#define JZ_RTC_CTRL_WRDY BIT(7) +#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0 +#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0 -static void jz4740_power_off(void) +static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base) { - void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x24); uint32_t ctrl; do { ctrl = readl(rtc_base + JZ_REG_RTC_CTRL); } while (!(ctrl & JZ_RTC_CTRL_WRDY)); +} +static void jz4740_power_off(void) +{ + void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38); + unsigned long wakeup_filter_ticks; + unsigned long reset_counter_ticks; + + /* + * Set minimum wakeup pin assertion time: 100 ms. + * Range is 0 to 2 sec if RTC is clocked at 32 kHz. + */ + wakeup_filter_ticks = (100 * jz4740_clock_bdata.rtc_rate) / 1000; + if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK) + wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK; + else + wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK; + jz4740_rtc_wait_ready(rtc_base); + writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER); + + /* + * Set reset pin low-level assertion time after wakeup: 60 ms. + * Range is 0 to 125 ms if RTC is clocked at 32 kHz. + */ + reset_counter_ticks = (60 * jz4740_clock_bdata.rtc_rate) / 1000; + if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK) + reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK; + else + reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK; + jz4740_rtc_wait_ready(rtc_base); + writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER); + + jz4740_rtc_wait_ready(rtc_base); writel(1, rtc_base + JZ_REG_RTC_HIBERNATE); + jz4740_halt(); } -- cgit v0.10.2 From f9c9affc5799b9243d57b86fefda0dffbce3a32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Batlle=20i=20Rossell?= Date: Fri, 30 Mar 2012 16:48:05 +0200 Subject: MIPS: Enable vmlinuz for JZ4740 This patch adds support for building a compressed kernel for the JZ4740 architecture. Signed-off-by: Lars-Peter Clausen Signed-off-by: Maarten ter Huurne Cc: Sergei Shtylyov Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3563/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b3e10fd..debdb6e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -209,6 +209,7 @@ config MACH_JZ4740 select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_ZBOOT_UART16550 select DMA_NONCOHERENT select IRQ_CPU select GENERIC_GPIO diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 5042d51..c2a3fb0 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -58,8 +58,12 @@ $(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.bin.z FORCE # Calculate the load address of the compressed kernel image hostprogs-y := calc_vmlinuz_load_addr +ifeq ($(CONFIG_MACH_JZ4740),y) +VMLINUZ_LOAD_ADDRESS := 0x80600000 +else VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \ $(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS)) +endif vmlinuzobjs-y += $(obj)/piggy.o diff --git a/arch/mips/boot/compressed/uart-16550.c b/arch/mips/boot/compressed/uart-16550.c index c9caaf4..1c7b739 100644 --- a/arch/mips/boot/compressed/uart-16550.c +++ b/arch/mips/boot/compressed/uart-16550.c @@ -18,6 +18,11 @@ #define PORT(offset) (CKSEG1ADDR(AR7_REGS_UART0) + (4 * offset)) #endif +#ifdef CONFIG_MACH_JZ4740 +#define UART0_BASE 0xB0030000 +#define PORT(offset) (UART0_BASE + (4 * offset)) +#endif + #ifndef PORT #error please define the serial port address for your own machine #endif -- cgit v0.10.2 From 6cd3c7e2b1dc1e3cc28ffcef074d0b8182b6e501 Mon Sep 17 00:00:00 2001 From: Thomas Langer Date: Sun, 20 May 2012 15:46:19 +0200 Subject: SPI: MIPS: lantiq: add FALCON spi driver The external bus unit (EBU) found on the FALCON SoC has spi emulation that is designed for serial flash access. This driver has only been tested with m25p80 type chips. The hardware has no support for other types of spi peripherals. Signed-off-by: Thomas Langer Signed-off-by: John Crispin Cc: spi-devel-general@lists.sourceforge.net Cc: linux-mips@linux-mips.org Acked-by: Grant Likely Patchwork: https://patchwork.linux-mips.org/patch/3844/ Signed-off-by: Ralf Baechle diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index cd2fe35..b18abf3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -144,6 +144,15 @@ config SPI_EP93XX This enables using the Cirrus EP93xx SPI controller in master mode. +config SPI_FALCON + tristate "Falcon SPI controller support" + depends on SOC_FALCON + help + The external bus unit (EBU) found on the FALC-ON SoC has SPI + emulation that is designed for serial flash access. This driver + has only been tested with m25p80 type chips. The hardware has no + support for other types of SPI peripherals. + config SPI_GPIO tristate "GPIO-based bitbanging SPI Master" depends on GENERIC_GPIO diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 9d75d21..b5cbab2 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o +obj-$(CONFIG_SPI_FALCON) += spi-falcon.o obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c new file mode 100644 index 0000000..8f6aa73 --- /dev/null +++ b/drivers/spi/spi-falcon.c @@ -0,0 +1,469 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2012 Thomas Langer + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRV_NAME "sflash-falcon" + +#define FALCON_SPI_XFER_BEGIN (1 << 0) +#define FALCON_SPI_XFER_END (1 << 1) + +/* Bus Read Configuration Register0 */ +#define BUSRCON0 0x00000010 +/* Bus Write Configuration Register0 */ +#define BUSWCON0 0x00000018 +/* Serial Flash Configuration Register */ +#define SFCON 0x00000080 +/* Serial Flash Time Register */ +#define SFTIME 0x00000084 +/* Serial Flash Status Register */ +#define SFSTAT 0x00000088 +/* Serial Flash Command Register */ +#define SFCMD 0x0000008C +/* Serial Flash Address Register */ +#define SFADDR 0x00000090 +/* Serial Flash Data Register */ +#define SFDATA 0x00000094 +/* Serial Flash I/O Control Register */ +#define SFIO 0x00000098 +/* EBU Clock Control Register */ +#define EBUCC 0x000000C4 + +/* Dummy Phase Length */ +#define SFCMD_DUMLEN_OFFSET 16 +#define SFCMD_DUMLEN_MASK 0x000F0000 +/* Chip Select */ +#define SFCMD_CS_OFFSET 24 +#define SFCMD_CS_MASK 0x07000000 +/* field offset */ +#define SFCMD_ALEN_OFFSET 20 +#define SFCMD_ALEN_MASK 0x00700000 +/* SCK Rise-edge Position */ +#define SFTIME_SCKR_POS_OFFSET 8 +#define SFTIME_SCKR_POS_MASK 0x00000F00 +/* SCK Period */ +#define SFTIME_SCK_PER_OFFSET 0 +#define SFTIME_SCK_PER_MASK 0x0000000F +/* SCK Fall-edge Position */ +#define SFTIME_SCKF_POS_OFFSET 12 +#define SFTIME_SCKF_POS_MASK 0x0000F000 +/* Device Size */ +#define SFCON_DEV_SIZE_A23_0 0x03000000 +#define SFCON_DEV_SIZE_MASK 0x0F000000 +/* Read Data Position */ +#define SFTIME_RD_POS_MASK 0x000F0000 +/* Data Output */ +#define SFIO_UNUSED_WD_MASK 0x0000000F +/* Command Opcode mask */ +#define SFCMD_OPC_MASK 0x000000FF +/* dlen bytes of data to write */ +#define SFCMD_DIR_WRITE 0x00000100 +/* Data Length offset */ +#define SFCMD_DLEN_OFFSET 9 +/* Command Error */ +#define SFSTAT_CMD_ERR 0x20000000 +/* Access Command Pending */ +#define SFSTAT_CMD_PEND 0x00400000 +/* Frequency set to 100MHz. */ +#define EBUCC_EBUDIV_SELF100 0x00000001 +/* Serial Flash */ +#define BUSRCON0_AGEN_SERIAL_FLASH 0xF0000000 +/* 8-bit multiplexed */ +#define BUSRCON0_PORTW_8_BIT_MUX 0x00000000 +/* Serial Flash */ +#define BUSWCON0_AGEN_SERIAL_FLASH 0xF0000000 +/* Chip Select after opcode */ +#define SFCMD_KEEP_CS_KEEP_SELECTED 0x00008000 + +#define CLOCK_100M 100000000 +#define CLOCK_50M 50000000 + +struct falcon_sflash { + u32 sfcmd; /* for caching of opcode, direction, ... */ + struct spi_master *master; +}; + +int falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t, + unsigned long flags) +{ + struct device *dev = &spi->dev; + struct falcon_sflash *priv = spi_master_get_devdata(spi->master); + const u8 *txp = t->tx_buf; + u8 *rxp = t->rx_buf; + unsigned int bytelen = ((8 * t->len + 7) / 8); + unsigned int len, alen, dumlen; + u32 val; + enum { + state_init, + state_command_prepare, + state_write, + state_read, + state_disable_cs, + state_end + } state = state_init; + + do { + switch (state) { + case state_init: /* detect phase of upper layer sequence */ + { + /* initial write ? */ + if (flags & FALCON_SPI_XFER_BEGIN) { + if (!txp) { + dev_err(dev, + "BEGIN without tx data!\n"); + return -ENODATA; + } + /* + * Prepare the parts of the sfcmd register, + * which should not change during a sequence! + * Only exception are the length fields, + * especially alen and dumlen. + */ + + priv->sfcmd = ((spi->chip_select + << SFCMD_CS_OFFSET) + & SFCMD_CS_MASK); + priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED; + priv->sfcmd |= *txp; + txp++; + bytelen--; + if (bytelen) { + /* + * more data: + * maybe address and/or dummy + */ + state = state_command_prepare; + break; + } else { + dev_dbg(dev, "write cmd %02X\n", + priv->sfcmd & SFCMD_OPC_MASK); + } + } + /* continued write ? */ + if (txp && bytelen) { + state = state_write; + break; + } + /* read data? */ + if (rxp && bytelen) { + state = state_read; + break; + } + /* end of sequence? */ + if (flags & FALCON_SPI_XFER_END) + state = state_disable_cs; + else + state = state_end; + break; + } + /* collect tx data for address and dummy phase */ + case state_command_prepare: + { + /* txp is valid, already checked */ + val = 0; + alen = 0; + dumlen = 0; + while (bytelen > 0) { + if (alen < 3) { + val = (val << 8) | (*txp++); + alen++; + } else if ((dumlen < 15) && (*txp == 0)) { + /* + * assume dummy bytes are set to 0 + * from upper layer + */ + dumlen++; + txp++; + } else { + break; + } + bytelen--; + } + priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK); + priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) | + (dumlen << SFCMD_DUMLEN_OFFSET); + if (alen > 0) + ltq_ebu_w32(val, SFADDR); + + dev_dbg(dev, "wr %02X, alen=%d (addr=%06X) dlen=%d\n", + priv->sfcmd & SFCMD_OPC_MASK, + alen, val, dumlen); + + if (bytelen > 0) { + /* continue with write */ + state = state_write; + } else if (flags & FALCON_SPI_XFER_END) { + /* end of sequence? */ + state = state_disable_cs; + } else { + /* + * go to end and expect another + * call (read or write) + */ + state = state_end; + } + break; + } + case state_write: + { + /* txp still valid */ + priv->sfcmd |= SFCMD_DIR_WRITE; + len = 0; + val = 0; + do { + if (bytelen--) + val |= (*txp++) << (8 * len++); + if ((flags & FALCON_SPI_XFER_END) + && (bytelen == 0)) { + priv->sfcmd &= + ~SFCMD_KEEP_CS_KEEP_SELECTED; + } + if ((len == 4) || (bytelen == 0)) { + ltq_ebu_w32(val, SFDATA); + ltq_ebu_w32(priv->sfcmd + | (len<sfcmd &= ~(SFCMD_ALEN_MASK + | SFCMD_DUMLEN_MASK); + } + } while (bytelen); + state = state_end; + break; + } + case state_read: + { + /* read data */ + priv->sfcmd &= ~SFCMD_DIR_WRITE; + do { + if ((flags & FALCON_SPI_XFER_END) + && (bytelen <= 4)) { + priv->sfcmd &= + ~SFCMD_KEEP_CS_KEEP_SELECTED; + } + len = (bytelen > 4) ? 4 : bytelen; + bytelen -= len; + ltq_ebu_w32(priv->sfcmd + | (len << SFCMD_DLEN_OFFSET), SFCMD); + priv->sfcmd &= ~(SFCMD_ALEN_MASK + | SFCMD_DUMLEN_MASK); + do { + val = ltq_ebu_r32(SFSTAT); + if (val & SFSTAT_CMD_ERR) { + /* reset error status */ + dev_err(dev, "SFSTAT: CMD_ERR"); + dev_err(dev, " (%x)\n", val); + ltq_ebu_w32(SFSTAT_CMD_ERR, + SFSTAT); + return -EBADE; + } + } while (val & SFSTAT_CMD_PEND); + val = ltq_ebu_r32(SFDATA); + do { + *rxp = (val & 0xFF); + rxp++; + val >>= 8; + len--; + } while (len); + } while (bytelen); + state = state_end; + break; + } + case state_disable_cs: + { + priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED; + ltq_ebu_w32(priv->sfcmd | (0 << SFCMD_DLEN_OFFSET), + SFCMD); + val = ltq_ebu_r32(SFSTAT); + if (val & SFSTAT_CMD_ERR) { + /* reset error status */ + dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val); + ltq_ebu_w32(SFSTAT_CMD_ERR, SFSTAT); + return -EBADE; + } + state = state_end; + break; + } + case state_end: + break; + } + } while (state != state_end); + + return 0; +} + +static int falcon_sflash_setup(struct spi_device *spi) +{ + unsigned int i; + unsigned long flags; + + if (spi->chip_select > 0) + return -ENODEV; + + spin_lock_irqsave(&ebu_lock, flags); + + if (spi->max_speed_hz >= CLOCK_100M) { + /* set EBU clock to 100 MHz */ + ltq_sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, EBUCC); + i = 1; /* divider */ + } else { + /* set EBU clock to 50 MHz */ + ltq_sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, EBUCC); + + /* search for suitable divider */ + for (i = 1; i < 7; i++) { + if (CLOCK_50M / i <= spi->max_speed_hz) + break; + } + } + + /* setup period of serial clock */ + ltq_ebu_w32_mask(SFTIME_SCKF_POS_MASK + | SFTIME_SCKR_POS_MASK + | SFTIME_SCK_PER_MASK, + (i << SFTIME_SCKR_POS_OFFSET) + | (i << (SFTIME_SCK_PER_OFFSET + 1)), + SFTIME); + + /* + * set some bits of unused_wd, to not trigger HOLD/WP + * signals on non QUAD flashes + */ + ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), SFIO); + + ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX, + BUSRCON0); + ltq_ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, BUSWCON0); + /* set address wrap around to maximum for 24-bit addresses */ + ltq_ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, SFCON); + + spin_unlock_irqrestore(&ebu_lock, flags); + + return 0; +} + +static int falcon_sflash_prepare_xfer(struct spi_master *master) +{ + return 0; +} + +static int falcon_sflash_unprepare_xfer(struct spi_master *master) +{ + return 0; +} + +static int falcon_sflash_xfer_one(struct spi_master *master, + struct spi_message *m) +{ + struct falcon_sflash *priv = spi_master_get_devdata(master); + struct spi_transfer *t; + unsigned long spi_flags; + unsigned long flags; + int ret = 0; + + priv->sfcmd = 0; + m->actual_length = 0; + + spi_flags = FALCON_SPI_XFER_BEGIN; + list_for_each_entry(t, &m->transfers, transfer_list) { + if (list_is_last(&t->transfer_list, &m->transfers)) + spi_flags |= FALCON_SPI_XFER_END; + + spin_lock_irqsave(&ebu_lock, flags); + ret = falcon_sflash_xfer(m->spi, t, spi_flags); + spin_unlock_irqrestore(&ebu_lock, flags); + + if (ret) + break; + + m->actual_length += t->len; + + WARN_ON(t->delay_usecs || t->cs_change); + spi_flags = 0; + } + + m->status = ret; + m->complete(m->context); + + return 0; +} + +static int __devinit falcon_sflash_probe(struct platform_device *pdev) +{ + struct falcon_sflash *priv; + struct spi_master *master; + int ret; + + if (ltq_boot_select() != BS_SPI) { + dev_err(&pdev->dev, "invalid bootstrap options\n"); + return -ENODEV; + } + + master = spi_alloc_master(&pdev->dev, sizeof(*priv)); + if (!master) + return -ENOMEM; + + priv = spi_master_get_devdata(master); + priv->master = master; + + master->mode_bits = SPI_MODE_3; + master->num_chipselect = 1; + master->bus_num = -1; + master->setup = falcon_sflash_setup; + master->prepare_transfer_hardware = falcon_sflash_prepare_xfer; + master->transfer_one_message = falcon_sflash_xfer_one; + master->unprepare_transfer_hardware = falcon_sflash_unprepare_xfer; + master->dev.of_node = pdev->dev.of_node; + + platform_set_drvdata(pdev, priv); + + ret = spi_register_master(master); + if (ret) + spi_master_put(master); + return ret; +} + +static int __devexit falcon_sflash_remove(struct platform_device *pdev) +{ + struct falcon_sflash *priv = platform_get_drvdata(pdev); + + spi_unregister_master(priv->master); + + return 0; +} + +static const struct of_device_id falcon_sflash_match[] = { + { .compatible = "lantiq,sflash-falcon" }, + {}, +}; +MODULE_DEVICE_TABLE(of, falcon_sflash_match); + +static struct platform_driver falcon_sflash_driver = { + .probe = falcon_sflash_probe, + .remove = __devexit_p(falcon_sflash_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = falcon_sflash_match, + } +}; + +module_platform_driver(falcon_sflash_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Lantiq Falcon SPI/SFLASH controller driver"); -- cgit v0.10.2 From 2fa36399e63c911134f28b6878aada9b395c4209 Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Wed, 20 Jun 2012 20:05:32 +0100 Subject: MIPS: Add CPU support for Loongson1B Loongson 1B is a 32-bit SoC designed by Institute of Computing Technology (ICT) and the Chinese Academy of Sciences (CAS), which implements the MIPS32 release 2 instruction set. [ralf@linux-mips.org: But which is not strictly a MIPS32 compliant device which also is why it identifies itself with the Legacy Vendor ID in the PrID register. When applying the patch I shoveled some code around to keep things in alphabetical order and avoid forward declarations.] Signed-off-by: Kelvin Cheung Cc: To: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: wuzhangjin@gmail.com Cc: zhzhl555@gmail.com Cc: Kelvin Cheung Patchwork: https://patchwork.linux-mips.org/patch/3976/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 95e40c1..f21b7c0 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -197,6 +197,7 @@ #define PRID_REV_VR4181A 0x0070 /* Same as VR4122 */ #define PRID_REV_VR4130 0x0080 #define PRID_REV_34K_V1_0_2 0x0022 +#define PRID_REV_LOONGSON1B 0x0020 #define PRID_REV_LOONGSON2E 0x0002 #define PRID_REV_LOONGSON2F 0x0003 @@ -261,7 +262,7 @@ enum cpu_type_enum { */ CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K, CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, - CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_M14KC, + CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, /* * MIPS64 class processors diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h index 5300080..7531ecd 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h @@ -117,6 +117,8 @@ search_module_dbetables(unsigned long addr) #define MODULE_PROC_FAMILY "RM9000 " #elif defined CONFIG_CPU_SB1 #define MODULE_PROC_FAMILY "SB1 " +#elif defined CONFIG_CPU_LOONGSON1 +#define MODULE_PROC_FAMILY "LOONGSON1 " #elif defined CONFIG_CPU_LOONGSON2 #define MODULE_PROC_FAMILY "LOONGSON2 " #elif defined CONFIG_CPU_CAVIUM_OCTEON diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index f4630e1..1b51046 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -190,6 +190,7 @@ void __init check_wait(void) case CPU_CAVIUM_OCTEON_PLUS: case CPU_CAVIUM_OCTEON2: case CPU_JZRISC: + case CPU_LOONGSON1: case CPU_XLR: case CPU_XLP: cpu_wait = r4k_wait; @@ -330,6 +331,154 @@ static inline void cpu_probe_vmbits(struct cpuinfo_mips *c) #endif } +static char unknown_isa[] __cpuinitdata = KERN_ERR \ + "Unsupported ISA type, c0.config0: %d."; + +static inline unsigned int decode_config0(struct cpuinfo_mips *c) +{ + unsigned int config0; + int isa; + + config0 = read_c0_config(); + + if (((config0 & MIPS_CONF_MT) >> 7) == 1) + c->options |= MIPS_CPU_TLB; + isa = (config0 & MIPS_CONF_AT) >> 13; + switch (isa) { + case 0: + switch ((config0 & MIPS_CONF_AR) >> 10) { + case 0: + c->isa_level = MIPS_CPU_ISA_M32R1; + break; + case 1: + c->isa_level = MIPS_CPU_ISA_M32R2; + break; + default: + goto unknown; + } + break; + case 2: + switch ((config0 & MIPS_CONF_AR) >> 10) { + case 0: + c->isa_level = MIPS_CPU_ISA_M64R1; + break; + case 1: + c->isa_level = MIPS_CPU_ISA_M64R2; + break; + default: + goto unknown; + } + break; + default: + goto unknown; + } + + return config0 & MIPS_CONF_M; + +unknown: + panic(unknown_isa, config0); +} + +static inline unsigned int decode_config1(struct cpuinfo_mips *c) +{ + unsigned int config1; + + config1 = read_c0_config1(); + + if (config1 & MIPS_CONF1_MD) + c->ases |= MIPS_ASE_MDMX; + if (config1 & MIPS_CONF1_WR) + c->options |= MIPS_CPU_WATCH; + if (config1 & MIPS_CONF1_CA) + c->ases |= MIPS_ASE_MIPS16; + if (config1 & MIPS_CONF1_EP) + c->options |= MIPS_CPU_EJTAG; + if (config1 & MIPS_CONF1_FP) { + c->options |= MIPS_CPU_FPU; + c->options |= MIPS_CPU_32FPR; + } + if (cpu_has_tlb) + c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1; + + return config1 & MIPS_CONF_M; +} + +static inline unsigned int decode_config2(struct cpuinfo_mips *c) +{ + unsigned int config2; + + config2 = read_c0_config2(); + + if (config2 & MIPS_CONF2_SL) + c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + + return config2 & MIPS_CONF_M; +} + +static inline unsigned int decode_config3(struct cpuinfo_mips *c) +{ + unsigned int config3; + + config3 = read_c0_config3(); + + if (config3 & MIPS_CONF3_SM) + c->ases |= MIPS_ASE_SMARTMIPS; + if (config3 & MIPS_CONF3_DSP) + c->ases |= MIPS_ASE_DSP; + if (config3 & MIPS_CONF3_VINT) + c->options |= MIPS_CPU_VINT; + if (config3 & MIPS_CONF3_VEIC) + c->options |= MIPS_CPU_VEIC; + if (config3 & MIPS_CONF3_MT) + c->ases |= MIPS_ASE_MIPSMT; + if (config3 & MIPS_CONF3_ULRI) + c->options |= MIPS_CPU_ULRI; + + return config3 & MIPS_CONF_M; +} + +static inline unsigned int decode_config4(struct cpuinfo_mips *c) +{ + unsigned int config4; + + config4 = read_c0_config4(); + + if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT + && cpu_has_tlb) + c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; + + c->kscratch_mask = (config4 >> 16) & 0xff; + + return config4 & MIPS_CONF_M; +} + +static void __cpuinit decode_configs(struct cpuinfo_mips *c) +{ + int ok; + + /* MIPS32 or MIPS64 compliant CPU. */ + c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK; + + c->scache.flags = MIPS_CACHE_NOT_PRESENT; + + ok = decode_config0(c); /* Read Config registers. */ + BUG_ON(!ok); /* Arch spec violation! */ + if (ok) + ok = decode_config1(c); + if (ok) + ok = decode_config2(c); + if (ok) + ok = decode_config3(c); + if (ok) + ok = decode_config4(c); + + mips_probe_watch_registers(c); + + if (cpu_has_mips_r2) + c->core = read_c0_ebase() & 0x3ff; +} + #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \ | MIPS_CPU_COUNTER) @@ -638,155 +787,19 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) MIPS_CPU_32FPR; c->tlbsize = 64; break; - } -} - -static char unknown_isa[] __cpuinitdata = KERN_ERR \ - "Unsupported ISA type, c0.config0: %d."; + case PRID_IMP_LOONGSON1: + decode_configs(c); -static inline unsigned int decode_config0(struct cpuinfo_mips *c) -{ - unsigned int config0; - int isa; + c->cputype = CPU_LOONGSON1; - config0 = read_c0_config(); - - if (((config0 & MIPS_CONF_MT) >> 7) == 1) - c->options |= MIPS_CPU_TLB; - isa = (config0 & MIPS_CONF_AT) >> 13; - switch (isa) { - case 0: - switch ((config0 & MIPS_CONF_AR) >> 10) { - case 0: - c->isa_level = MIPS_CPU_ISA_M32R1; - break; - case 1: - c->isa_level = MIPS_CPU_ISA_M32R2; + switch (c->processor_id & PRID_REV_MASK) { + case PRID_REV_LOONGSON1B: + __cpu_name[cpu] = "Loongson 1B"; break; - default: - goto unknown; } - break; - case 2: - switch ((config0 & MIPS_CONF_AR) >> 10) { - case 0: - c->isa_level = MIPS_CPU_ISA_M64R1; - break; - case 1: - c->isa_level = MIPS_CPU_ISA_M64R2; - break; - default: - goto unknown; - } - break; - default: - goto unknown; - } - - return config0 & MIPS_CONF_M; - -unknown: - panic(unknown_isa, config0); -} -static inline unsigned int decode_config1(struct cpuinfo_mips *c) -{ - unsigned int config1; - - config1 = read_c0_config1(); - - if (config1 & MIPS_CONF1_MD) - c->ases |= MIPS_ASE_MDMX; - if (config1 & MIPS_CONF1_WR) - c->options |= MIPS_CPU_WATCH; - if (config1 & MIPS_CONF1_CA) - c->ases |= MIPS_ASE_MIPS16; - if (config1 & MIPS_CONF1_EP) - c->options |= MIPS_CPU_EJTAG; - if (config1 & MIPS_CONF1_FP) { - c->options |= MIPS_CPU_FPU; - c->options |= MIPS_CPU_32FPR; + break; } - if (cpu_has_tlb) - c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1; - - return config1 & MIPS_CONF_M; -} - -static inline unsigned int decode_config2(struct cpuinfo_mips *c) -{ - unsigned int config2; - - config2 = read_c0_config2(); - - if (config2 & MIPS_CONF2_SL) - c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; - - return config2 & MIPS_CONF_M; -} - -static inline unsigned int decode_config3(struct cpuinfo_mips *c) -{ - unsigned int config3; - - config3 = read_c0_config3(); - - if (config3 & MIPS_CONF3_SM) - c->ases |= MIPS_ASE_SMARTMIPS; - if (config3 & MIPS_CONF3_DSP) - c->ases |= MIPS_ASE_DSP; - if (config3 & MIPS_CONF3_VINT) - c->options |= MIPS_CPU_VINT; - if (config3 & MIPS_CONF3_VEIC) - c->options |= MIPS_CPU_VEIC; - if (config3 & MIPS_CONF3_MT) - c->ases |= MIPS_ASE_MIPSMT; - if (config3 & MIPS_CONF3_ULRI) - c->options |= MIPS_CPU_ULRI; - - return config3 & MIPS_CONF_M; -} - -static inline unsigned int decode_config4(struct cpuinfo_mips *c) -{ - unsigned int config4; - - config4 = read_c0_config4(); - - if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT - && cpu_has_tlb) - c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; - - c->kscratch_mask = (config4 >> 16) & 0xff; - - return config4 & MIPS_CONF_M; -} - -static void __cpuinit decode_configs(struct cpuinfo_mips *c) -{ - int ok; - - /* MIPS32 or MIPS64 compliant CPU. */ - c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER | - MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK; - - c->scache.flags = MIPS_CACHE_NOT_PRESENT; - - ok = decode_config0(c); /* Read Config registers. */ - BUG_ON(!ok); /* Arch spec violation! */ - if (ok) - ok = decode_config1(c); - if (ok) - ok = decode_config2(c); - if (ok) - ok = decode_config3(c); - if (ok) - ok = decode_config4(c); - - mips_probe_watch_registers(c); - - if (cpu_has_mips_r2) - c->core = read_c0_ebase() & 0x3ff; } static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index eb5e394..2f28d3b 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -1559,6 +1559,11 @@ init_hw_perf_events(void) mipspmu.general_event_map = &mipsxxcore_event_map; mipspmu.cache_event_map = &mipsxxcore_cache_map; break; + case CPU_LOONGSON1: + mipspmu.name = "mips/loongson1"; + mipspmu.general_event_map = &mipsxxcore_event_map; + mipspmu.cache_event_map = &mipsxxcore_cache_map; + break; case CPU_CAVIUM_OCTEON: case CPU_CAVIUM_OCTEON_PLUS: case CPU_CAVIUM_OCTEON2: diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index c3c2935..9be3df1 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1253,6 +1253,7 @@ static inline void parity_protection_init(void) case CPU_5KC: case CPU_5KE: + case CPU_LOONGSON1: write_c0_ecc(0x80000000); back_to_back_c0_hazard(); /* Set the PE bit (bit 31) in the c0_errctl register. */ diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index b6e3782..f80480a 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -85,6 +85,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) case CPU_34K: case CPU_1004K: case CPU_74K: + case CPU_LOONGSON1: case CPU_SB1: case CPU_SB1A: case CPU_R10000: diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 4d80a85..056da62 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -374,6 +374,10 @@ static int __init mipsxx_init(void) op_model_mipsxx_ops.cpu_type = "mips/sb1"; break; + case CPU_LOONGSON1: + op_model_mipsxx_ops.cpu_type = "mips/loongson1"; + break; + default: printk(KERN_ERR "Profiling unsupported for this CPU\n"); -- cgit v0.10.2 From 94c58b7f237d33e6afcc8998e98364a7b9e4e289 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 24 Jul 2012 16:33:09 +0200 Subject: MIPS: BCM63XX: Fix platform_devices id There is only one watchdog and VoIP DSP platform devices per board, use -1 as the platform_device id accordingly. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3313/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/dev-dsp.c b/arch/mips/bcm63xx/dev-dsp.c index da46d1d..5bb5b15 100644 --- a/arch/mips/bcm63xx/dev-dsp.c +++ b/arch/mips/bcm63xx/dev-dsp.c @@ -31,7 +31,7 @@ static struct resource voip_dsp_resources[] = { static struct platform_device bcm63xx_voip_dsp_device = { .name = "bcm63xx-voip-dsp", - .id = 0, + .id = -1, .num_resources = ARRAY_SIZE(voip_dsp_resources), .resource = voip_dsp_resources, }; diff --git a/arch/mips/bcm63xx/dev-wdt.c b/arch/mips/bcm63xx/dev-wdt.c index 3e6c716..2a2346a 100644 --- a/arch/mips/bcm63xx/dev-wdt.c +++ b/arch/mips/bcm63xx/dev-wdt.c @@ -21,7 +21,7 @@ static struct resource wdt_resources[] = { static struct platform_device bcm63xx_wdt_device = { .name = "bcm63xx-wdt", - .id = 0, + .id = -1, .num_resources = ARRAY_SIZE(wdt_resources), .resource = wdt_resources, }; -- cgit v0.10.2 From a03822ea5df6365c878f0765d7af56a94b9c2cfe Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 24 Jul 2012 16:33:09 +0200 Subject: MIPS: OCTEON: Remove some unused files. These FPA related files are not used anywhere in the kernel. Remove them. Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3892/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/executive/cvmx-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-fpa.c deleted file mode 100644 index ad44b8b..0000000 --- a/arch/mips/cavium-octeon/executive/cvmx-fpa.c +++ /dev/null @@ -1,183 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Support library for the hardware Free Pool Allocator. - * - * - */ - -#include "cvmx-config.h" -#include "cvmx.h" -#include "cvmx-fpa.h" -#include "cvmx-ipd.h" - -/** - * Current state of all the pools. Use access functions - * instead of using it directly. - */ -CVMX_SHARED cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS]; - -/** - * Setup a FPA pool to control a new block of memory. The - * buffer pointer must be a physical address. - * - * @pool: Pool to initialize - * 0 <= pool < 8 - * @name: Constant character string to name this pool. - * String is not copied. - * @buffer: Pointer to the block of memory to use. This must be - * accessible by all processors and external hardware. - * @block_size: Size for each block controlled by the FPA - * @num_blocks: Number of blocks - * - * Returns 0 on Success, - * -1 on failure - */ -int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer, - uint64_t block_size, uint64_t num_blocks) -{ - char *ptr; - if (!buffer) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: NULL buffer pointer!\n"); - return -1; - } - if (pool >= CVMX_FPA_NUM_POOLS) { - cvmx_dprintf("ERROR: cvmx_fpa_setup_pool: Illegal pool!\n"); - return -1; - } - - if (block_size < CVMX_FPA_MIN_BLOCK_SIZE) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: Block size too small.\n"); - return -1; - } - - if (((unsigned long)buffer & (CVMX_FPA_ALIGNMENT - 1)) != 0) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: Buffer not aligned properly.\n"); - return -1; - } - - cvmx_fpa_pool_info[pool].name = name; - cvmx_fpa_pool_info[pool].size = block_size; - cvmx_fpa_pool_info[pool].starting_element_count = num_blocks; - cvmx_fpa_pool_info[pool].base = buffer; - - ptr = (char *)buffer; - while (num_blocks--) { - cvmx_fpa_free(ptr, pool, 0); - ptr += block_size; - } - return 0; -} - -/** - * Shutdown a Memory pool and validate that it had all of - * the buffers originally placed in it. - * - * @pool: Pool to shutdown - * Returns Zero on success - * - Positive is count of missing buffers - * - Negative is too many buffers or corrupted pointers - */ -uint64_t cvmx_fpa_shutdown_pool(uint64_t pool) -{ - uint64_t errors = 0; - uint64_t count = 0; - uint64_t base = cvmx_ptr_to_phys(cvmx_fpa_pool_info[pool].base); - uint64_t finish = - base + - cvmx_fpa_pool_info[pool].size * - cvmx_fpa_pool_info[pool].starting_element_count; - void *ptr; - uint64_t address; - - count = 0; - do { - ptr = cvmx_fpa_alloc(pool); - if (ptr) - address = cvmx_ptr_to_phys(ptr); - else - address = 0; - if (address) { - if ((address >= base) && (address < finish) && - (((address - - base) % cvmx_fpa_pool_info[pool].size) == 0)) { - count++; - } else { - cvmx_dprintf - ("ERROR: cvmx_fpa_shutdown_pool: Illegal address 0x%llx in pool %s(%d)\n", - (unsigned long long)address, - cvmx_fpa_pool_info[pool].name, (int)pool); - errors++; - } - } - } while (address); - -#ifdef CVMX_ENABLE_PKO_FUNCTIONS - if (pool == 0) - cvmx_ipd_free_ptr(); -#endif - - if (errors) { - cvmx_dprintf - ("ERROR: cvmx_fpa_shutdown_pool: Pool %s(%d) started at 0x%llx, ended at 0x%llx, with a step of 0x%llx\n", - cvmx_fpa_pool_info[pool].name, (int)pool, - (unsigned long long)base, (unsigned long long)finish, - (unsigned long long)cvmx_fpa_pool_info[pool].size); - return -errors; - } else - return 0; -} - -uint64_t cvmx_fpa_get_block_size(uint64_t pool) -{ - switch (pool) { - case 0: - return CVMX_FPA_POOL_0_SIZE; - case 1: - return CVMX_FPA_POOL_1_SIZE; - case 2: - return CVMX_FPA_POOL_2_SIZE; - case 3: - return CVMX_FPA_POOL_3_SIZE; - case 4: - return CVMX_FPA_POOL_4_SIZE; - case 5: - return CVMX_FPA_POOL_5_SIZE; - case 6: - return CVMX_FPA_POOL_6_SIZE; - case 7: - return CVMX_FPA_POOL_7_SIZE; - default: - return 0; - } -} diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c deleted file mode 100644 index c239e5f..0000000 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c +++ /dev/null @@ -1,243 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Helper functions for FPA setup. - * - */ -#include "executive-config.h" -#include "cvmx-config.h" -#include "cvmx.h" -#include "cvmx-bootmem.h" -#include "cvmx-fpa.h" -#include "cvmx-helper-fpa.h" - -/** - * Allocate memory for and initialize a single FPA pool. - * - * @pool: Pool to initialize - * @buffer_size: Size of buffers to allocate in bytes - * @buffers: Number of buffers to put in the pool. Zero is allowed - * @name: String name of the pool for debugging purposes - * Returns Zero on success, non-zero on failure - */ -static int __cvmx_helper_initialize_fpa_pool(int pool, uint64_t buffer_size, - uint64_t buffers, const char *name) -{ - uint64_t current_num; - void *memory; - uint64_t align = CVMX_CACHE_LINE_SIZE; - - /* - * Align the allocation so that power of 2 size buffers are - * naturally aligned. - */ - while (align < buffer_size) - align = align << 1; - - if (buffers == 0) - return 0; - - current_num = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(pool)); - if (current_num) { - cvmx_dprintf("Fpa pool %d(%s) already has %llu buffers. " - "Skipping setup.\n", - pool, name, (unsigned long long)current_num); - return 0; - } - - memory = cvmx_bootmem_alloc(buffer_size * buffers, align); - if (memory == NULL) { - cvmx_dprintf("Out of memory initializing fpa pool %d(%s).\n", - pool, name); - return -1; - } - cvmx_fpa_setup_pool(pool, name, memory, buffer_size, buffers); - return 0; -} - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Specifying zero for the number of - * buffers will cause that FPA pool to not be setup. This is - * useful if you aren't using some of the hardware and want - * to save memory. Use cvmx_helper_initialize_fpa instead of - * this function directly. - * - * @pip_pool: Should always be CVMX_FPA_PACKET_POOL - * @pip_size: Should always be CVMX_FPA_PACKET_POOL_SIZE - * @pip_buffers: - * Number of packet buffers. - * @wqe_pool: Should always be CVMX_FPA_WQE_POOL - * @wqe_size: Should always be CVMX_FPA_WQE_POOL_SIZE - * @wqe_entries: - * Number of work queue entries - * @pko_pool: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL - * @pko_size: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_pool: Should always be CVMX_FPA_TIMER_POOL - * @tim_size: Should always be CVMX_FPA_TIMER_POOL_SIZE - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_pool: Should always be CVMX_FPA_DFA_POOL - * @dfa_size: Should always be CVMX_FPA_DFA_POOL_SIZE - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -static int __cvmx_helper_initialize_fpa(int pip_pool, int pip_size, - int pip_buffers, int wqe_pool, - int wqe_size, int wqe_entries, - int pko_pool, int pko_size, - int pko_buffers, int tim_pool, - int tim_size, int tim_buffers, - int dfa_pool, int dfa_size, - int dfa_buffers) -{ - int status; - - cvmx_fpa_enable(); - - if ((pip_buffers > 0) && (pip_buffers <= 64)) - cvmx_dprintf - ("Warning: %d packet buffers may not be enough for hardware" - " prefetch. 65 or more is recommended.\n", pip_buffers); - - if (pip_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(pip_pool, pip_size, - pip_buffers, - "Packet Buffers"); - if (status) - return status; - } - - if (wqe_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(wqe_pool, wqe_size, - wqe_entries, - "Work Queue Entries"); - if (status) - return status; - } - - if (pko_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(pko_pool, pko_size, - pko_buffers, - "PKO Command Buffers"); - if (status) - return status; - } - - if (tim_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(tim_pool, tim_size, - tim_buffers, - "TIM Command Buffers"); - if (status) - return status; - } - - if (dfa_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(dfa_pool, dfa_size, - dfa_buffers, - "DFA Command Buffers"); - if (status) - return status; - } - - return 0; -} - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Sizes of each element in the pools is - * controlled by the cvmx-config.h header file. Specifying - * zero for any parameter will cause that FPA pool to not be - * setup. This is useful if you aren't using some of the - * hardware and want to save memory. - * - * @packet_buffers: - * Number of packet buffers to allocate - * @work_queue_entries: - * Number of work queue entries - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -int cvmx_helper_initialize_fpa(int packet_buffers, int work_queue_entries, - int pko_buffers, int tim_buffers, - int dfa_buffers) -{ -#ifndef CVMX_FPA_PACKET_POOL -#define CVMX_FPA_PACKET_POOL -1 -#define CVMX_FPA_PACKET_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_WQE_POOL -#define CVMX_FPA_WQE_POOL -1 -#define CVMX_FPA_WQE_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_OUTPUT_BUFFER_POOL -#define CVMX_FPA_OUTPUT_BUFFER_POOL -1 -#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_TIMER_POOL -#define CVMX_FPA_TIMER_POOL -1 -#define CVMX_FPA_TIMER_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_DFA_POOL -#define CVMX_FPA_DFA_POOL -1 -#define CVMX_FPA_DFA_POOL_SIZE 0 -#endif - return __cvmx_helper_initialize_fpa(CVMX_FPA_PACKET_POOL, - CVMX_FPA_PACKET_POOL_SIZE, - packet_buffers, CVMX_FPA_WQE_POOL, - CVMX_FPA_WQE_POOL_SIZE, - work_queue_entries, - CVMX_FPA_OUTPUT_BUFFER_POOL, - CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, - pko_buffers, CVMX_FPA_TIMER_POOL, - CVMX_FPA_TIMER_POOL_SIZE, - tim_buffers, CVMX_FPA_DFA_POOL, - CVMX_FPA_DFA_POOL_SIZE, - dfa_buffers); -} diff --git a/arch/mips/include/asm/octeon/cvmx-helper-fpa.h b/arch/mips/include/asm/octeon/cvmx-helper-fpa.h deleted file mode 100644 index 5ff8c93..0000000 --- a/arch/mips/include/asm/octeon/cvmx-helper-fpa.h +++ /dev/null @@ -1,64 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Helper functions for FPA setup. - * - */ -#ifndef __CVMX_HELPER_H_FPA__ -#define __CVMX_HELPER_H_FPA__ - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Sizes of each element in the pools is - * controlled by the cvmx-config.h header file. Specifying - * zero for any parameter will cause that FPA pool to not be - * setup. This is useful if you aren't using some of the - * hardware and want to save memory. - * - * @packet_buffers: - * Number of packet buffers to allocate - * @work_queue_entries: - * Number of work queue entries - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -extern int cvmx_helper_initialize_fpa(int packet_buffers, - int work_queue_entries, int pko_buffers, - int tim_buffers, int dfa_buffers); - -#endif /* __CVMX_HELPER_H__ */ diff --git a/arch/mips/include/asm/octeon/cvmx-helper.h b/arch/mips/include/asm/octeon/cvmx-helper.h index 3169cd7..0ac6b9f 100644 --- a/arch/mips/include/asm/octeon/cvmx-helper.h +++ b/arch/mips/include/asm/octeon/cvmx-helper.h @@ -61,8 +61,6 @@ typedef union { } s; } cvmx_helper_link_info_t; -#include "cvmx-helper-fpa.h" - #include #include "cvmx-helper-loop.h" #include "cvmx-helper-npi.h" -- cgit v0.10.2 From 0b55561bc608abbbd1b5c98e0a4e9158334086c1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 24 Jul 2012 16:33:09 +0200 Subject: MIPS: BCM63XX: add support for "ipsec" clock This module is only available on BCM6368 so far and does not require resetting the block. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: mpm@selenic.com Cc: herbert@gondor.apana.org.au Patchwork: https://patchwork.linux-mips.org/patch/3324/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c index be49b9a..1db48ad 100644 --- a/arch/mips/bcm63xx/clk.c +++ b/arch/mips/bcm63xx/clk.c @@ -224,6 +224,18 @@ static struct clk clk_xtm = { }; /* + * IPsec clock + */ +static void ipsec_set(struct clk *clk, int enable) +{ + bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable); +} + +static struct clk clk_ipsec = { + .set = ipsec_set, +}; + +/* * Internal peripheral clock */ static struct clk clk_periph = { @@ -280,6 +292,8 @@ struct clk *clk_get(struct device *dev, const char *id) return &clk_periph; if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) return &clk_pcm; + if (BCMCPU_IS_6368() && !strcmp(id, "ipsec")) + return &clk_ipsec; return ERR_PTR(-ENOENT); } -- cgit v0.10.2 From 8aecfe946275d23a207c73dbaf7a7c7a8a80be24 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 24 Jul 2012 16:33:10 +0200 Subject: MIPS: BCM63XX: add RNG peripheral definitions Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: mpm@selenic.com Cc: herbert@gondor.apana.org.au Patchwork: https://patchwork.linux-mips.org/patch/3326/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index 82a8175..0c981aa 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -129,6 +129,7 @@ enum bcm63xx_regs_set { RSET_PCMDMA, RSET_PCMDMAC, RSET_PCMDMAS, + RSET_RNG }; #define RSET_DSL_LMEM_SIZE (64 * 1024 * 4) @@ -152,6 +153,7 @@ enum bcm63xx_regs_set { #define RSET_XTMDMA_SIZE 256 #define RSET_XTMDMAC_SIZE(chans) (16 * (chans)) #define RSET_XTMDMAS_SIZE(chans) (16 * (chans)) +#define RSET_RNG_SIZE 20 /* * 6338 register sets base address @@ -195,6 +197,7 @@ enum bcm63xx_regs_set { #define BCM_6338_PCMDMA_BASE (0xdeadbeef) #define BCM_6338_PCMDMAC_BASE (0xdeadbeef) #define BCM_6338_PCMDMAS_BASE (0xdeadbeef) +#define BCM_6338_RNG_BASE (0xdeadbeef) /* * 6345 register sets base address @@ -238,6 +241,7 @@ enum bcm63xx_regs_set { #define BCM_6345_PCMDMA_BASE (0xdeadbeef) #define BCM_6345_PCMDMAC_BASE (0xdeadbeef) #define BCM_6345_PCMDMAS_BASE (0xdeadbeef) +#define BCM_6345_RNG_BASE (0xdeadbeef) /* * 6348 register sets base address @@ -278,6 +282,7 @@ enum bcm63xx_regs_set { #define BCM_6348_PCMDMA_BASE (0xdeadbeef) #define BCM_6348_PCMDMAC_BASE (0xdeadbeef) #define BCM_6348_PCMDMAS_BASE (0xdeadbeef) +#define BCM_6348_RNG_BASE (0xdeadbeef) /* * 6358 register sets base address @@ -318,6 +323,7 @@ enum bcm63xx_regs_set { #define BCM_6358_PCMDMA_BASE (0xfffe1800) #define BCM_6358_PCMDMAC_BASE (0xfffe1900) #define BCM_6358_PCMDMAS_BASE (0xfffe1a00) +#define BCM_6358_RNG_BASE (0xdeadbeef) /* @@ -359,6 +365,7 @@ enum bcm63xx_regs_set { #define BCM_6368_PCMDMA_BASE (0xb0005800) #define BCM_6368_PCMDMAC_BASE (0xb0005a00) #define BCM_6368_PCMDMAS_BASE (0xb0005c00) +#define BCM_6368_RNG_BASE (0xb0004180) extern const unsigned long *bcm63xx_regs_base; @@ -404,6 +411,7 @@ extern const unsigned long *bcm63xx_regs_base; __GEN_RSET_BASE(__cpu, PCMDMA) \ __GEN_RSET_BASE(__cpu, PCMDMAC) \ __GEN_RSET_BASE(__cpu, PCMDMAS) \ + __GEN_RSET_BASE(__cpu, RNG) \ } #define __GEN_CPU_REGS_TABLE(__cpu) \ @@ -442,6 +450,7 @@ extern const unsigned long *bcm63xx_regs_base; [RSET_PCMDMA] = BCM_## __cpu ##_PCMDMA_BASE, \ [RSET_PCMDMAC] = BCM_## __cpu ##_PCMDMAC_BASE, \ [RSET_PCMDMAS] = BCM_## __cpu ##_PCMDMAS_BASE, \ + [RSET_RNG] = BCM_## __cpu ##_RNG_BASE, \ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set) diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index be107e9..6a8df56 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -974,6 +974,20 @@ #define M2M_DSTID_REG(x) ((x) * 0x40 + 0x18) /************************************************************************* + * _REG relative to RSET_RNG + *************************************************************************/ + +#define RNG_CTRL 0x00 +#define RNG_EN (1 << 0) + +#define RNG_STAT 0x04 +#define RNG_AVAIL_MASK (0xff000000) + +#define RNG_DATA 0x08 +#define RNG_THRES 0x0c +#define RNG_MASK 0x10 + +/************************************************************************* * _REG relative to RSET_SPI *************************************************************************/ -- cgit v0.10.2 From b73ab84199a9760cd99bd7329e58b6a8ce2eb36f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 24 Jul 2012 16:33:10 +0200 Subject: MIPS: BCM63XX: add RNG driver platform_device stub Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: mpm@selenic.com Cc: herbert@gondor.apana.org.au Patchwork: https://patchwork.linux-mips.org/patch/3325/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile index 4049cd5..349b206 100644 --- a/arch/mips/bcm63xx/Makefile +++ b/arch/mips/bcm63xx/Makefile @@ -1,6 +1,6 @@ obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \ - dev-dsp.o dev-enet.o dev-pcmcia.o dev-spi.o dev-uart.o \ - dev-wdt.o + dev-dsp.o dev-enet.o dev-pcmcia.o dev-rng.o dev-spi.o \ + dev-uart.o dev-wdt.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-y += boards/ diff --git a/arch/mips/bcm63xx/dev-rng.c b/arch/mips/bcm63xx/dev-rng.c new file mode 100644 index 0000000..d277b4d --- /dev/null +++ b/arch/mips/bcm63xx/dev-rng.c @@ -0,0 +1,40 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011 Florian Fainelli + */ + +#include +#include +#include +#include + +static struct resource rng_resources[] = { + { + .start = -1, /* filled at runtime */ + .end = -1, /* filled at runtime */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bcm63xx_rng_device = { + .name = "bcm63xx-rng", + .id = -1, + .num_resources = ARRAY_SIZE(rng_resources), + .resource = rng_resources, +}; + +int __init bcm63xx_rng_register(void) +{ + if (!BCMCPU_IS_6368()) + return -ENODEV; + + rng_resources[0].start = bcm63xx_regset_address(RSET_RNG); + rng_resources[0].end = rng_resources[0].start; + rng_resources[0].end += RSET_RNG_SIZE - 1; + + return platform_device_register(&bcm63xx_rng_device); +} +arch_initcall(bcm63xx_rng_register); -- cgit v0.10.2 From 553072b27e0990ab1d73d43efb4ab518f953fcc3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 24 Jul 2012 16:33:11 +0200 Subject: hw_random: add Broadcom BCM63xx RNG driver Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: mpm@selenic.com Cc: herbert@gondor.apana.org.au Patchwork: https://patchwork.linux-mips.org/patch/3327/ Patchwork: https://patchwork.linux-mips.org/patch/4072/ Signed-off-by: Ralf Baechle diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index f45dad3..6640311 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -73,6 +73,20 @@ config HW_RANDOM_ATMEL If unsure, say Y. +config HW_RANDOM_BCM63XX + tristate "Broadcom BCM63xx Random Number Generator support" + depends on HW_RANDOM && BCM63XX + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on the Broadcom BCM63xx SoCs. + + To compile this driver as a module, choose M here: the + module will be called bcm63xx-rng + + If unusure, say Y. + + config HW_RANDOM_GEODE tristate "AMD Geode HW Random Number Generator support" depends on HW_RANDOM && X86_32 && PCI diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index d901dfa..67f57bf 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o +obj-$(CONFIG_HW_RANDOM_BCM63XX) += bcm63xx-rng.o obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o n2-rng-y := n2-drv.o n2-asm.o diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c new file mode 100644 index 0000000..aec6a42 --- /dev/null +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -0,0 +1,175 @@ +/* + * Broadcom BCM63xx Random Number Generator support + * + * Copyright (C) 2011, Florian Fainelli + * Copyright (C) 2009, Broadcom Corporation + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct bcm63xx_rng_priv { + struct clk *clk; + void __iomem *regs; +}; + +#define to_rng_priv(rng) ((struct bcm63xx_rng_priv *)rng->priv) + +static int bcm63xx_rng_init(struct hwrng *rng) +{ + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + u32 val; + + val = bcm_readl(priv->regs + RNG_CTRL); + val |= RNG_EN; + bcm_writel(val, priv->regs + RNG_CTRL); + + return 0; +} + +static void bcm63xx_rng_cleanup(struct hwrng *rng) +{ + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + u32 val; + + val = bcm_readl(priv->regs + RNG_CTRL); + val &= ~RNG_EN; + bcm_writel(val, priv->regs + RNG_CTRL); +} + +static int bcm63xx_rng_data_present(struct hwrng *rng, int wait) +{ + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + + return bcm_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK; +} + +static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data) +{ + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + + *data = bcm_readl(priv->regs + RNG_DATA); + + return 4; +} + +static int __devinit bcm63xx_rng_probe(struct platform_device *pdev) +{ + struct resource *r; + struct clk *clk; + int ret; + struct bcm63xx_rng_priv *priv; + struct hwrng *rng; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no iomem resource\n"); + ret = -ENXIO; + goto out; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "no memory for private structure\n"); + ret = -ENOMEM; + goto out; + } + + rng = kzalloc(sizeof(*rng), GFP_KERNEL); + if (!rng) { + dev_err(&pdev->dev, "no memory for rng structure\n"); + ret = -ENOMEM; + goto out_free_priv; + } + + platform_set_drvdata(pdev, rng); + rng->priv = (unsigned long)priv; + rng->name = pdev->name; + rng->init = bcm63xx_rng_init; + rng->cleanup = bcm63xx_rng_cleanup; + rng->data_present = bcm63xx_rng_data_present; + rng->data_read = bcm63xx_rng_data_read; + + clk = clk_get(&pdev->dev, "ipsec"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "no clock for device\n"); + ret = PTR_ERR(clk); + goto out_free_rng; + } + + priv->clk = clk; + + if (!devm_request_mem_region(&pdev->dev, r->start, + resource_size(r), pdev->name)) { + dev_err(&pdev->dev, "request mem failed"); + ret = -ENOMEM; + goto out_free_rng; + } + + priv->regs = devm_ioremap_nocache(&pdev->dev, r->start, + resource_size(r)); + if (!priv->regs) { + dev_err(&pdev->dev, "ioremap failed"); + ret = -ENOMEM; + goto out_free_rng; + } + + clk_enable(clk); + + ret = hwrng_register(rng); + if (ret) { + dev_err(&pdev->dev, "failed to register rng device\n"); + goto out_clk_disable; + } + + dev_info(&pdev->dev, "registered RNG driver\n"); + + return 0; + +out_clk_disable: + clk_disable(clk); +out_free_rng: + platform_set_drvdata(pdev, NULL); + kfree(rng); +out_free_priv: + kfree(priv); +out: + return ret; +} + +static int __devexit bcm63xx_rng_remove(struct platform_device *pdev) +{ + struct hwrng *rng = platform_get_drvdata(pdev); + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + + hwrng_unregister(rng); + clk_disable(priv->clk); + kfree(priv); + kfree(rng); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver bcm63xx_rng_driver = { + .probe = bcm63xx_rng_probe, + .remove = __devexit_p(bcm63xx_rng_remove), + .driver = { + .name = "bcm63xx-rng", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(bcm63xx_rng_driver); + +MODULE_AUTHOR("Florian Fainelli "); +MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 4b897d5483da5c3f3c4d52440a994aad574b62b4 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 24 Jul 2012 16:33:11 +0200 Subject: MIPS: BCM63XX: Move flash registration out of board_bcm963xx.c board_bcm963xx.c is already large enough. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Patchwork: https://patchwork.linux-mips.org/patch/3952/ Reviewed-by: Florian Fainelli Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile index 349b206..833af72 100644 --- a/arch/mips/bcm63xx/Makefile +++ b/arch/mips/bcm63xx/Makefile @@ -1,6 +1,6 @@ obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \ - dev-dsp.o dev-enet.o dev-pcmcia.o dev-rng.o dev-spi.o \ - dev-uart.o dev-wdt.o + dev-dsp.o dev-enet.o dev-flash.o dev-pcmcia.o dev-rng.o \ + dev-spi.o dev-uart.o dev-wdt.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-y += boards/ diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index ea65c0f..bdfbdf9 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -11,9 +11,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -24,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -809,40 +807,6 @@ void __init board_setup(void) panic("unexpected CPU for bcm963xx board"); } -static struct mtd_partition mtd_partitions[] = { - { - .name = "cfe", - .offset = 0x0, - .size = 0x40000, - } -}; - -static const char *bcm63xx_part_types[] = { "bcm63xxpart", NULL }; - -static struct physmap_flash_data flash_data = { - .width = 2, - .nr_parts = ARRAY_SIZE(mtd_partitions), - .parts = mtd_partitions, - .part_probe_types = bcm63xx_part_types, -}; - -static struct resource mtd_resources[] = { - { - .start = 0, /* filled at runtime */ - .end = 0, /* filled at runtime */ - .flags = IORESOURCE_MEM, - } -}; - -static struct platform_device mtd_dev = { - .name = "physmap-flash", - .resource = mtd_resources, - .num_resources = ARRAY_SIZE(mtd_resources), - .dev = { - .platform_data = &flash_data, - }, -}; - static struct gpio_led_platform_data bcm63xx_led_data; static struct platform_device bcm63xx_gpio_leds = { @@ -856,8 +820,6 @@ static struct platform_device bcm63xx_gpio_leds = { */ int __init board_register_devices(void) { - u32 val; - if (board.has_uart0) bcm63xx_uart_register(0); @@ -893,14 +855,7 @@ int __init board_register_devices(void) bcm63xx_spi_register(); - /* read base address of boot chip select (0) */ - val = bcm_mpi_readl(MPI_CSBASE_REG(0)); - val &= MPI_CSBASE_BASE_MASK; - - mtd_resources[0].start = val; - mtd_resources[0].end = 0x1FFFFFFF; - - platform_device_register(&mtd_dev); + bcm63xx_flash_register(); bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds); bcm63xx_led_data.leds = board.leds; diff --git a/arch/mips/bcm63xx/dev-flash.c b/arch/mips/bcm63xx/dev-flash.c new file mode 100644 index 0000000..af52738 --- /dev/null +++ b/arch/mips/bcm63xx/dev-flash.c @@ -0,0 +1,69 @@ +/* + * Broadcom BCM63xx flash registration + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2008 Maxime Bizon + * Copyright (C) 2008 Florian Fainelli + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct mtd_partition mtd_partitions[] = { + { + .name = "cfe", + .offset = 0x0, + .size = 0x40000, + } +}; + +static const char *bcm63xx_part_types[] = { "bcm63xxpart", NULL }; + +static struct physmap_flash_data flash_data = { + .width = 2, + .parts = mtd_partitions, + .part_probe_types = bcm63xx_part_types, +}; + +static struct resource mtd_resources[] = { + { + .start = 0, /* filled at runtime */ + .end = 0, /* filled at runtime */ + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device mtd_dev = { + .name = "physmap-flash", + .resource = mtd_resources, + .num_resources = ARRAY_SIZE(mtd_resources), + .dev = { + .platform_data = &flash_data, + }, +}; + +int __init bcm63xx_flash_register(void) +{ + u32 val; + + /* read base address of boot chip select (0) */ + val = bcm_mpi_readl(MPI_CSBASE_REG(0)); + val &= MPI_CSBASE_BASE_MASK; + + mtd_resources[0].start = val; + mtd_resources[0].end = 0x1FFFFFFF; + + return platform_device_register(&mtd_dev); +} diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h new file mode 100644 index 0000000..8dcb541 --- /dev/null +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h @@ -0,0 +1,6 @@ +#ifndef __BCM63XX_FLASH_H +#define __BCM63XX_FLASH_H + +int __init bcm63xx_flash_register(void); + +#endif /* __BCM63XX_FLASH_H */ -- cgit v0.10.2 From aaf3fedb56c95b419eda4c5392e03ad9b82c4847 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 24 Jul 2012 16:33:11 +0200 Subject: MIPS: BCM63XX: Add flash type detection On BCM6358 and BCM6368 the attached flash type is exposed through a bootstrapping register. Use it for auto detecting the flash type on those and default to parallel flash for earlier SoCs. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Patchwork: https://patchwork.linux-mips.org/patch/3954/ Reviewed-by: Florian Fainelli Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/dev-flash.c b/arch/mips/bcm63xx/dev-flash.c index af52738..1051fae 100644 --- a/arch/mips/bcm63xx/dev-flash.c +++ b/arch/mips/bcm63xx/dev-flash.c @@ -7,6 +7,7 @@ * * Copyright (C) 2008 Maxime Bizon * Copyright (C) 2008 Florian Fainelli + * Copyright (C) 2012 Jonas Gorski */ #include @@ -54,16 +55,63 @@ static struct platform_device mtd_dev = { }, }; +static int __init bcm63xx_detect_flash_type(void) +{ + u32 val; + + switch (bcm63xx_get_cpu_id()) { + case BCM6338_CPU_ID: + case BCM6345_CPU_ID: + case BCM6348_CPU_ID: + /* no way to auto detect so assume parallel */ + return BCM63XX_FLASH_TYPE_PARALLEL; + case BCM6358_CPU_ID: + val = bcm_gpio_readl(GPIO_STRAPBUS_REG); + if (val & STRAPBUS_6358_BOOT_SEL_PARALLEL) + return BCM63XX_FLASH_TYPE_PARALLEL; + else + return BCM63XX_FLASH_TYPE_SERIAL; + case BCM6368_CPU_ID: + val = bcm_gpio_readl(GPIO_STRAPBUS_REG); + switch (val & STRAPBUS_6368_BOOT_SEL_MASK) { + case STRAPBUS_6368_BOOT_SEL_NAND: + return BCM63XX_FLASH_TYPE_NAND; + case STRAPBUS_6368_BOOT_SEL_SERIAL: + return BCM63XX_FLASH_TYPE_SERIAL; + case STRAPBUS_6368_BOOT_SEL_PARALLEL: + return BCM63XX_FLASH_TYPE_PARALLEL; + } + default: + return -EINVAL; + } +} + int __init bcm63xx_flash_register(void) { + int flash_type; u32 val; - /* read base address of boot chip select (0) */ - val = bcm_mpi_readl(MPI_CSBASE_REG(0)); - val &= MPI_CSBASE_BASE_MASK; + flash_type = bcm63xx_detect_flash_type(); - mtd_resources[0].start = val; - mtd_resources[0].end = 0x1FFFFFFF; + switch (flash_type) { + case BCM63XX_FLASH_TYPE_PARALLEL: + /* read base address of boot chip select (0) */ + val = bcm_mpi_readl(MPI_CSBASE_REG(0)); + val &= MPI_CSBASE_BASE_MASK; - return platform_device_register(&mtd_dev); + mtd_resources[0].start = val; + mtd_resources[0].end = 0x1FFFFFFF; + + return platform_device_register(&mtd_dev); + case BCM63XX_FLASH_TYPE_SERIAL: + pr_warn("unsupported serial flash detected\n"); + return -ENODEV; + case BCM63XX_FLASH_TYPE_NAND: + pr_warn("unsupported NAND flash detected\n"); + return -ENODEV; + default: + pr_err("flash detection failed for BCM%x: %d\n", + bcm63xx_get_cpu_id(), flash_type); + return -ENODEV; + } } diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h index 8dcb541..354b848 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h @@ -1,6 +1,12 @@ #ifndef __BCM63XX_FLASH_H #define __BCM63XX_FLASH_H +enum { + BCM63XX_FLASH_TYPE_PARALLEL, + BCM63XX_FLASH_TYPE_SERIAL, + BCM63XX_FLASH_TYPE_NAND, +}; + int __init bcm63xx_flash_register(void); #endif /* __BCM63XX_FLASH_H */ diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index 6a8df56..849fd97 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -507,6 +507,15 @@ #define GPIO_BASEMODE_6368_MASK 0x7 /* those bits must be kept as read in gpio basemode register*/ +#define GPIO_STRAPBUS_REG 0x40 +#define STRAPBUS_6358_BOOT_SEL_PARALLEL (1 << 1) +#define STRAPBUS_6358_BOOT_SEL_SERIAL (0 << 1) +#define STRAPBUS_6368_BOOT_SEL_MASK 0x3 +#define STRAPBUS_6368_BOOT_SEL_NAND 0 +#define STRAPBUS_6368_BOOT_SEL_SERIAL 1 +#define STRAPBUS_6368_BOOT_SEL_PARALLEL 3 + + /************************************************************************* * _REG relative to RSET_ENET *************************************************************************/ -- cgit v0.10.2 From 288752a8aa1be6cf89ee5066435a617efd97fb86 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 24 Jul 2012 16:33:12 +0200 Subject: MIPS: BCM63XX: Use the Chip ID register for identifying the SoC Newer BCM63XX SoCs use virtually the same CPU ID, differing only in the revision bits. But since they all have the Chip ID register at the same location, we can use that to identify the SoC we are running on. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Patchwork: https://patchwork.linux-mips.org/patch/3955/ Reviewed-by: Florian Fainelli Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c index 8f0d6c7..e3c1da5 100644 --- a/arch/mips/bcm63xx/cpu.c +++ b/arch/mips/bcm63xx/cpu.c @@ -228,17 +228,21 @@ void __init bcm63xx_cpu_init(void) bcm63xx_irqs = bcm6345_irqs; break; case CPU_BMIPS4350: - switch (read_c0_prid() & 0xf0) { - case 0x10: + if ((read_c0_prid() & 0xf0) == 0x10) { expected_cpu_id = BCM6358_CPU_ID; bcm63xx_regs_base = bcm6358_regs_base; bcm63xx_irqs = bcm6358_irqs; - break; - case 0x30: - expected_cpu_id = BCM6368_CPU_ID; - bcm63xx_regs_base = bcm6368_regs_base; - bcm63xx_irqs = bcm6368_irqs; - break; + } else { + /* all newer chips have the same chip id location */ + u16 chip_id = bcm_readw(BCM_6368_PERF_BASE); + + switch (chip_id) { + case BCM6368_CPU_ID: + expected_cpu_id = BCM6368_CPU_ID; + bcm63xx_regs_base = bcm6368_regs_base; + bcm63xx_irqs = bcm6368_irqs; + break; + } } break; } -- cgit v0.10.2 From e5766aea5b9b7519654261c27b639f567b5415b4 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 24 Jul 2012 16:33:12 +0200 Subject: MIPS: BCM63XX: Add basic BCM6328 support This includes CPU speed, memory size detection and working UART, but lacking the appropriate drivers, no support for attached flash. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Patchwork: https://patchwork.linux-mips.org/patch/3951/ Reviewed-by: Florian Fainelli Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig index 6b1b9ad..09e93ca 100644 --- a/arch/mips/bcm63xx/Kconfig +++ b/arch/mips/bcm63xx/Kconfig @@ -1,6 +1,9 @@ menu "CPU support" depends on BCM63XX +config BCM63XX_CPU_6328 + bool "support 6328 CPU" + config BCM63XX_CPU_6338 bool "support 6338 CPU" select HW_HAS_PCI diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index bdfbdf9..be7498a 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -708,9 +708,15 @@ void __init board_prom_init(void) char cfe_version[32]; u32 val; - /* read base address of boot chip select (0) */ - val = bcm_mpi_readl(MPI_CSBASE_REG(0)); - val &= MPI_CSBASE_BASE_MASK; + /* read base address of boot chip select (0) + * 6328 does not have MPI but boots from a fixed address + */ + if (BCMCPU_IS_6328()) + val = 0x18000000; + else { + val = bcm_mpi_readl(MPI_CSBASE_REG(0)); + val &= MPI_CSBASE_BASE_MASK; + } boot_addr = (u8 *)KSEG1ADDR(val); /* dump cfe version */ diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c index e3c1da5..a7afb28 100644 --- a/arch/mips/bcm63xx/cpu.c +++ b/arch/mips/bcm63xx/cpu.c @@ -29,6 +29,14 @@ static u16 bcm63xx_cpu_rev; static unsigned int bcm63xx_cpu_freq; static unsigned int bcm63xx_memory_size; +static const unsigned long bcm6328_regs_base[] = { + __GEN_CPU_REGS_TABLE(6328) +}; + +static const int bcm6328_irqs[] = { + __GEN_CPU_IRQ_TABLE(6328) +}; + static const unsigned long bcm6338_regs_base[] = { __GEN_CPU_REGS_TABLE(6338) }; @@ -99,6 +107,33 @@ unsigned int bcm63xx_get_memory_size(void) static unsigned int detect_cpu_clock(void) { switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + { + unsigned int tmp, mips_pll_fcvo; + + tmp = bcm_misc_readl(MISC_STRAPBUS_6328_REG); + mips_pll_fcvo = (tmp & STRAPBUS_6328_FCVO_MASK) + >> STRAPBUS_6328_FCVO_SHIFT; + + switch (mips_pll_fcvo) { + case 0x12: + case 0x14: + case 0x19: + return 160000000; + case 0x1c: + return 192000000; + case 0x13: + case 0x15: + return 200000000; + case 0x1a: + return 384000000; + case 0x16: + return 400000000; + default: + return 320000000; + } + + } case BCM6338_CPU_ID: /* BCM6338 has a fixed 240 Mhz frequency */ return 240000000; @@ -170,6 +205,9 @@ static unsigned int detect_memory_size(void) unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0; u32 val; + if (BCMCPU_IS_6328()) + return bcm_ddr_readl(DDR_CSEND_REG) << 24; + if (BCMCPU_IS_6345()) { val = bcm_sdram_readl(SDRAM_MBASE_REG); return (val * 8 * 1024 * 1024); @@ -237,6 +275,11 @@ void __init bcm63xx_cpu_init(void) u16 chip_id = bcm_readw(BCM_6368_PERF_BASE); switch (chip_id) { + case BCM6328_CPU_ID: + expected_cpu_id = BCM6328_CPU_ID; + bcm63xx_regs_base = bcm6328_regs_base; + bcm63xx_irqs = bcm6328_irqs; + break; case BCM6368_CPU_ID: expected_cpu_id = BCM6368_CPU_ID; bcm63xx_regs_base = bcm6368_regs_base; diff --git a/arch/mips/bcm63xx/dev-flash.c b/arch/mips/bcm63xx/dev-flash.c index 1051fae..58371c7 100644 --- a/arch/mips/bcm63xx/dev-flash.c +++ b/arch/mips/bcm63xx/dev-flash.c @@ -60,6 +60,12 @@ static int __init bcm63xx_detect_flash_type(void) u32 val; switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + val = bcm_misc_readl(MISC_STRAPBUS_6328_REG); + if (val & STRAPBUS_6328_BOOT_SEL_SERIAL) + return BCM63XX_FLASH_TYPE_SERIAL; + else + return BCM63XX_FLASH_TYPE_NAND; case BCM6338_CPU_ID: case BCM6345_CPU_ID: case BCM6348_CPU_ID: diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c index 67fa45b..e39f730 100644 --- a/arch/mips/bcm63xx/dev-spi.c +++ b/arch/mips/bcm63xx/dev-spi.c @@ -87,7 +87,7 @@ int __init bcm63xx_spi_register(void) { struct clk *periph_clk; - if (BCMCPU_IS_6345()) + if (BCMCPU_IS_6328() || BCMCPU_IS_6345()) return -ENODEV; periph_clk = clk_get(NULL, "periph"); diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 9a216a4..18e051a 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -27,6 +27,17 @@ static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused; static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; #ifndef BCMCPU_RUNTIME_DETECT +#ifdef CONFIG_BCM63XX_CPU_6328 +#define irq_stat_reg PERF_IRQSTAT_6328_REG +#define irq_mask_reg PERF_IRQMASK_6328_REG +#define irq_bits 64 +#define is_ext_irq_cascaded 1 +#define ext_irq_start (BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE) +#define ext_irq_end (BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE) +#define ext_irq_count 4 +#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6328 +#define ext_irq_cfg_reg2 0 +#endif #ifdef CONFIG_BCM63XX_CPU_6338 #define irq_stat_reg PERF_IRQSTAT_6338_REG #define irq_mask_reg PERF_IRQMASK_6338_REG @@ -118,6 +129,16 @@ static void bcm63xx_init_irq(void) irq_mask_addr = bcm63xx_regset_address(RSET_PERF); switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + irq_stat_addr += PERF_IRQSTAT_6328_REG; + irq_mask_addr += PERF_IRQMASK_6328_REG; + irq_bits = 64; + ext_irq_count = 4; + is_ext_irq_cascaded = 1; + ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE; + ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE; + ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328; + break; case BCM6338_CPU_ID: irq_stat_addr += PERF_IRQSTAT_6338_REG; irq_mask_addr += PERF_IRQMASK_6338_REG; diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c index 99d7f40..10eaff4 100644 --- a/arch/mips/bcm63xx/prom.c +++ b/arch/mips/bcm63xx/prom.c @@ -26,7 +26,9 @@ void __init prom_init(void) bcm_wdt_writel(WDT_STOP_2, WDT_CTL_REG); /* disable all hardware blocks clock for now */ - if (BCMCPU_IS_6338()) + if (BCMCPU_IS_6328()) + mask = CKCTL_6328_ALL_SAFE_EN; + else if (BCMCPU_IS_6338()) mask = CKCTL_6338_ALL_SAFE_EN; else if (BCMCPU_IS_6345()) mask = CKCTL_6345_ALL_SAFE_EN; diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index 356b055..0e74a13 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -68,6 +68,9 @@ void bcm63xx_machine_reboot(void) /* mask and clear all external irq */ switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + perf_regs[0] = PERF_EXTIRQ_CFG_REG_6328; + break; case BCM6338_CPU_ID: perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338; break; @@ -95,9 +98,13 @@ void bcm63xx_machine_reboot(void) bcm6348_a1_reboot(); printk(KERN_INFO "triggering watchdog soft-reset...\n"); - reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG); - reg |= SYS_PLL_SOFT_RESET; - bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG); + if (BCMCPU_IS_6328()) { + bcm_wdt_writel(1, WDT_SOFTRESET_REG); + } else { + reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG); + reg |= SYS_PLL_SOFT_RESET; + bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG); + } while (1) ; } diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index 0c981aa..b842b6d 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -9,6 +9,7 @@ * compile time if only one CPU support is enabled (idea stolen from * arm mach-types) */ +#define BCM6328_CPU_ID 0x6328 #define BCM6338_CPU_ID 0x6338 #define BCM6345_CPU_ID 0x6345 #define BCM6348_CPU_ID 0x6348 @@ -20,6 +21,19 @@ u16 __bcm63xx_get_cpu_id(void); u16 bcm63xx_get_cpu_rev(void); unsigned int bcm63xx_get_cpu_freq(void); +#ifdef CONFIG_BCM63XX_CPU_6328 +# ifdef bcm63xx_get_cpu_id +# undef bcm63xx_get_cpu_id +# define bcm63xx_get_cpu_id() __bcm63xx_get_cpu_id() +# define BCMCPU_RUNTIME_DETECT +# else +# define bcm63xx_get_cpu_id() BCM6328_CPU_ID +# endif +# define BCMCPU_IS_6328() (bcm63xx_get_cpu_id() == BCM6328_CPU_ID) +#else +# define BCMCPU_IS_6328() (0) +#endif + #ifdef CONFIG_BCM63XX_CPU_6338 # ifdef bcm63xx_get_cpu_id # undef bcm63xx_get_cpu_id @@ -129,7 +143,8 @@ enum bcm63xx_regs_set { RSET_PCMDMA, RSET_PCMDMAC, RSET_PCMDMAS, - RSET_RNG + RSET_RNG, + RSET_MISC }; #define RSET_DSL_LMEM_SIZE (64 * 1024 * 4) @@ -156,6 +171,49 @@ enum bcm63xx_regs_set { #define RSET_RNG_SIZE 20 /* + * 6328 register sets base address + */ +#define BCM_6328_DSL_LMEM_BASE (0xdeadbeef) +#define BCM_6328_PERF_BASE (0xb0000000) +#define BCM_6328_TIMER_BASE (0xb0000040) +#define BCM_6328_WDT_BASE (0xb000005c) +#define BCM_6328_UART0_BASE (0xb0000100) +#define BCM_6328_UART1_BASE (0xb0000120) +#define BCM_6328_GPIO_BASE (0xb0000080) +#define BCM_6328_SPI_BASE (0xdeadbeef) +#define BCM_6328_UDC0_BASE (0xdeadbeef) +#define BCM_6328_USBDMA_BASE (0xdeadbeef) +#define BCM_6328_OHCI0_BASE (0xdeadbeef) +#define BCM_6328_OHCI_PRIV_BASE (0xdeadbeef) +#define BCM_6328_USBH_PRIV_BASE (0xdeadbeef) +#define BCM_6328_MPI_BASE (0xdeadbeef) +#define BCM_6328_PCMCIA_BASE (0xdeadbeef) +#define BCM_6328_SDRAM_REGS_BASE (0xdeadbeef) +#define BCM_6328_DSL_BASE (0xb0001900) +#define BCM_6328_UBUS_BASE (0xdeadbeef) +#define BCM_6328_ENET0_BASE (0xdeadbeef) +#define BCM_6328_ENET1_BASE (0xdeadbeef) +#define BCM_6328_ENETDMA_BASE (0xb000d800) +#define BCM_6328_ENETDMAC_BASE (0xb000da00) +#define BCM_6328_ENETDMAS_BASE (0xb000dc00) +#define BCM_6328_ENETSW_BASE (0xb0e00000) +#define BCM_6328_EHCI0_BASE (0x10002500) +#define BCM_6328_SDRAM_BASE (0xdeadbeef) +#define BCM_6328_MEMC_BASE (0xdeadbeef) +#define BCM_6328_DDR_BASE (0xb0003000) +#define BCM_6328_M2M_BASE (0xdeadbeef) +#define BCM_6328_ATM_BASE (0xdeadbeef) +#define BCM_6328_XTM_BASE (0xdeadbeef) +#define BCM_6328_XTMDMA_BASE (0xb000b800) +#define BCM_6328_XTMDMAC_BASE (0xdeadbeef) +#define BCM_6328_XTMDMAS_BASE (0xdeadbeef) +#define BCM_6328_PCM_BASE (0xb000a800) +#define BCM_6328_PCMDMA_BASE (0xdeadbeef) +#define BCM_6328_PCMDMAC_BASE (0xdeadbeef) +#define BCM_6328_PCMDMAS_BASE (0xdeadbeef) +#define BCM_6328_RNG_BASE (0xdeadbeef) +#define BCM_6328_MISC_BASE (0xb0001800) +/* * 6338 register sets base address */ #define BCM_6338_DSL_LMEM_BASE (0xfff00000) @@ -198,6 +256,7 @@ enum bcm63xx_regs_set { #define BCM_6338_PCMDMAC_BASE (0xdeadbeef) #define BCM_6338_PCMDMAS_BASE (0xdeadbeef) #define BCM_6338_RNG_BASE (0xdeadbeef) +#define BCM_6338_MISC_BASE (0xdeadbeef) /* * 6345 register sets base address @@ -242,6 +301,7 @@ enum bcm63xx_regs_set { #define BCM_6345_PCMDMAC_BASE (0xdeadbeef) #define BCM_6345_PCMDMAS_BASE (0xdeadbeef) #define BCM_6345_RNG_BASE (0xdeadbeef) +#define BCM_6345_MISC_BASE (0xdeadbeef) /* * 6348 register sets base address @@ -283,6 +343,7 @@ enum bcm63xx_regs_set { #define BCM_6348_PCMDMAC_BASE (0xdeadbeef) #define BCM_6348_PCMDMAS_BASE (0xdeadbeef) #define BCM_6348_RNG_BASE (0xdeadbeef) +#define BCM_6348_MISC_BASE (0xdeadbeef) /* * 6358 register sets base address @@ -324,6 +385,7 @@ enum bcm63xx_regs_set { #define BCM_6358_PCMDMAC_BASE (0xfffe1900) #define BCM_6358_PCMDMAS_BASE (0xfffe1a00) #define BCM_6358_RNG_BASE (0xdeadbeef) +#define BCM_6358_MISC_BASE (0xdeadbeef) /* @@ -366,6 +428,7 @@ enum bcm63xx_regs_set { #define BCM_6368_PCMDMAC_BASE (0xb0005a00) #define BCM_6368_PCMDMAS_BASE (0xb0005c00) #define BCM_6368_RNG_BASE (0xb0004180) +#define BCM_6368_MISC_BASE (0xdeadbeef) extern const unsigned long *bcm63xx_regs_base; @@ -412,6 +475,7 @@ extern const unsigned long *bcm63xx_regs_base; __GEN_RSET_BASE(__cpu, PCMDMAC) \ __GEN_RSET_BASE(__cpu, PCMDMAS) \ __GEN_RSET_BASE(__cpu, RNG) \ + __GEN_RSET_BASE(__cpu, MISC) \ } #define __GEN_CPU_REGS_TABLE(__cpu) \ @@ -451,6 +515,7 @@ extern const unsigned long *bcm63xx_regs_base; [RSET_PCMDMAC] = BCM_## __cpu ##_PCMDMAC_BASE, \ [RSET_PCMDMAS] = BCM_## __cpu ##_PCMDMAS_BASE, \ [RSET_RNG] = BCM_## __cpu ##_RNG_BASE, \ + [RSET_MISC] = BCM_## __cpu ##_MISC_BASE, \ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set) @@ -458,6 +523,9 @@ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set) #ifdef BCMCPU_RUNTIME_DETECT return bcm63xx_regs_base[set]; #else +#ifdef CONFIG_BCM63XX_CPU_6328 + __GEN_RSET(6328) +#endif #ifdef CONFIG_BCM63XX_CPU_6338 __GEN_RSET(6338) #endif @@ -512,6 +580,47 @@ enum bcm63xx_irq { }; /* + * 6328 irqs + */ +#define BCM_6328_HIGH_IRQ_BASE (IRQ_INTERNAL_BASE + 32) + +#define BCM_6328_TIMER_IRQ (IRQ_INTERNAL_BASE + 31) +#define BCM_6328_SPI_IRQ 0 +#define BCM_6328_UART0_IRQ (IRQ_INTERNAL_BASE + 28) +#define BCM_6328_UART1_IRQ (BCM_6328_HIGH_IRQ_BASE + 7) +#define BCM_6328_DSL_IRQ (IRQ_INTERNAL_BASE + 4) +#define BCM_6328_UDC0_IRQ 0 +#define BCM_6328_ENET0_IRQ 0 +#define BCM_6328_ENET1_IRQ 0 +#define BCM_6328_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 12) +#define BCM_6328_OHCI0_IRQ (IRQ_INTERNAL_BASE + 9) +#define BCM_6328_EHCI0_IRQ (IRQ_INTERNAL_BASE + 10) +#define BCM_6328_PCMCIA_IRQ 0 +#define BCM_6328_ENET0_RXDMA_IRQ 0 +#define BCM_6328_ENET0_TXDMA_IRQ 0 +#define BCM_6328_ENET1_RXDMA_IRQ 0 +#define BCM_6328_ENET1_TXDMA_IRQ 0 +#define BCM_6328_PCI_IRQ (IRQ_INTERNAL_BASE + 23) +#define BCM_6328_ATM_IRQ 0 +#define BCM_6328_ENETSW_RXDMA0_IRQ (BCM_6328_HIGH_IRQ_BASE + 0) +#define BCM_6328_ENETSW_RXDMA1_IRQ (BCM_6328_HIGH_IRQ_BASE + 1) +#define BCM_6328_ENETSW_RXDMA2_IRQ (BCM_6328_HIGH_IRQ_BASE + 2) +#define BCM_6328_ENETSW_RXDMA3_IRQ (BCM_6328_HIGH_IRQ_BASE + 3) +#define BCM_6328_ENETSW_TXDMA0_IRQ (BCM_6328_HIGH_IRQ_BASE + 4) +#define BCM_6328_ENETSW_TXDMA1_IRQ (BCM_6328_HIGH_IRQ_BASE + 5) +#define BCM_6328_ENETSW_TXDMA2_IRQ (BCM_6328_HIGH_IRQ_BASE + 6) +#define BCM_6328_ENETSW_TXDMA3_IRQ (BCM_6328_HIGH_IRQ_BASE + 7) +#define BCM_6328_XTM_IRQ (BCM_6328_HIGH_IRQ_BASE + 31) +#define BCM_6328_XTM_DMA0_IRQ (BCM_6328_HIGH_IRQ_BASE + 11) + +#define BCM_6328_PCM_DMA0_IRQ (IRQ_INTERNAL_BASE + 2) +#define BCM_6328_PCM_DMA1_IRQ (IRQ_INTERNAL_BASE + 3) +#define BCM_6328_EXT_IRQ0 (IRQ_INTERNAL_BASE + 24) +#define BCM_6328_EXT_IRQ1 (IRQ_INTERNAL_BASE + 25) +#define BCM_6328_EXT_IRQ2 (IRQ_INTERNAL_BASE + 26) +#define BCM_6328_EXT_IRQ3 (IRQ_INTERNAL_BASE + 27) + +/* * 6338 irqs */ #define BCM_6338_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h index 1d7dd96..0a9891f 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h @@ -9,6 +9,8 @@ int __init bcm63xx_gpio_init(void); static inline unsigned long bcm63xx_gpio_count(void) { switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + return 32; case BCM6358_CPU_ID: return 40; case BCM6338_CPU_ID: diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h index 72477a6..6dcd8b2 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h @@ -91,5 +91,7 @@ #define bcm_memc_writel(v, o) bcm_rset_writel(RSET_MEMC, (v), (o)) #define bcm_ddr_readl(o) bcm_rset_readl(RSET_DDR, (o)) #define bcm_ddr_writel(v, o) bcm_rset_writel(RSET_DDR, (v), (o)) +#define bcm_misc_readl(o) bcm_rset_readl(RSET_MISC, (o)) +#define bcm_misc_writel(v, o) bcm_rset_writel(RSET_MISC, (v), (o)) #endif /* ! BCM63XX_IO_H_ */ diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index 849fd97..4fc2ab2 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -15,6 +15,30 @@ /* Clock Control register */ #define PERF_CKCTL_REG 0x4 +#define CKCTL_6328_PHYMIPS_EN (1 << 0) +#define CKCTL_6328_ADSL_QPROC_EN (1 << 1) +#define CKCTL_6328_ADSL_AFE_EN (1 << 2) +#define CKCTL_6328_ADSL_EN (1 << 3) +#define CKCTL_6328_MIPS_EN (1 << 4) +#define CKCTL_6328_SAR_EN (1 << 5) +#define CKCTL_6328_PCM_EN (1 << 6) +#define CKCTL_6328_USBD_EN (1 << 7) +#define CKCTL_6328_USBH_EN (1 << 8) +#define CKCTL_6328_HSSPI_EN (1 << 9) +#define CKCTL_6328_PCIE_EN (1 << 10) +#define CKCTL_6328_ROBOSW_EN (1 << 11) + +#define CKCTL_6328_ALL_SAFE_EN (CKCTL_6328_PHYMIPS_EN | \ + CKCTL_6328_ADSL_QPROC_EN | \ + CKCTL_6328_ADSL_AFE_EN | \ + CKCTL_6328_ADSL_EN | \ + CKCTL_6328_SAR_EN | \ + CKCTL_6328_PCM_EN | \ + CKCTL_6328_USBD_EN | \ + CKCTL_6328_USBH_EN | \ + CKCTL_6328_ROBOSW_EN | \ + CKCTL_6328_PCIE_EN) + #define CKCTL_6338_ADSLPHY_EN (1 << 0) #define CKCTL_6338_MPI_EN (1 << 1) #define CKCTL_6338_DRAM_EN (1 << 2) @@ -119,6 +143,7 @@ #define SYS_PLL_SOFT_RESET 0x1 /* Interrupt Mask register */ +#define PERF_IRQMASK_6328_REG 0x20 #define PERF_IRQMASK_6338_REG 0xc #define PERF_IRQMASK_6345_REG 0xc #define PERF_IRQMASK_6348_REG 0xc @@ -126,6 +151,7 @@ #define PERF_IRQMASK_6368_REG 0x20 /* Interrupt Status register */ +#define PERF_IRQSTAT_6328_REG 0x28 #define PERF_IRQSTAT_6338_REG 0x10 #define PERF_IRQSTAT_6345_REG 0x10 #define PERF_IRQSTAT_6348_REG 0x10 @@ -133,6 +159,7 @@ #define PERF_IRQSTAT_6368_REG 0x28 /* External Interrupt Configuration register */ +#define PERF_EXTIRQ_CFG_REG_6328 0x18 #define PERF_EXTIRQ_CFG_REG_6338 0x14 #define PERF_EXTIRQ_CFG_REG_6348 0x14 #define PERF_EXTIRQ_CFG_REG_6358 0x14 @@ -162,8 +189,21 @@ /* Soft Reset register */ #define PERF_SOFTRESET_REG 0x28 +#define PERF_SOFTRESET_6328_REG 0x10 #define PERF_SOFTRESET_6368_REG 0x10 +#define SOFTRESET_6328_SPI_MASK (1 << 0) +#define SOFTRESET_6328_EPHY_MASK (1 << 1) +#define SOFTRESET_6328_SAR_MASK (1 << 2) +#define SOFTRESET_6328_ENETSW_MASK (1 << 3) +#define SOFTRESET_6328_USBS_MASK (1 << 4) +#define SOFTRESET_6328_USBH_MASK (1 << 5) +#define SOFTRESET_6328_PCM_MASK (1 << 6) +#define SOFTRESET_6328_PCIE_CORE_MASK (1 << 7) +#define SOFTRESET_6328_PCIE_MASK (1 << 8) +#define SOFTRESET_6328_PCIE_EXT_MASK (1 << 9) +#define SOFTRESET_6328_PCIE_HARD_MASK (1 << 10) + #define SOFTRESET_6338_SPI_MASK (1 << 0) #define SOFTRESET_6338_ENET_MASK (1 << 2) #define SOFTRESET_6338_USBH_MASK (1 << 3) @@ -307,6 +347,8 @@ /* Watchdog reset length register */ #define WDT_RSTLEN_REG 0x8 +/* Watchdog soft reset register (BCM6328 only) */ +#define WDT_SOFTRESET_REG 0xc /************************************************************************* * _REG relative to RSET_UARTx @@ -933,6 +975,8 @@ * _REG relative to RSET_DDR *************************************************************************/ +#define DDR_CSEND_REG 0x8 + #define DDR_DMIPSPLLCFG_REG 0x18 #define DMIPSPLLCFG_M1_SHIFT 0 #define DMIPSPLLCFG_M1_MASK (0xff << DMIPSPLLCFG_M1_SHIFT) @@ -1115,4 +1159,14 @@ #define SPI_SSOFFTIME_SHIFT 3 #define SPI_BYTE_SWAP 0x80 +/************************************************************************* + * _REG relative to RSET_MISC + *************************************************************************/ + +#define MISC_STRAPBUS_6328_REG 0x240 +#define STRAPBUS_6328_FCVO_SHIFT 7 +#define STRAPBUS_6328_FCVO_MASK (0x1f << STRAPBUS_6328_FCVO_SHIFT) +#define STRAPBUS_6328_BOOT_SEL_SERIAL (1 << 28) +#define STRAPBUS_6328_BOOT_SEL_NAND (0 << 28) + #endif /* BCM63XX_REGS_H_ */ diff --git a/arch/mips/include/asm/mach-bcm63xx/ioremap.h b/arch/mips/include/asm/mach-bcm63xx/ioremap.h index ef94ba7..30931c4 100644 --- a/arch/mips/include/asm/mach-bcm63xx/ioremap.h +++ b/arch/mips/include/asm/mach-bcm63xx/ioremap.h @@ -18,6 +18,7 @@ static inline int is_bcm63xx_internal_registers(phys_t offset) if (offset >= 0xfff00000) return 1; break; + case BCM6328_CPU_ID: case BCM6368_CPU_ID: if (offset >= 0xb0000000 && offset < 0xb1000000) return 1; -- cgit v0.10.2 From 76f42fe8117c85fced0135b23835890cfa41a47b Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 24 Jul 2012 16:33:13 +0200 Subject: MIPS: BCM63XX: Move the PCI initialization into its own function Also make the cpu check a bit more explicit. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Patchwork: https://patchwork.linux-mips.org/patch/3953/ Reviewed-by: Florian Fainelli Signed-off-by: Ralf Baechle diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index 39eb7c4..a2b6d55 100644 --- a/arch/mips/pci/pci-bcm63xx.c +++ b/arch/mips/pci/pci-bcm63xx.c @@ -94,17 +94,10 @@ static void bcm63xx_int_cfg_writel(u32 val, u32 reg) void __iomem *pci_iospace_start; -static int __init bcm63xx_pci_init(void) +static int __init bcm63xx_register_pci(void) { unsigned int mem_size; u32 val; - - if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358() && !BCMCPU_IS_6368()) - return -ENODEV; - - if (!bcm63xx_pci_enabled) - return -ENODEV; - /* * configuration access are done through IO space, remap 4 * first bytes to access it from CPU. @@ -221,4 +214,20 @@ static int __init bcm63xx_pci_init(void) return 0; } + +static int __init bcm63xx_pci_init(void) +{ + if (!bcm63xx_pci_enabled) + return -ENODEV; + + switch (bcm63xx_get_cpu_id()) { + case BCM6348_CPU_ID: + case BCM6358_CPU_ID: + case BCM6368_CPU_ID: + return bcm63xx_register_pci(); + default: + return -ENODEV; + } +} + arch_initcall(bcm63xx_pci_init); -- cgit v0.10.2 From 19c860d932de520017c9b2d88cd9dff90b71ba36 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 24 Jul 2012 16:33:13 +0200 Subject: MIPS: BCM63XX: Add PCIe Support for BCM6328 Add support for the PCIe port found on BCM6328. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Patchwork: https://patchwork.linux-mips.org/patch/3956/ Reviewed-by: Florian Fainelli Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig index 09e93ca..d03e879 100644 --- a/arch/mips/bcm63xx/Kconfig +++ b/arch/mips/bcm63xx/Kconfig @@ -3,6 +3,7 @@ menu "CPU support" config BCM63XX_CPU_6328 bool "support 6328 CPU" + select HW_HAS_PCI config BCM63XX_CPU_6338 bool "support 6338 CPU" diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index b842b6d..e104ddb 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -122,6 +122,7 @@ enum bcm63xx_regs_set { RSET_USBH_PRIV, RSET_MPI, RSET_PCMCIA, + RSET_PCIE, RSET_DSL, RSET_ENET0, RSET_ENET1, @@ -188,6 +189,7 @@ enum bcm63xx_regs_set { #define BCM_6328_USBH_PRIV_BASE (0xdeadbeef) #define BCM_6328_MPI_BASE (0xdeadbeef) #define BCM_6328_PCMCIA_BASE (0xdeadbeef) +#define BCM_6328_PCIE_BASE (0xb0e40000) #define BCM_6328_SDRAM_REGS_BASE (0xdeadbeef) #define BCM_6328_DSL_BASE (0xb0001900) #define BCM_6328_UBUS_BASE (0xdeadbeef) @@ -232,6 +234,7 @@ enum bcm63xx_regs_set { #define BCM_6338_USBH_PRIV_BASE (0xdeadbeef) #define BCM_6338_MPI_BASE (0xfffe3160) #define BCM_6338_PCMCIA_BASE (0xdeadbeef) +#define BCM_6338_PCIE_BASE (0xdeadbeef) #define BCM_6338_SDRAM_REGS_BASE (0xfffe3100) #define BCM_6338_DSL_BASE (0xfffe1000) #define BCM_6338_UBUS_BASE (0xdeadbeef) @@ -279,6 +282,7 @@ enum bcm63xx_regs_set { #define BCM_6345_ENETSW_BASE (0xdeadbeef) #define BCM_6345_PCMCIA_BASE (0xfffe2028) #define BCM_6345_MPI_BASE (0xfffe2000) +#define BCM_6345_PCIE_BASE (0xdeadbeef) #define BCM_6345_OHCI0_BASE (0xfffe2100) #define BCM_6345_OHCI_PRIV_BASE (0xfffe2200) #define BCM_6345_USBH_PRIV_BASE (0xdeadbeef) @@ -320,6 +324,7 @@ enum bcm63xx_regs_set { #define BCM_6348_USBH_PRIV_BASE (0xdeadbeef) #define BCM_6348_MPI_BASE (0xfffe2000) #define BCM_6348_PCMCIA_BASE (0xfffe2054) +#define BCM_6348_PCIE_BASE (0xdeadbeef) #define BCM_6348_SDRAM_REGS_BASE (0xfffe2300) #define BCM_6348_M2M_BASE (0xfffe2800) #define BCM_6348_DSL_BASE (0xfffe3000) @@ -362,6 +367,7 @@ enum bcm63xx_regs_set { #define BCM_6358_USBH_PRIV_BASE (0xfffe1500) #define BCM_6358_MPI_BASE (0xfffe1000) #define BCM_6358_PCMCIA_BASE (0xfffe1054) +#define BCM_6358_PCIE_BASE (0xdeadbeef) #define BCM_6358_SDRAM_REGS_BASE (0xfffe2300) #define BCM_6358_M2M_BASE (0xdeadbeef) #define BCM_6358_DSL_BASE (0xfffe3000) @@ -405,6 +411,7 @@ enum bcm63xx_regs_set { #define BCM_6368_USBH_PRIV_BASE (0xb0001700) #define BCM_6368_MPI_BASE (0xb0001000) #define BCM_6368_PCMCIA_BASE (0xb0001054) +#define BCM_6368_PCIE_BASE (0xdeadbeef) #define BCM_6368_SDRAM_REGS_BASE (0xdeadbeef) #define BCM_6368_M2M_BASE (0xdeadbeef) #define BCM_6368_DSL_BASE (0xdeadbeef) @@ -453,6 +460,7 @@ extern const unsigned long *bcm63xx_regs_base; __GEN_RSET_BASE(__cpu, USBH_PRIV) \ __GEN_RSET_BASE(__cpu, MPI) \ __GEN_RSET_BASE(__cpu, PCMCIA) \ + __GEN_RSET_BASE(__cpu, PCIE) \ __GEN_RSET_BASE(__cpu, DSL) \ __GEN_RSET_BASE(__cpu, ENET0) \ __GEN_RSET_BASE(__cpu, ENET1) \ @@ -493,6 +501,7 @@ extern const unsigned long *bcm63xx_regs_base; [RSET_USBH_PRIV] = BCM_## __cpu ##_USBH_PRIV_BASE, \ [RSET_MPI] = BCM_## __cpu ##_MPI_BASE, \ [RSET_PCMCIA] = BCM_## __cpu ##_PCMCIA_BASE, \ + [RSET_PCIE] = BCM_## __cpu ##_PCIE_BASE, \ [RSET_DSL] = BCM_## __cpu ##_DSL_BASE, \ [RSET_ENET0] = BCM_## __cpu ##_ENET0_BASE, \ [RSET_ENET1] = BCM_## __cpu ##_ENET1_BASE, \ diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h index 6dcd8b2..9203d90 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h @@ -40,6 +40,10 @@ #define BCM_CB_MEM_END_PA (BCM_CB_MEM_BASE_PA + \ BCM_CB_MEM_SIZE - 1) +#define BCM_PCIE_MEM_BASE_PA 0x10f00000 +#define BCM_PCIE_MEM_SIZE (16 * 1024 * 1024) +#define BCM_PCIE_MEM_END_PA (BCM_PCIE_MEM_BASE_PA + \ + BCM_PCIE_MEM_SIZE - 1) /* * Internal registers are accessed through KSEG3 @@ -85,6 +89,8 @@ #define bcm_mpi_writel(v, o) bcm_rset_writel(RSET_MPI, (v), (o)) #define bcm_pcmcia_readl(o) bcm_rset_readl(RSET_PCMCIA, (o)) #define bcm_pcmcia_writel(v, o) bcm_rset_writel(RSET_PCMCIA, (v), (o)) +#define bcm_pcie_readl(o) bcm_rset_readl(RSET_PCIE, (o)) +#define bcm_pcie_writel(v, o) bcm_rset_writel(RSET_PCIE, (v), (o)) #define bcm_sdram_readl(o) bcm_rset_readl(RSET_SDRAM, (o)) #define bcm_sdram_writel(v, o) bcm_rset_writel(RSET_SDRAM, (v), (o)) #define bcm_memc_readl(o) bcm_rset_readl(RSET_MEMC, (o)) diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index 4fc2ab2..4ccc2a7 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -1162,6 +1162,9 @@ /************************************************************************* * _REG relative to RSET_MISC *************************************************************************/ +#define MISC_SERDES_CTRL_REG 0x0 +#define SERDES_PCIE_EN (1 << 0) +#define SERDES_PCIE_EXD_EN (1 << 15) #define MISC_STRAPBUS_6328_REG 0x240 #define STRAPBUS_6328_FCVO_SHIFT 7 @@ -1169,4 +1172,55 @@ #define STRAPBUS_6328_BOOT_SEL_SERIAL (1 << 28) #define STRAPBUS_6328_BOOT_SEL_NAND (0 << 28) +/************************************************************************* + * _REG relative to RSET_PCIE + *************************************************************************/ + +#define PCIE_CONFIG2_REG 0x408 +#define CONFIG2_BAR1_SIZE_EN 1 +#define CONFIG2_BAR1_SIZE_MASK 0xf + +#define PCIE_IDVAL3_REG 0x43c +#define IDVAL3_CLASS_CODE_MASK 0xffffff +#define IDVAL3_SUBCLASS_SHIFT 8 +#define IDVAL3_CLASS_SHIFT 16 + +#define PCIE_DLSTATUS_REG 0x1048 +#define DLSTATUS_PHYLINKUP (1 << 13) + +#define PCIE_BRIDGE_OPT1_REG 0x2820 +#define OPT1_RD_BE_OPT_EN (1 << 7) +#define OPT1_RD_REPLY_BE_FIX_EN (1 << 9) +#define OPT1_PCIE_BRIDGE_HOLE_DET_EN (1 << 11) +#define OPT1_L1_INT_STATUS_MASK_POL (1 << 12) + +#define PCIE_BRIDGE_OPT2_REG 0x2824 +#define OPT2_UBUS_UR_DECODE_DIS (1 << 2) +#define OPT2_TX_CREDIT_CHK_EN (1 << 4) +#define OPT2_CFG_TYPE1_BD_SEL (1 << 7) +#define OPT2_CFG_TYPE1_BUS_NO_SHIFT 16 +#define OPT2_CFG_TYPE1_BUS_NO_MASK (0xff << OPT2_CFG_TYPE1_BUS_NO_SHIFT) + +#define PCIE_BRIDGE_BAR0_BASEMASK_REG 0x2828 +#define PCIE_BRIDGE_BAR1_BASEMASK_REG 0x2830 +#define BASEMASK_REMAP_EN (1 << 0) +#define BASEMASK_SWAP_EN (1 << 1) +#define BASEMASK_MASK_SHIFT 4 +#define BASEMASK_MASK_MASK (0xfff << BASEMASK_MASK_SHIFT) +#define BASEMASK_BASE_SHIFT 20 +#define BASEMASK_BASE_MASK (0xfff << BASEMASK_BASE_SHIFT) + +#define PCIE_BRIDGE_BAR0_REBASE_ADDR_REG 0x282c +#define PCIE_BRIDGE_BAR1_REBASE_ADDR_REG 0x2834 +#define REBASE_ADDR_BASE_SHIFT 20 +#define REBASE_ADDR_BASE_MASK (0xfff << REBASE_ADDR_BASE_SHIFT) + +#define PCIE_BRIDGE_RC_INT_MASK_REG 0x2854 +#define PCIE_RC_INT_A (1 << 0) +#define PCIE_RC_INT_B (1 << 1) +#define PCIE_RC_INT_C (1 << 2) +#define PCIE_RC_INT_D (1 << 3) + +#define PCIE_DEVICE_OFFSET 0x8000 + #endif /* BCM63XX_REGS_H_ */ diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index 822ae17..4a15662 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c @@ -465,3 +465,64 @@ static void bcm63xx_fixup(struct pci_dev *dev) DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, bcm63xx_fixup); #endif + +static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn) +{ + switch (bus->number) { + case PCIE_BUS_BRIDGE: + return (PCI_SLOT(devfn) == 0); + case PCIE_BUS_DEVICE: + if (PCI_SLOT(devfn) == 0) + return bcm_pcie_readl(PCIE_DLSTATUS_REG) + & DLSTATUS_PHYLINKUP; + default: + return false; + } +} + +static int bcm63xx_pcie_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + u32 data; + u32 reg = where & ~3; + + if (!bcm63xx_pcie_can_access(bus, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (bus->number == PCIE_BUS_DEVICE) + reg += PCIE_DEVICE_OFFSET; + + data = bcm_pcie_readl(reg); + + *val = postprocess_read(data, where, size); + + return PCIBIOS_SUCCESSFUL; + +} + +static int bcm63xx_pcie_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 data; + u32 reg = where & ~3; + + if (!bcm63xx_pcie_can_access(bus, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (bus->number == PCIE_BUS_DEVICE) + reg += PCIE_DEVICE_OFFSET; + + + data = bcm_pcie_readl(reg); + + data = preprocess_write(data, val, where, size); + bcm_pcie_writel(data, reg); + + return PCIBIOS_SUCCESSFUL; +} + + +struct pci_ops bcm63xx_pcie_ops = { + .read = bcm63xx_pcie_read, + .write = bcm63xx_pcie_write +}; diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index a2b6d55..8a48139 100644 --- a/arch/mips/pci/pci-bcm63xx.c +++ b/arch/mips/pci/pci-bcm63xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "pci-bcm63xx.h" @@ -71,6 +72,26 @@ struct pci_controller bcm63xx_cb_controller = { }; #endif +static struct resource bcm_pcie_mem_resource = { + .name = "bcm63xx PCIe memory space", + .start = BCM_PCIE_MEM_BASE_PA, + .end = BCM_PCIE_MEM_END_PA, + .flags = IORESOURCE_MEM, +}; + +static struct resource bcm_pcie_io_resource = { + .name = "bcm63xx PCIe IO space", + .start = 0, + .end = 0, + .flags = 0, +}; + +struct pci_controller bcm63xx_pcie_controller = { + .pci_ops = &bcm63xx_pcie_ops, + .io_resource = &bcm_pcie_io_resource, + .mem_resource = &bcm_pcie_mem_resource, +}; + static u32 bcm63xx_int_cfg_readl(u32 reg) { u32 tmp; @@ -94,6 +115,95 @@ static void bcm63xx_int_cfg_writel(u32 val, u32 reg) void __iomem *pci_iospace_start; +static void __init bcm63xx_reset_pcie(void) +{ + u32 val; + + /* enable clock */ + val = bcm_perf_readl(PERF_CKCTL_REG); + val |= CKCTL_6328_PCIE_EN; + bcm_perf_writel(val, PERF_CKCTL_REG); + + /* enable SERDES */ + val = bcm_misc_readl(MISC_SERDES_CTRL_REG); + val |= SERDES_PCIE_EN | SERDES_PCIE_EXD_EN; + bcm_misc_writel(val, MISC_SERDES_CTRL_REG); + + /* reset the PCIe core */ + val = bcm_perf_readl(PERF_SOFTRESET_6328_REG); + + val &= ~SOFTRESET_6328_PCIE_MASK; + val &= ~SOFTRESET_6328_PCIE_CORE_MASK; + val &= ~SOFTRESET_6328_PCIE_HARD_MASK; + val &= ~SOFTRESET_6328_PCIE_EXT_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(10); + + val |= SOFTRESET_6328_PCIE_MASK; + val |= SOFTRESET_6328_PCIE_CORE_MASK; + val |= SOFTRESET_6328_PCIE_HARD_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(10); + + val |= SOFTRESET_6328_PCIE_EXT_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(200); +} + +static int __init bcm63xx_register_pcie(void) +{ + u32 val; + + bcm63xx_reset_pcie(); + + /* configure the PCIe bridge */ + val = bcm_pcie_readl(PCIE_BRIDGE_OPT1_REG); + val |= OPT1_RD_BE_OPT_EN; + val |= OPT1_RD_REPLY_BE_FIX_EN; + val |= OPT1_PCIE_BRIDGE_HOLE_DET_EN; + val |= OPT1_L1_INT_STATUS_MASK_POL; + bcm_pcie_writel(val, PCIE_BRIDGE_OPT1_REG); + + /* setup the interrupts */ + val = bcm_pcie_readl(PCIE_BRIDGE_RC_INT_MASK_REG); + val |= PCIE_RC_INT_A | PCIE_RC_INT_B | PCIE_RC_INT_C | PCIE_RC_INT_D; + bcm_pcie_writel(val, PCIE_BRIDGE_RC_INT_MASK_REG); + + val = bcm_pcie_readl(PCIE_BRIDGE_OPT2_REG); + /* enable credit checking and error checking */ + val |= OPT2_TX_CREDIT_CHK_EN; + val |= OPT2_UBUS_UR_DECODE_DIS; + + /* set device bus/func for the pcie device */ + val |= (PCIE_BUS_DEVICE << OPT2_CFG_TYPE1_BUS_NO_SHIFT); + val |= OPT2_CFG_TYPE1_BD_SEL; + bcm_pcie_writel(val, PCIE_BRIDGE_OPT2_REG); + + /* setup class code as bridge */ + val = bcm_pcie_readl(PCIE_IDVAL3_REG); + val &= ~IDVAL3_CLASS_CODE_MASK; + val |= (PCI_CLASS_BRIDGE_PCI << IDVAL3_SUBCLASS_SHIFT); + bcm_pcie_writel(val, PCIE_IDVAL3_REG); + + /* disable bar1 size */ + val = bcm_pcie_readl(PCIE_CONFIG2_REG); + val &= ~CONFIG2_BAR1_SIZE_MASK; + bcm_pcie_writel(val, PCIE_CONFIG2_REG); + + /* set bar0 to little endian */ + val = (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_BASE_SHIFT; + val |= (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_MASK_SHIFT; + val |= BASEMASK_REMAP_EN; + bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG); + + val = (BCM_PCIE_MEM_BASE_PA >> 20) << REBASE_ADDR_BASE_SHIFT; + bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG); + + register_pci_controller(&bcm63xx_pcie_controller); + + return 0; +} + static int __init bcm63xx_register_pci(void) { unsigned int mem_size; @@ -221,6 +331,8 @@ static int __init bcm63xx_pci_init(void) return -ENODEV; switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + return bcm63xx_register_pcie(); case BCM6348_CPU_ID: case BCM6358_CPU_ID: case BCM6368_CPU_ID: diff --git a/arch/mips/pci/pci-bcm63xx.h b/arch/mips/pci/pci-bcm63xx.h index a6e594e..e6736d5 100644 --- a/arch/mips/pci/pci-bcm63xx.h +++ b/arch/mips/pci/pci-bcm63xx.h @@ -13,11 +13,16 @@ */ #define CARDBUS_PCI_IDSEL 0x8 + +#define PCIE_BUS_BRIDGE 0 +#define PCIE_BUS_DEVICE 1 + /* * defined in ops-bcm63xx.c */ extern struct pci_ops bcm63xx_pci_ops; extern struct pci_ops bcm63xx_cb_ops; +extern struct pci_ops bcm63xx_pcie_ops; /* * defined in pci-bcm63xx.c -- cgit v0.10.2 From 3f787ca46810f929f0823856ef8d35b078ec3825 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 24 Jul 2012 16:33:14 +0200 Subject: MIPS: Expose PCIe drivers for MIPS Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Patchwork: https://patchwork.linux-mips.org/patch/3957/ Reviewed-by: Florian Fainelli Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b3e10fd..4ddecff 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2366,6 +2366,8 @@ config PCI_DOMAINS source "drivers/pci/Kconfig" +source "drivers/pci/pcie/Kconfig" + # # ISA support is now enabled via select. Too many systems still have the one # or other ISA chip on the board that users don't know about so don't expect -- cgit v0.10.2 From 2f74b770aa6deea65415e198852c832cceedf994 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 24 Jul 2012 16:33:14 +0200 Subject: MIPS: BCM63XX: Add 96328avng reference board This allows booting to command line. Ethernet is not supported yet, but PCIe connected wireless should work. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Maxime Bizon Cc: Florian Fainelli Cc: Kevin Cernekee Patchwork: https://patchwork.linux-mips.org/patch/3958/ Reviewed-by: Florian Fainelli Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index be7498a..feb0525 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -33,6 +33,48 @@ static unsigned int mac_addr_used; static struct board_info board; /* + * known 6328 boards + */ +#ifdef CONFIG_BCM63XX_CPU_6328 +static struct board_info __initdata board_96328avng = { + .name = "96328avng", + .expected_cpu_id = 0x6328, + + .has_uart0 = 1, + .has_pci = 1, + + .leds = { + { + .name = "96328avng::ppp-fail", + .gpio = 2, + .active_low = 1, + }, + { + .name = "96328avng::power", + .gpio = 4, + .active_low = 1, + .default_trigger = "default-on", + }, + { + .name = "96328avng::power-fail", + .gpio = 8, + .active_low = 1, + }, + { + .name = "96328avng::wps", + .gpio = 9, + .active_low = 1, + }, + { + .name = "96328avng::ppp", + .gpio = 11, + .active_low = 1, + }, + }, +}; +#endif + +/* * known 6338 boards */ #ifdef CONFIG_BCM63XX_CPU_6338 @@ -591,6 +633,9 @@ static struct board_info __initdata board_DWVS0 = { * all boards */ static const struct board_info __initdata *bcm963xx_boards[] = { +#ifdef CONFIG_BCM63XX_CPU_6328 + &board_96328avng, +#endif #ifdef CONFIG_BCM63XX_CPU_6338 &board_96338gw, &board_96338w, -- cgit v0.10.2 From cedc8ef87c3349a6645e285f920715380dd25ddc Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 17:26:34 +0200 Subject: MIPS: Netlogic: Update comments in smpboot.S No change in logic, comments update and whitespace cleanup. * A few comments in the file were in assembler style and the rest int C style, convert all of them to C style. * Mark workarounds for Ax silicon with a macro XLP_AX_WORKAROUND * Whitespace fixes - use tabs consistently * rename __config_lsu macro to xlp_config_lsu Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3749/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index c138b1a..c4872a7 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -54,28 +54,36 @@ XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \ SYS_CPU_NONCOHERENT_MODE * 4 -.macro __config_lsu - li t0, LSU_DEFEATURE - mfcr t1, t0 +#define XLP_AX_WORKAROUND /* enable Ax silicon workarounds */ - lui t2, 0x4080 /* Enable Unaligned Access, L2HPE */ - or t1, t1, t2 - li t2, ~0xe /* S1RCM */ +/* Enable XLP features and workarounds in the LSU */ +.macro xlp_config_lsu + li t0, LSU_DEFEATURE + mfcr t1, t0 + + lui t2, 0x4080 /* Enable Unaligned Access, L2HPE */ + or t1, t1, t2 +#ifdef XLP_AX_WORKAROUND + li t2, ~0xe /* S1RCM */ and t1, t1, t2 +#endif mtcr t1, t0 - li t0, SCHED_DEFEATURE - lui t1, 0x0100 /* Experimental: Disable BRU accepting ALU ops */ - mtcr t1, t0 +#ifdef XLP_AX_WORKAROUND + li t0, SCHED_DEFEATURE + lui t1, 0x0100 /* Disable BRU accepting ALU ops */ + mtcr t1, t0 +#endif .endm /* - * The cores can come start when they are woken up. This is also the NMI - * entry, so check that first. + * This is the code that will be copied to the reset entry point for + * XLR and XLP. The XLP cores start here when they are woken up. This + * is also the NMI entry point. * - * The data corresponding to reset is stored at RESET_DATA_PHYS location, - * this will have the thread mask (used when core is woken up) and the - * current NMI handler in case we reached here for an NMI. + * The data corresponding to reset/NMI is stored at RESET_DATA_PHYS + * location, this will have the thread mask (used when core is woken up) + * and the current NMI handler in case we reached here for an NMI. * * When a core or thread is newly woken up, it loops in a 'wait'. When * the CPU really needs waking up, we send an NMI to it, with the NMI @@ -89,12 +97,12 @@ FEXPORT(nlm_reset_entry) dmtc0 k0, $22, 6 dmtc0 k1, $22, 7 - mfc0 k0, CP0_STATUS - li k1, 0x80000 - and k1, k0, k1 - beqz k1, 1f /* go to real reset entry */ + mfc0 k0, CP0_STATUS + li k1, 0x80000 + and k1, k0, k1 + beqz k1, 1f /* go to real reset entry */ nop - li k1, CKSEG1ADDR(RESET_DATA_PHYS) /* NMI */ + li k1, CKSEG1ADDR(RESET_DATA_PHYS) /* NMI */ ld k0, BOOT_NMI_HANDLER(k1) jr k0 nop @@ -114,21 +122,23 @@ FEXPORT(nlm_reset_entry) li t2, SYS_CPU_COHERENT_BASE(0) add t2, t2, t3 /* t2 <- SYS offset for node */ lw t1, 0(t2) - and t1, t1, t0 - sw t1, 0(t2) + and t1, t1, t0 + sw t1, 0(t2) /* read back to ensure complete */ - lw t1, 0(t2) + lw t1, 0(t2) sync /* Configure LSU on Non-0 Cores. */ - __config_lsu + xlp_config_lsu + /* FALL THROUGH */ /* * Wake up sibling threads from the initial thread in * a core. */ EXPORT(nlm_boot_siblings) + /* Enable hw threads by writing to MAP_THREADMODE of the core */ li t0, CKSEG1ADDR(RESET_DATA_PHYS) lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ li t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE) @@ -139,13 +149,14 @@ EXPORT(nlm_boot_siblings) /* * The new hardware thread starts at the next instruction * For all the cases other than core 0 thread 0, we will - * jump to the secondary wait function. - */ + * jump to the secondary wait function. + */ mfc0 v0, CP0_EBASE, 1 andi v0, 0x7f /* v0 <- node/core */ -#if 1 - /* A0 errata - Write MMU_SETUP after changing thread mode register. */ + /* Init MMU in the first thread after changing THREAD_MODE + * register (Ax Errata?) + */ andi v1, v0, 0x3 /* v1 <- thread id */ bnez v1, 2f nop @@ -154,9 +165,8 @@ EXPORT(nlm_boot_siblings) li t1, 0 mtcr t1, t0 ehb -#endif -2: beqz v0, 4f +2: beqz v0, 4f /* boot cpu (cpuid == 0)? */ nop /* setup status reg */ @@ -183,9 +193,9 @@ EXPORT(nlm_boot_siblings) * For the boot CPU, we have to restore registers and * return */ -4: dmfc0 t0, $4, 2 /* restore SP from UserLocal */ +4: dmfc0 t0, $4, 2 /* restore SP from UserLocal */ li t1, 0xfadebeef - dmtc0 t1, $4, 2 /* restore SP from UserLocal */ + dmtc0 t1, $4, 2 /* restore SP from UserLocal */ PTR_SUBU sp, t0, PT_SIZE RESTORE_ALL jr ra @@ -193,7 +203,7 @@ EXPORT(nlm_boot_siblings) EXPORT(nlm_reset_entry_end) FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ - __config_lsu + xlp_config_lsu dmtc0 sp, $4, 2 /* SP saved in UserLocal */ SAVE_ALL sync @@ -234,36 +244,36 @@ END(nlm_boot_secondary_cpus) */ __CPUINIT NESTED(nlm_rmiboot_preboot, 16, sp) - mfc0 t0, $15, 1 # read ebase - andi t0, 0x1f # t0 has the processor_id() - andi t2, t0, 0x3 # thread no - sll t0, 2 # offset in cpu array + mfc0 t0, $15, 1 /* read ebase */ + andi t0, 0x1f /* t0 has the processor_id() */ + andi t2, t0, 0x3 /* thread num */ + sll t0, 2 /* offset in cpu array */ - PTR_LA t1, nlm_cpu_ready # mark CPU ready + PTR_LA t1, nlm_cpu_ready /* mark CPU ready */ PTR_ADDU t1, t0 li t3, 1 sw t3, 0(t1) - bnez t2, 1f # skip thread programming - nop # for non zero hw threads + bnez t2, 1f /* skip thread programming */ + nop /* for thread id != 0 */ /* - * MMU setup only for first thread in core + * XLR MMU setup only for first thread in core */ li t0, 0x400 mfcr t1, t0 - li t2, 6 # XLR thread mode mask + li t2, 6 /* XLR thread mode mask */ nor t3, t2, zero - and t2, t1, t2 # t2 - current thread mode + and t2, t1, t2 /* t2 - current thread mode */ li v0, CKSEG1ADDR(RESET_DATA_PHYS) - lw v1, BOOT_THREAD_MODE(v0) # v1 - new thread mode + lw v1, BOOT_THREAD_MODE(v0) /* v1 - new thread mode */ sll v1, 1 - beq v1, t2, 1f # same as request value - nop # nothing to do */ + beq v1, t2, 1f /* same as request value */ + nop /* nothing to do */ - and t2, t1, t3 # mask out old thread mode - or t1, t2, v1 # put in new value - mtcr t1, t0 # update core control + and t2, t1, t3 /* mask out old thread mode */ + or t1, t2, v1 /* put in new value */ + mtcr t1, t0 /* update core control */ 1: wait j 1b -- cgit v0.10.2 From 51d1eac0cd633b58be2a1e4e75765dc5bf913e6b Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 17:28:47 +0200 Subject: MIPS: Netlogic: SMP wakeup code update Update for core intialization code. Initialize status register after receiving NMI for CPU wakeup. Add the low level L1D flush code before enabling threads in core. Also convert the ehb to _ehb so that it works under more GCC versions. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3755/ Patchwork: https://patchwork.linux-mips.org/patch/4095/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h index bf7d41d..7b63a6b 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h @@ -47,7 +47,9 @@ #define CPU_BLOCKID_MAP 10 #define LSU_DEFEATURE 0x304 -#define LSU_CERRLOG_REGID 0x09 +#define LSU_DEBUG_ADDR 0x305 +#define LSU_DEBUG_DATA0 0x306 +#define LSU_CERRLOG_REGID 0x309 #define SCHED_DEFEATURE 0x700 /* Offsets of interest from the 'MAP' Block */ diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index c4872a7..d6431b7 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -80,6 +80,38 @@ * This is the code that will be copied to the reset entry point for * XLR and XLP. The XLP cores start here when they are woken up. This * is also the NMI entry point. + */ +.macro xlp_flush_l1_dcache + li t0, LSU_DEBUG_DATA0 + li t1, LSU_DEBUG_ADDR + li t2, 0 /* index */ + li t3, 0x1000 /* loop count */ +1: + sll v0, t2, 5 + mtcr zero, t0 + ori v1, v0, 0x3 /* way0 | write_enable | write_active */ + mtcr v1, t1 +2: + mfcr v1, t1 + andi v1, 0x1 /* wait for write_active == 0 */ + bnez v1, 2b + nop + mtcr zero, t0 + ori v1, v0, 0x7 /* way1 | write_enable | write_active */ + mtcr v1, t1 +3: + mfcr v1, t1 + andi v1, 0x1 /* wait for write_active == 0 */ + bnez v1, 3b + nop + addi t2, 1 + bne t3, t2, 1b + nop +.endm + +/* + * The cores can come start when they are woken up. This is also the NMI + * entry, so check that first. * * The data corresponding to reset/NMI is stored at RESET_DATA_PHYS * location, this will have the thread mask (used when core is woken up) @@ -138,6 +170,8 @@ FEXPORT(nlm_reset_entry) * a core. */ EXPORT(nlm_boot_siblings) + /* core L1D flush before enable threads */ + xlp_flush_l1_dcache /* Enable hw threads by writing to MAP_THREADMODE of the core */ li t0, CKSEG1ADDR(RESET_DATA_PHYS) lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ @@ -164,16 +198,13 @@ EXPORT(nlm_boot_siblings) li t0, MMU_SETUP li t1, 0 mtcr t1, t0 - ehb + _ehb 2: beqz v0, 4f /* boot cpu (cpuid == 0)? */ nop /* setup status reg */ - mfc0 t1, CP0_STATUS - li t0, ST0_BEV - or t1, t0 - xor t1, t0 + move t1, zero #ifdef CONFIG_64BIT ori t1, ST0_KX #endif @@ -220,6 +251,12 @@ FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ __CPUINIT NESTED(nlm_boot_secondary_cpus, 16, sp) + /* Initialize CP0 Status */ + move t1, zero +#ifdef CONFIG_64BIT + ori t1, ST0_KX +#endif + mtc0 t1, CP0_STATUS PTR_LA t1, nlm_next_sp PTR_L sp, 0(t1) PTR_LA t1, nlm_next_gp -- cgit v0.10.2 From c5a48ff81e25c8585dae981a6cc19ed55788cadf Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 17:28:53 +0200 Subject: MIPS: Netlogic: Remove NETLOGIC_ prefix Remove NETLOGIC_ prefix from gpio register definitions, this will bring it in-line with the other Netlogic headers. Having NETLOGIC prefix here is misleading because these are XLR/XLS specific register definitions. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3754/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/netlogic/xlr/gpio.h b/arch/mips/include/asm/netlogic/xlr/gpio.h index 51f6ad4..8492e83 100644 --- a/arch/mips/include/asm/netlogic/xlr/gpio.h +++ b/arch/mips/include/asm/netlogic/xlr/gpio.h @@ -35,39 +35,40 @@ #ifndef _ASM_NLM_GPIO_H #define _ASM_NLM_GPIO_H -#define NETLOGIC_GPIO_INT_EN_REG 0 -#define NETLOGIC_GPIO_INPUT_INVERSION_REG 1 -#define NETLOGIC_GPIO_IO_DIR_REG 2 -#define NETLOGIC_GPIO_IO_DATA_WR_REG 3 -#define NETLOGIC_GPIO_IO_DATA_RD_REG 4 +#define GPIO_INT_EN_REG 0 +#define GPIO_INPUT_INVERSION_REG 1 +#define GPIO_IO_DIR_REG 2 +#define GPIO_IO_DATA_WR_REG 3 +#define GPIO_IO_DATA_RD_REG 4 -#define NETLOGIC_GPIO_SWRESET_REG 8 -#define NETLOGIC_GPIO_DRAM1_CNTRL_REG 9 -#define NETLOGIC_GPIO_DRAM1_RATIO_REG 10 -#define NETLOGIC_GPIO_DRAM1_RESET_REG 11 -#define NETLOGIC_GPIO_DRAM1_STATUS_REG 12 -#define NETLOGIC_GPIO_DRAM2_CNTRL_REG 13 -#define NETLOGIC_GPIO_DRAM2_RATIO_REG 14 -#define NETLOGIC_GPIO_DRAM2_RESET_REG 15 -#define NETLOGIC_GPIO_DRAM2_STATUS_REG 16 +#define GPIO_SWRESET_REG 8 +#define GPIO_DRAM1_CNTRL_REG 9 +#define GPIO_DRAM1_RATIO_REG 10 +#define GPIO_DRAM1_RESET_REG 11 +#define GPIO_DRAM1_STATUS_REG 12 +#define GPIO_DRAM2_CNTRL_REG 13 +#define GPIO_DRAM2_RATIO_REG 14 +#define GPIO_DRAM2_RESET_REG 15 +#define GPIO_DRAM2_STATUS_REG 16 -#define NETLOGIC_GPIO_PWRON_RESET_CFG_REG 21 -#define NETLOGIC_GPIO_BIST_ALL_GO_STATUS_REG 24 -#define NETLOGIC_GPIO_BIST_CPU_GO_STATUS_REG 25 -#define NETLOGIC_GPIO_BIST_DEV_GO_STATUS_REG 26 +#define GPIO_PWRON_RESET_CFG_REG 21 +#define GPIO_BIST_ALL_GO_STATUS_REG 24 +#define GPIO_BIST_CPU_GO_STATUS_REG 25 +#define GPIO_BIST_DEV_GO_STATUS_REG 26 -#define NETLOGIC_GPIO_FUSE_BANK_REG 35 -#define NETLOGIC_GPIO_CPU_RESET_REG 40 -#define NETLOGIC_GPIO_RNG_REG 43 +#define GPIO_FUSE_BANK_REG 35 +#define GPIO_CPU_RESET_REG 40 +#define GPIO_RNG_REG 43 -#define NETLOGIC_PWRON_RESET_PCMCIA_BOOT 17 -#define NETLOGIC_GPIO_LED_BITMAP 0x1700000 -#define NETLOGIC_GPIO_LED_0_SHIFT 20 -#define NETLOGIC_GPIO_LED_1_SHIFT 24 +#define PWRON_RESET_PCMCIA_BOOT 17 -#define NETLOGIC_GPIO_LED_OUTPUT_CODE_RESET 0x01 -#define NETLOGIC_GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02 -#define NETLOGIC_GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03 -#define NETLOGIC_GPIO_LED_OUTPUT_CODE_MAIN 0x04 +#define GPIO_LED_BITMAP 0x1700000 +#define GPIO_LED_0_SHIFT 20 +#define GPIO_LED_1_SHIFT 24 + +#define GPIO_LED_OUTPUT_CODE_RESET 0x01 +#define GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02 +#define GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03 +#define GPIO_LED_OUTPUT_CODE_MAIN 0x04 #endif diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index c9d066d..81b1d31 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -85,7 +85,7 @@ static void nlm_linux_exit(void) gpiobase = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */ - nlm_write_reg(gpiobase, NETLOGIC_GPIO_SWRESET_REG, 1); + nlm_write_reg(gpiobase, GPIO_SWRESET_REG, 1); for ( ; ; ) cpu_wait(); } -- cgit v0.10.2 From f35574a3abe4fc85db6d3d7f7915f7e857373155 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 17:28:53 +0200 Subject: MIPS: Netlogic: Platform changes for XLS USB Add USB initialization code, setup resources and add USB platform driver in mips/netlogic/xlr/platform.c. Add USB support for XLR/XLS platform in Kconfig. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3759/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b3e10fd..96bad98 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -787,6 +787,8 @@ config NLM_XLR_BOARD select ZONE_DMA if 64BIT select SYNC_R4K select SYS_HAS_EARLY_PRINTK + select USB_ARCH_HAS_OHCI if USB_SUPPORT + select USB_ARCH_HAS_EHCI if USB_SUPPORT help Support for systems based on Netlogic XLR and XLS processors. Say Y here if you have a XLR or XLS based board. diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index eab64b4..cb0ab63 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -97,3 +97,92 @@ static int __init nlm_uart_init(void) } arch_initcall(nlm_uart_init); + +#ifdef CONFIG_USB +/* Platform USB devices, only on XLS chips */ +static u64 xls_usb_dmamask = ~(u32)0; +#define USB_PLATFORM_DEV(n, i, irq) \ + { \ + .name = n, \ + .id = i, \ + .num_resources = 2, \ + .dev = { \ + .dma_mask = &xls_usb_dmamask, \ + .coherent_dma_mask = 0xffffffff, \ + }, \ + .resource = (struct resource[]) { \ + { \ + .flags = IORESOURCE_MEM, \ + }, \ + { \ + .start = irq, \ + .end = irq, \ + .flags = IORESOURCE_IRQ, \ + }, \ + }, \ + } + +static struct platform_device xls_usb_ehci_device = + USB_PLATFORM_DEV("ehci-xls", 0, PIC_USB_IRQ); +static struct platform_device xls_usb_ohci_device_0 = + USB_PLATFORM_DEV("ohci-xls-0", 1, PIC_USB_IRQ); +static struct platform_device xls_usb_ohci_device_1 = + USB_PLATFORM_DEV("ohci-xls-1", 2, PIC_USB_IRQ); + +static struct platform_device *xls_platform_devices[] = { + &xls_usb_ehci_device, + &xls_usb_ohci_device_0, + &xls_usb_ohci_device_1, +}; + +int xls_platform_usb_init(void) +{ + uint64_t usb_mmio, gpio_mmio; + unsigned long memres; + uint32_t val; + + if (!nlm_chip_is_xls()) + return 0; + + gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); + usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_1_OFFSET); + + /* Clear Rogue Phy INTs */ + nlm_write_reg(usb_mmio, 49, 0x10000000); + /* Enable all interrupts */ + nlm_write_reg(usb_mmio, 50, 0x1f000000); + + /* Enable ports */ + nlm_write_reg(usb_mmio, 1, 0x07000500); + + val = nlm_read_reg(gpio_mmio, 21); + if (((val >> 22) & 0x01) == 0) { + pr_info("Detected USB Device mode - Not supported!\n"); + nlm_write_reg(usb_mmio, 0, 0x01000000); + return 0; + } + + pr_info("Detected USB Host mode - Adding XLS USB devices.\n"); + /* Clear reset, host mode */ + nlm_write_reg(usb_mmio, 0, 0x02000000); + + /* Memory resource for various XLS usb ports */ + usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_0_OFFSET); + memres = CPHYSADDR((unsigned long)usb_mmio); + xls_usb_ehci_device.resource[0].start = memres; + xls_usb_ehci_device.resource[0].end = memres + 0x400 - 1; + + memres += 0x400; + xls_usb_ohci_device_0.resource[0].start = memres; + xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1; + + memres += 0x400; + xls_usb_ohci_device_1.resource[0].start = memres; + xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1; + + return platform_add_devices(xls_platform_devices, + ARRAY_SIZE(xls_platform_devices)); +} + +arch_initcall(xls_platform_usb_init); +#endif -- cgit v0.10.2 From 3a2f9b99058cbe3f1b01297d29dc5b376563f670 Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Tue, 24 Jul 2012 17:28:54 +0200 Subject: MIPS: Netlogic: Platform NAND/NOR flash support Changes to add support for the boot NOR flash on XLR boards and the boot NAND/NOR flash drivers on the XLS boards. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3758/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/netlogic/xlr/bridge.h b/arch/mips/include/asm/netlogic/xlr/bridge.h new file mode 100644 index 0000000..2d02428 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/bridge.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ASM_NLM_BRIDGE_H_ +#define _ASM_NLM_BRIDGE_H_ + +#define BRIDGE_DRAM_0_BAR 0 +#define BRIDGE_DRAM_1_BAR 1 +#define BRIDGE_DRAM_2_BAR 2 +#define BRIDGE_DRAM_3_BAR 3 +#define BRIDGE_DRAM_4_BAR 4 +#define BRIDGE_DRAM_5_BAR 5 +#define BRIDGE_DRAM_6_BAR 6 +#define BRIDGE_DRAM_7_BAR 7 +#define BRIDGE_DRAM_CHN_0_MTR_0_BAR 8 +#define BRIDGE_DRAM_CHN_0_MTR_1_BAR 9 +#define BRIDGE_DRAM_CHN_0_MTR_2_BAR 10 +#define BRIDGE_DRAM_CHN_0_MTR_3_BAR 11 +#define BRIDGE_DRAM_CHN_0_MTR_4_BAR 12 +#define BRIDGE_DRAM_CHN_0_MTR_5_BAR 13 +#define BRIDGE_DRAM_CHN_0_MTR_6_BAR 14 +#define BRIDGE_DRAM_CHN_0_MTR_7_BAR 15 +#define BRIDGE_DRAM_CHN_1_MTR_0_BAR 16 +#define BRIDGE_DRAM_CHN_1_MTR_1_BAR 17 +#define BRIDGE_DRAM_CHN_1_MTR_2_BAR 18 +#define BRIDGE_DRAM_CHN_1_MTR_3_BAR 19 +#define BRIDGE_DRAM_CHN_1_MTR_4_BAR 20 +#define BRIDGE_DRAM_CHN_1_MTR_5_BAR 21 +#define BRIDGE_DRAM_CHN_1_MTR_6_BAR 22 +#define BRIDGE_DRAM_CHN_1_MTR_7_BAR 23 +#define BRIDGE_CFG_BAR 24 +#define BRIDGE_PHNX_IO_BAR 25 +#define BRIDGE_FLASH_BAR 26 +#define BRIDGE_SRAM_BAR 27 +#define BRIDGE_HTMEM_BAR 28 +#define BRIDGE_HTINT_BAR 29 +#define BRIDGE_HTPIC_BAR 30 +#define BRIDGE_HTSM_BAR 31 +#define BRIDGE_HTIO_BAR 32 +#define BRIDGE_HTCFG_BAR 33 +#define BRIDGE_PCIXCFG_BAR 34 +#define BRIDGE_PCIXMEM_BAR 35 +#define BRIDGE_PCIXIO_BAR 36 +#define BRIDGE_DEVICE_MASK 37 +#define BRIDGE_AERR_INTR_LOG1 38 +#define BRIDGE_AERR_INTR_LOG2 39 +#define BRIDGE_AERR_INTR_LOG3 40 +#define BRIDGE_AERR_DEV_STAT 41 +#define BRIDGE_AERR1_LOG1 42 +#define BRIDGE_AERR1_LOG2 43 +#define BRIDGE_AERR1_LOG3 44 +#define BRIDGE_AERR1_DEV_STAT 45 +#define BRIDGE_AERR_INTR_EN 46 +#define BRIDGE_AERR_UPG 47 +#define BRIDGE_AERR_CLEAR 48 +#define BRIDGE_AERR1_CLEAR 49 +#define BRIDGE_SBE_COUNTS 50 +#define BRIDGE_DBE_COUNTS 51 +#define BRIDGE_BITERR_INT_EN 52 + +#define BRIDGE_SYS2IO_CREDITS 53 +#define BRIDGE_EVNT_CNT_CTRL1 54 +#define BRIDGE_EVNT_COUNTER1 55 +#define BRIDGE_EVNT_CNT_CTRL2 56 +#define BRIDGE_EVNT_COUNTER2 57 +#define BRIDGE_RESERVED1 58 + +#define BRIDGE_DEFEATURE 59 +#define BRIDGE_SCRATCH0 60 +#define BRIDGE_SCRATCH1 61 +#define BRIDGE_SCRATCH2 62 +#define BRIDGE_SCRATCH3 63 + +#endif diff --git a/arch/mips/include/asm/netlogic/xlr/flash.h b/arch/mips/include/asm/netlogic/xlr/flash.h new file mode 100644 index 0000000..f8aca54 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/flash.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ASM_NLM_FLASH_H_ +#define _ASM_NLM_FLASH_H_ + +#define FLASH_CSBASE_ADDR(cs) (cs) +#define FLASH_CSADDR_MASK(cs) (0x10 + (cs)) +#define FLASH_CSDEV_PARM(cs) (0x20 + (cs)) +#define FLASH_CSTIME_PARMA(cs) (0x30 + (cs)) +#define FLASH_CSTIME_PARMB(cs) (0x40 + (cs)) + +#define FLASH_INT_MASK 0x50 +#define FLASH_INT_STATUS 0x60 +#define FLASH_ERROR_STATUS 0x70 +#define FLASH_ERROR_ADDR 0x80 + +#define FLASH_NAND_CLE(cs) (0x90 + (cs)) +#define FLASH_NAND_ALE(cs) (0xa0 + (cs)) + +#define FLASH_NAND_CSDEV_PARAM 0x000041e6 +#define FLASH_NAND_CSTIME_PARAMA 0x4f400e22 +#define FLASH_NAND_CSTIME_PARAMB 0x000083cf + +#endif diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile index f01e4d7..c287dea 100644 --- a/arch/mips/netlogic/xlr/Makefile +++ b/arch/mips/netlogic/xlr/Makefile @@ -1,2 +1,2 @@ -obj-y += setup.o platform.o +obj-y += setup.o platform.o platform-flash.o obj-$(CONFIG_SMP) += wakeup.o diff --git a/arch/mips/netlogic/xlr/platform-flash.c b/arch/mips/netlogic/xlr/platform-flash.c new file mode 100644 index 0000000..340ab16 --- /dev/null +++ b/arch/mips/netlogic/xlr/platform-flash.c @@ -0,0 +1,220 @@ +/* + * Copyright 2011, Netlogic Microsystems. + * Copyright 2004, Matt Porter + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * Default NOR partition layout + */ +static struct mtd_partition xlr_nor_parts[] = { + { + .name = "User FS", + .offset = 0x800000, + .size = MTDPART_SIZ_FULL, + } +}; + +/* + * Default NAND partition layout + */ +static struct mtd_partition xlr_nand_parts[] = { + { + .name = "Root Filesystem", + .offset = 64 * 64 * 2048, + .size = 432 * 64 * 2048, + }, + { + .name = "Home Filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +/* Use PHYSMAP flash for NOR */ +struct physmap_flash_data xlr_nor_data = { + .width = 2, + .parts = xlr_nor_parts, + .nr_parts = ARRAY_SIZE(xlr_nor_parts), +}; + +static struct resource xlr_nor_res[] = { + { + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device xlr_nor_dev = { + .name = "physmap-flash", + .dev = { + .platform_data = &xlr_nor_data, + }, + .num_resources = ARRAY_SIZE(xlr_nor_res), + .resource = xlr_nor_res, +}; + +const char *xlr_part_probes[] = { "cmdlinepart", NULL }; + +/* + * Use "gen_nand" driver for NAND flash + * + * There seems to be no way to store a private pointer containing + * platform specific info in gen_nand drivier. We will use a global + * struct for now, since we currently have only one NAND chip per board. + */ +struct xlr_nand_flash_priv { + int cs; + uint64_t flash_mmio; +}; + +static struct xlr_nand_flash_priv nand_priv; + +static void xlr_nand_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + if (ctrl & NAND_CLE) + nlm_write_reg(nand_priv.flash_mmio, + FLASH_NAND_CLE(nand_priv.cs), cmd); + else if (ctrl & NAND_ALE) + nlm_write_reg(nand_priv.flash_mmio, + FLASH_NAND_ALE(nand_priv.cs), cmd); +} + +struct platform_nand_data xlr_nand_data = { + .chip = { + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(xlr_nand_parts), + .chip_delay = 50, + .partitions = xlr_nand_parts, + .part_probe_types = xlr_part_probes, + }, + .ctrl = { + .cmd_ctrl = xlr_nand_ctrl, + }, +}; + +static struct resource xlr_nand_res[] = { + { + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device xlr_nand_dev = { + .name = "gen_nand", + .id = -1, + .num_resources = ARRAY_SIZE(xlr_nand_res), + .resource = xlr_nand_res, + .dev = { + .platform_data = &xlr_nand_data, + } +}; + +/* + * XLR/XLS supports upto 8 devices on its FLASH interface. The value in + * FLASH_BAR (on the MEM/IO bridge) gives the base for mapping all the + * flash devices. + * Under this, each flash device has an offset and size given by the + * CSBASE_ADDR and CSBASE_MASK registers for the device. + * + * The CSBASE_ registers are expected to be setup by the bootloader. + */ +static void setup_flash_resource(uint64_t flash_mmio, + uint64_t flash_map_base, int cs, struct resource *res) +{ + u32 base, mask; + + base = nlm_read_reg(flash_mmio, FLASH_CSBASE_ADDR(cs)); + mask = nlm_read_reg(flash_mmio, FLASH_CSADDR_MASK(cs)); + + res->start = flash_map_base + ((unsigned long)base << 16); + res->end = res->start + (mask + 1) * 64 * 1024; +} + +static int __init xlr_flash_init(void) +{ + uint64_t gpio_mmio, flash_mmio, flash_map_base; + u32 gpio_resetcfg, flash_bar; + int cs, boot_nand, boot_nor; + + /* Flash address bits 39:24 is in bridge flash BAR */ + flash_bar = nlm_read_reg(nlm_io_base, BRIDGE_FLASH_BAR); + flash_map_base = (flash_bar & 0xffff0000) << 8; + + gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); + flash_mmio = nlm_mmio_base(NETLOGIC_IO_FLASH_OFFSET); + + /* Get the chip reset config */ + gpio_resetcfg = nlm_read_reg(gpio_mmio, GPIO_PWRON_RESET_CFG_REG); + + /* Check for boot flash type */ + boot_nor = boot_nand = 0; + if (nlm_chip_is_xls()) { + /* On XLS, check boot from NAND bit (GPIO reset reg bit 16) */ + if (gpio_resetcfg & (1 << 16)) + boot_nand = 1; + + /* check boot from PCMCIA, (GPIO reset reg bit 15 */ + if ((gpio_resetcfg & (1 << 15)) == 0) + boot_nor = 1; /* not set, booted from NOR */ + } else { /* XLR */ + /* check boot from PCMCIA (bit 16 in GPIO reset on XLR) */ + if ((gpio_resetcfg & (1 << 16)) == 0) + boot_nor = 1; /* not set, booted from NOR */ + } + + /* boot flash at chip select 0 */ + cs = 0; + + if (boot_nand) { + nand_priv.cs = cs; + nand_priv.flash_mmio = flash_mmio; + setup_flash_resource(flash_mmio, flash_map_base, cs, + xlr_nand_res); + + /* Initialize NAND flash at CS 0 */ + nlm_write_reg(flash_mmio, FLASH_CSDEV_PARM(cs), + FLASH_NAND_CSDEV_PARAM); + nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMA(cs), + FLASH_NAND_CSTIME_PARAMA); + nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMB(cs), + FLASH_NAND_CSTIME_PARAMB); + + pr_info("ChipSelect %d: NAND Flash %pR\n", cs, xlr_nand_res); + return platform_device_register(&xlr_nand_dev); + } + + if (boot_nor) { + setup_flash_resource(flash_mmio, flash_map_base, cs, + xlr_nor_res); + pr_info("ChipSelect %d: NOR Flash %pR\n", cs, xlr_nor_res); + return platform_device_register(&xlr_nor_dev); + } + return 0; +} + +arch_initcall(xlr_flash_init); -- cgit v0.10.2 From 77c8da014afcc0ea7a522faad1824771dbe21577 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 17:28:54 +0200 Subject: MIPS: Netlogic: Platform changes for XLR/XLS I2C Add platform code for XLR/XLS I2C controller and devices. Add devices on the I2C bus on the XLR/XLS developement boards. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3757/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig index d0b857d..138f698 100644 --- a/arch/mips/configs/nlm_xlr_defconfig +++ b/arch/mips/configs/nlm_xlr_defconfig @@ -367,6 +367,10 @@ CONFIG_SERIAL_8250_RSA=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_TIMERIOMEM=m CONFIG_RAW_DRIVER=m +CONFIG_I2C=y +CONFIG_I2C_XLR=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1374=y # CONFIG_HWMON is not set # CONFIG_VGA_CONSOLE is not set # CONFIG_HID_SUPPORT is not set diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index cb0ab63..71b44d8 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -186,3 +187,53 @@ int xls_platform_usb_init(void) arch_initcall(xls_platform_usb_init); #endif + +#ifdef CONFIG_I2C +static struct i2c_board_info nlm_i2c_board_info1[] __initdata = { + /* All XLR boards have this RTC and Max6657 Temp Chip */ + [0] = { + .type = "ds1374", + .addr = 0x68 + }, + [1] = { + .type = "lm90", + .addr = 0x4c + }, +}; + +static struct resource i2c_resources[] = { + [0] = { + .start = 0, /* filled at init */ + .end = 0, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device nlm_xlr_i2c_1 = { + .name = "xlr-i2cbus", + .id = 1, + .num_resources = 1, + .resource = i2c_resources, +}; + +static int __init nlm_i2c_init(void) +{ + int err = 0; + unsigned int offset; + + /* I2C bus 0 does not have any useful devices, configure only bus 1 */ + offset = NETLOGIC_IO_I2C_1_OFFSET; + nlm_xlr_i2c_1.resource[0].start = CPHYSADDR(nlm_mmio_base(offset)); + nlm_xlr_i2c_1.resource[0].end = nlm_xlr_i2c_1.resource[0].start + 0xfff; + + platform_device_register(&nlm_xlr_i2c_1); + + err = i2c_register_board_info(1, nlm_i2c_board_info1, + ARRAY_SIZE(nlm_i2c_board_info1)); + if (err < 0) + pr_err("nlm-i2c: cannot register board I2C devices\n"); + return err; +} + +arch_initcall(nlm_i2c_init); +#endif -- cgit v0.10.2 From 9bac624b0fe0e51a7d5d2519634ed06ceeceb775 Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Tue, 24 Jul 2012 17:28:54 +0200 Subject: MIPS: Netlogic: XLP PCIe controller support. Adds support for the XLP on-chip PCIe controller. On XLP, the on-chip devices(including the 4 PCIe links) appear in the PCIe configuration space of the XLP as PCI devices. The changes are to initialize and register the PCIe controller, enable hardware byte swap in the PCIe IO and MEM space, and to enable PCIe interrupts. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3760/ Patchwork: https://patchwork.linux-mips.org/patch/4104/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 96bad98..de335bb2 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -801,7 +801,6 @@ config NLM_XLP_BOARD select SYS_HAS_CPU_XLP select SYS_SUPPORTS_SMP select HW_HAS_PCI - select SWAP_IO_SPACE select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select 64BIT_PHYS_ADDR diff --git a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h index 86cc339..ece86f1 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h @@ -36,6 +36,9 @@ #define __NLM_HAL_IOMAP_H__ #define XLP_DEFAULT_IO_BASE 0x18000000 +#define XLP_DEFAULT_PCI_ECFG_BASE XLP_DEFAULT_IO_BASE +#define XLP_DEFAULT_PCI_CFG_BASE 0x1c000000 + #define NMI_BASE 0xbfc00000 #define XLP_IO_CLK 133333333 diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h new file mode 100644 index 0000000..66c323d --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NLM_HAL_PCIBUS_H__ +#define __NLM_HAL_PCIBUS_H__ + +/* PCIE Memory and IO regions */ +#define PCIE_MEM_BASE 0xd0000000ULL +#define PCIE_MEM_LIMIT 0xdfffffffULL +#define PCIE_IO_BASE 0x14000000ULL +#define PCIE_IO_LIMIT 0x15ffffffULL + +#define PCIE_BRIDGE_CMD 0x1 +#define PCIE_BRIDGE_MSI_CAP 0x14 +#define PCIE_BRIDGE_MSI_ADDRL 0x15 +#define PCIE_BRIDGE_MSI_ADDRH 0x16 +#define PCIE_BRIDGE_MSI_DATA 0x17 + +/* XLP Global PCIE configuration space registers */ +#define PCIE_BYTE_SWAP_MEM_BASE 0x247 +#define PCIE_BYTE_SWAP_MEM_LIM 0x248 +#define PCIE_BYTE_SWAP_IO_BASE 0x249 +#define PCIE_BYTE_SWAP_IO_LIM 0x24A +#define PCIE_MSI_STATUS 0x25A +#define PCIE_MSI_EN 0x25B +#define PCIE_INT_EN0 0x261 + +/* PCIE_MSI_EN */ +#define PCIE_MSI_VECTOR_INT_EN 0xFFFFFFFF + +/* PCIE_INT_EN0 */ +#define PCIE_MSI_INT_EN (1 << 9) + +#ifndef __ASSEMBLY__ + +#define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_pcie_base(node, inst) \ + nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst)) +#define nlm_get_pcie_regbase(node, inst) \ + (nlm_get_pcie_base(node, inst) + XLP_IO_PCI_HDRSZ) + +int xlp_pcie_link_irt(int link); +#endif +#endif /* __NLM_HAL_PCIBUS_H__ */ diff --git a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h index 1540588..dc6e98e 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h @@ -35,8 +35,12 @@ #ifndef _NLM_HAL_XLP_H #define _NLM_HAL_XLP_H -#define PIC_UART_0_IRQ 17 -#define PIC_UART_1_IRQ 18 +#define PIC_UART_0_IRQ 17 +#define PIC_UART_1_IRQ 18 +#define PIC_PCIE_LINK_0_IRQ 19 +#define PIC_PCIE_LINK_1_IRQ 20 +#define PIC_PCIE_LINK_2_IRQ 21 +#define PIC_PCIE_LINK_3_IRQ 22 #ifndef __ASSEMBLY__ diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index 9428e71..3a4a172 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -69,6 +69,14 @@ int nlm_irq_to_irt(int irq) return PIC_IRT_UART_0_INDEX; case PIC_UART_1_IRQ: return PIC_IRT_UART_1_INDEX; + case PIC_PCIE_LINK_0_IRQ: + return PIC_IRT_PCIE_LINK_0_INDEX; + case PIC_PCIE_LINK_1_IRQ: + return PIC_IRT_PCIE_LINK_1_INDEX; + case PIC_PCIE_LINK_2_IRQ: + return PIC_IRT_PCIE_LINK_2_INDEX; + case PIC_PCIE_LINK_3_IRQ: + return PIC_IRT_PCIE_LINK_3_INDEX; default: return -1; } @@ -81,6 +89,14 @@ int nlm_irt_to_irq(int irt) return PIC_UART_0_IRQ; case PIC_IRT_UART_1_INDEX: return PIC_UART_1_IRQ; + case PIC_IRT_PCIE_LINK_0_INDEX: + return PIC_PCIE_LINK_0_IRQ; + case PIC_IRT_PCIE_LINK_1_INDEX: + return PIC_PCIE_LINK_1_IRQ; + case PIC_IRT_PCIE_LINK_2_INDEX: + return PIC_PCIE_LINK_2_IRQ; + case PIC_IRT_PCIE_LINK_3_INDEX: + return PIC_PCIE_LINK_3_IRQ; default: return -1; } diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index c703f43..e13a71c 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o obj-$(CONFIG_CPU_XLR) += pci-xlr.o +obj-$(CONFIG_CPU_XLP) += pci-xlp.o ifdef CONFIG_PCI_MSI obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c new file mode 100644 index 0000000..140557a --- /dev/null +++ b/arch/mips/pci/pci-xlp.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +static void *pci_config_base; + +#define pci_cfg_addr(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off)) + +/* PCI ops */ +static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, + int where) +{ + u32 data; + u32 *cfgaddr; + + cfgaddr = (u32 *)(pci_config_base + + pci_cfg_addr(bus->number, devfn, where & ~3)); + data = *cfgaddr; + return data; +} + +static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn, + int where, u32 data) +{ + u32 *cfgaddr; + + cfgaddr = (u32 *)(pci_config_base + + pci_cfg_addr(bus->number, devfn, where & ~3)); + *cfgaddr = data; +} + +static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + data = pci_cfg_read_32bit(bus, devfn, where); + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + + +static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + data = pci_cfg_read_32bit(bus, devfn, where); + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else + data = val; + + pci_cfg_write_32bit(bus, devfn, where, data); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops nlm_pci_ops = { + .read = nlm_pcibios_read, + .write = nlm_pcibios_write +}; + +static struct resource nlm_pci_mem_resource = { + .name = "XLP PCI MEM", + .start = 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */ + .end = 0xdfffffffUL, + .flags = IORESOURCE_MEM, +}; + +static struct resource nlm_pci_io_resource = { + .name = "XLP IO MEM", + .start = 0x14000000UL, /* 64MB PCI IO @ 0x1000_0000 */ + .end = 0x17ffffffUL, + .flags = IORESOURCE_IO, +}; + +struct pci_controller nlm_pci_controller = { + .index = 0, + .pci_ops = &nlm_pci_ops, + .mem_resource = &nlm_pci_mem_resource, + .mem_offset = 0x00000000UL, + .io_resource = &nlm_pci_io_resource, + .io_offset = 0x00000000UL, +}; + +static int get_irq_vector(const struct pci_dev *dev) +{ + /* + * For XLP PCIe, there is an IRQ per Link, find out which + * link the device is on to assign interrupts + */ + if (dev->bus->self == NULL) + return 0; + + switch (dev->bus->self->devfn) { + case 0x8: + return PIC_PCIE_LINK_0_IRQ; + case 0x9: + return PIC_PCIE_LINK_1_IRQ; + case 0xa: + return PIC_PCIE_LINK_2_IRQ; + case 0xb: + return PIC_PCIE_LINK_3_IRQ; + } + WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn); + return 0; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return get_irq_vector(dev); +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + +static int xlp_enable_pci_bswap(void) +{ + uint64_t pciebase, sysbase; + int node, i; + u32 reg; + + /* Chip-0 so node set to 0 */ + node = 0; + sysbase = nlm_get_bridge_regbase(node); + /* + * Enable byte swap in hardware. Program each link's PCIe SWAP regions + * from the link's address ranges. + */ + for (i = 0; i < 4; i++) { + pciebase = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, i)); + if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) + continue; + + reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_BASE0 + i); + nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_BASE, reg); + + reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_LIMIT0 + i); + nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_LIM, + reg | 0xfff); + + reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_BASE0 + i); + nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_BASE, reg); + + reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_LIMIT0 + i); + nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); + } + return 0; +} + +static int __init pcibios_init(void) +{ + /* Firmware assigns PCI resources */ + pci_set_flags(PCI_PROBE_ONLY); + pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20); + + /* Extend IO port for memory mapped io */ + ioport_resource.start = 0; + ioport_resource.end = ~0; + + xlp_enable_pci_bswap(); + set_io_port_base(CKSEG1); + nlm_pci_controller.io_map_base = CKSEG1; + + register_pci_controller(&nlm_pci_controller); + pr_info("XLP PCIe Controller %pR%pR.\n", &nlm_pci_io_resource, + &nlm_pci_mem_resource); + + return 0; +} +arch_initcall(pcibios_init); -- cgit v0.10.2 From 1004165f346ac17ea8615bac26398d70c9d6689b Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Tue, 24 Jul 2012 17:28:54 +0200 Subject: MIPS: Netlogic: USB support for XLP The XLP USB controller appears as a device on the internal SoC PCIe bus, the block has 2 EHCI blocks and 4 OHCI blocks. Change are to: * Add files netlogic/xlp/usb-init.c and asm/netlogic/xlp-hal/usb.h to initialize the USB controller and define PCI fixups. The PCI fixups are to setup interrupts and DMA mask. * Update include/asm/xlp-hal/{iomap.h,pic.h,xlp.h} to add interrupt mapping for EHCI/OHCI interrupts. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3756/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h index ece86f1..2c63f97 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h @@ -132,7 +132,7 @@ #define PCI_DEVICE_ID_NLM_PIC 0x1003 #define PCI_DEVICE_ID_NLM_PCIE 0x1004 #define PCI_DEVICE_ID_NLM_EHCI 0x1007 -#define PCI_DEVICE_ID_NLM_ILK 0x1008 +#define PCI_DEVICE_ID_NLM_OHCI 0x1008 #define PCI_DEVICE_ID_NLM_NAE 0x1009 #define PCI_DEVICE_ID_NLM_POE 0x100A #define PCI_DEVICE_ID_NLM_FMN 0x100B diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pic.h b/arch/mips/include/asm/netlogic/xlp-hal/pic.h index b6628f7..ad8b802 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/pic.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/pic.h @@ -201,7 +201,11 @@ #define PIC_NUM_USB_IRTS 6 #define PIC_IRT_USB_0_INDEX 115 #define PIC_IRT_EHCI_0_INDEX 115 +#define PIC_IRT_OHCI_0_INDEX 116 +#define PIC_IRT_OHCI_1_INDEX 117 #define PIC_IRT_EHCI_1_INDEX 118 +#define PIC_IRT_OHCI_2_INDEX 119 +#define PIC_IRT_OHCI_3_INDEX 120 #define PIC_IRT_USB_INDEX(num) ((num) + PIC_IRT_USB_0_INDEX) /* 115 to 120 */ #define PIC_IRT_GDX_INDEX 121 diff --git a/arch/mips/include/asm/netlogic/xlp-hal/usb.h b/arch/mips/include/asm/netlogic/xlp-hal/usb.h new file mode 100644 index 0000000..a9cd350 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlp-hal/usb.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NLM_HAL_USB_H__ +#define __NLM_HAL_USB_H__ + +#define USB_CTL_0 0x01 +#define USB_PHY_0 0x0A +#define USB_PHY_RESET 0x01 +#define USB_PHY_PORT_RESET_0 0x10 +#define USB_PHY_PORT_RESET_1 0x20 +#define USB_CONTROLLER_RESET 0x01 +#define USB_INT_STATUS 0x0E +#define USB_INT_EN 0x0F +#define USB_PHY_INTERRUPT_EN 0x01 +#define USB_OHCI_INTERRUPT_EN 0x02 +#define USB_OHCI_INTERRUPT1_EN 0x04 +#define USB_OHCI_INTERRUPT2_EN 0x08 +#define USB_CTRL_INTERRUPT_EN 0x10 + +#ifndef __ASSEMBLY__ + +#define nlm_read_usb_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_usb_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_usb_pcibase(node, inst) \ + nlm_pcicfg_base(XLP_IO_USB_OFFSET(node, inst)) +#define nlm_get_usb_hcd_base(node, inst) \ + nlm_xkphys_map_pcibar0(nlm_get_usb_pcibase(node, inst)) +#define nlm_get_usb_regbase(node, inst) \ + (nlm_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) + +#endif +#endif /* __NLM_HAL_USB_H__ */ diff --git a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h index dc6e98e..3921a31 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h @@ -41,6 +41,12 @@ #define PIC_PCIE_LINK_1_IRQ 20 #define PIC_PCIE_LINK_2_IRQ 21 #define PIC_PCIE_LINK_3_IRQ 22 +#define PIC_EHCI_0_IRQ 23 +#define PIC_EHCI_1_IRQ 24 +#define PIC_OHCI_0_IRQ 25 +#define PIC_OHCI_1_IRQ 26 +#define PIC_OHCI_2_IRQ 27 +#define PIC_OHCI_3_IRQ 28 #ifndef __ASSEMBLY__ diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile index b93ed83..5bd24b6 100644 --- a/arch/mips/netlogic/xlp/Makefile +++ b/arch/mips/netlogic/xlp/Makefile @@ -1,2 +1,3 @@ obj-y += setup.o platform.o nlm_hal.o obj-$(CONFIG_SMP) += wakeup.o +obj-$(CONFIG_USB) += usb-init.o diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index 3a4a172..fad2cae 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -77,6 +77,18 @@ int nlm_irq_to_irt(int irq) return PIC_IRT_PCIE_LINK_2_INDEX; case PIC_PCIE_LINK_3_IRQ: return PIC_IRT_PCIE_LINK_3_INDEX; + case PIC_EHCI_0_IRQ: + return PIC_IRT_EHCI_0_INDEX; + case PIC_EHCI_1_IRQ: + return PIC_IRT_EHCI_1_INDEX; + case PIC_OHCI_0_IRQ: + return PIC_IRT_OHCI_0_INDEX; + case PIC_OHCI_1_IRQ: + return PIC_IRT_OHCI_1_INDEX; + case PIC_OHCI_2_IRQ: + return PIC_IRT_OHCI_2_INDEX; + case PIC_OHCI_3_IRQ: + return PIC_IRT_OHCI_3_INDEX; default: return -1; } @@ -97,6 +109,18 @@ int nlm_irt_to_irq(int irt) return PIC_PCIE_LINK_2_IRQ; case PIC_IRT_PCIE_LINK_3_INDEX: return PIC_PCIE_LINK_3_IRQ; + case PIC_IRT_EHCI_0_INDEX: + return PIC_EHCI_0_IRQ; + case PIC_IRT_EHCI_1_INDEX: + return PIC_EHCI_1_IRQ; + case PIC_IRT_OHCI_0_INDEX: + return PIC_OHCI_0_IRQ; + case PIC_IRT_OHCI_1_INDEX: + return PIC_OHCI_1_IRQ; + case PIC_IRT_OHCI_2_INDEX: + return PIC_OHCI_2_IRQ; + case PIC_IRT_OHCI_3_INDEX: + return PIC_OHCI_3_IRQ; default: return -1; } diff --git a/arch/mips/netlogic/xlp/platform.c b/arch/mips/netlogic/xlp/platform.c index 1f5e4cb..2c510d5 100644 --- a/arch/mips/netlogic/xlp/platform.c +++ b/arch/mips/netlogic/xlp/platform.c @@ -53,7 +53,7 @@ static unsigned int nlm_xlp_uart_in(struct uart_port *p, int offset) { - return nlm_read_reg(p->iobase, offset); + return nlm_read_reg(p->iobase, offset); } static void nlm_xlp_uart_out(struct uart_port *p, int offset, int value) diff --git a/arch/mips/netlogic/xlp/usb-init.c b/arch/mips/netlogic/xlp/usb-init.c new file mode 100644 index 0000000..dbe083a --- /dev/null +++ b/arch/mips/netlogic/xlp/usb-init.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static void nlm_usb_intr_en(int node, int port) +{ + uint32_t val; + uint64_t port_addr; + + port_addr = nlm_get_usb_regbase(node, port); + val = nlm_read_usb_reg(port_addr, USB_INT_EN); + val = USB_CTRL_INTERRUPT_EN | USB_OHCI_INTERRUPT_EN | + USB_OHCI_INTERRUPT1_EN | USB_CTRL_INTERRUPT_EN | + USB_OHCI_INTERRUPT_EN | USB_OHCI_INTERRUPT2_EN; + nlm_write_usb_reg(port_addr, USB_INT_EN, val); +} + +static void nlm_usb_hw_reset(int node, int port) +{ + uint64_t port_addr; + uint32_t val; + + /* reset USB phy */ + port_addr = nlm_get_usb_regbase(node, port); + val = nlm_read_usb_reg(port_addr, USB_PHY_0); + val &= ~(USB_PHY_RESET | USB_PHY_PORT_RESET_0 | USB_PHY_PORT_RESET_1); + nlm_write_usb_reg(port_addr, USB_PHY_0, val); + + mdelay(100); + val = nlm_read_usb_reg(port_addr, USB_CTL_0); + val &= ~(USB_CONTROLLER_RESET); + val |= 0x4; + nlm_write_usb_reg(port_addr, USB_CTL_0, val); +} + +static int __init nlm_platform_usb_init(void) +{ + pr_info("Initializing USB Interface\n"); + nlm_usb_hw_reset(0, 0); + nlm_usb_hw_reset(0, 3); + + /* Enable PHY interrupts */ + nlm_usb_intr_en(0, 0); + nlm_usb_intr_en(0, 3); + + return 0; +} + +arch_initcall(nlm_platform_usb_init); + +static u64 xlp_usb_dmamask = ~(u32)0; + +/* Fixup the IRQ for USB devices which is exist on XLP SOC PCIE bus */ +static void nlm_usb_fixup_final(struct pci_dev *dev) +{ + dev->dev.dma_mask = &xlp_usb_dmamask; + dev->dev.coherent_dma_mask = DMA_BIT_MASK(64); + switch (dev->devfn) { + case 0x10: + dev->irq = PIC_EHCI_0_IRQ; + break; + case 0x11: + dev->irq = PIC_OHCI_0_IRQ; + break; + case 0x12: + dev->irq = PIC_OHCI_1_IRQ; + break; + case 0x13: + dev->irq = PIC_EHCI_1_IRQ; + break; + case 0x14: + dev->irq = PIC_OHCI_2_IRQ; + break; + case 0x15: + dev->irq = PIC_OHCI_3_IRQ; + break; + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_EHCI, + nlm_usb_fixup_final); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_OHCI, + nlm_usb_fixup_final); -- cgit v0.10.2 From 57d7cdb630716c3f9cf7beadd05059c65a9acd25 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 17:28:54 +0200 Subject: MIPS: Netlogic: Add IRQ mappings for more devices Add IRT to IRQ translation for the MMC and I2C IRQs. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3761/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h index 3921a31..7e47209 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/xlp.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h @@ -47,6 +47,9 @@ #define PIC_OHCI_1_IRQ 26 #define PIC_OHCI_2_IRQ 27 #define PIC_OHCI_3_IRQ 28 +#define PIC_MMC_IRQ 29 +#define PIC_I2C_0_IRQ 30 +#define PIC_I2C_1_IRQ 31 #ifndef __ASSEMBLY__ diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index fad2cae..6c65ac7 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -89,6 +89,12 @@ int nlm_irq_to_irt(int irq) return PIC_IRT_OHCI_2_INDEX; case PIC_OHCI_3_IRQ: return PIC_IRT_OHCI_3_INDEX; + case PIC_MMC_IRQ: + return PIC_IRT_MMC_INDEX; + case PIC_I2C_0_IRQ: + return PIC_IRT_I2C_0_INDEX; + case PIC_I2C_1_IRQ: + return PIC_IRT_I2C_1_INDEX; default: return -1; } @@ -121,6 +127,12 @@ int nlm_irt_to_irq(int irt) return PIC_OHCI_2_IRQ; case PIC_IRT_OHCI_3_INDEX: return PIC_OHCI_3_IRQ; + case PIC_IRT_MMC_INDEX: + return PIC_MMC_IRQ; + case PIC_IRT_I2C_0_INDEX: + return PIC_I2C_0_IRQ; + case PIC_IRT_I2C_1_INDEX: + return PIC_I2C_1_IRQ; default: return -1; } -- cgit v0.10.2 From fcf9b4de3374d0df79eb8e06c046006d3855e06e Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Tue, 24 Jul 2012 17:28:55 +0200 Subject: MIPS: Netlogic: Add XLP SoC devices in FDT Probe and add devices on SoC "simple-bus" on startup. This will in turn add devices like I2C controller that are specified in the device tree under 'soc'. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3762/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c index b3df7c2..3dec9f2 100644 --- a/arch/mips/netlogic/xlp/setup.c +++ b/arch/mips/netlogic/xlp/setup.c @@ -41,6 +41,8 @@ #include #include +#include +#include #include #include @@ -109,3 +111,17 @@ void __init prom_init(void) register_smp_ops(&nlm_smp_ops); #endif } + +static struct of_device_id __initdata xlp_ids[] = { + { .compatible = "simple-bus", }, + {}, +}; + +int __init xlp8xx_ds_publish_devices(void) +{ + if (!of_have_populated_dt()) + return 0; + return of_platform_bus_probe(NULL, xlp_ids, NULL); +} + +device_initcall(xlp8xx_ds_publish_devices); -- cgit v0.10.2 From 4d9bb75823eb1e22f8d6d13112d5eb6850fea475 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 17:28:55 +0200 Subject: MIPS: Netlogic: Remove unused pcibios_fixups This global is unneeded, and seems to be carried over from ancient code. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3752/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c index 172af1c..18af021 100644 --- a/arch/mips/pci/pci-xlr.c +++ b/arch/mips/pci/pci-xlr.c @@ -375,7 +375,3 @@ static int __init pcibios_init(void) } arch_initcall(pcibios_init); - -struct pci_fixup pcibios_fixups[] = { - {0} -}; -- cgit v0.10.2 From 1005f281fac16a64201ba5f39b463027772195ee Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 17:28:55 +0200 Subject: MIPS: Netlogic: remove cpu_has_dc_aliases define for XLP On XLP, the dcache size depends on the number of enabled threads in core. There are no dcache aliases if the pagesize is large enough or if enough threads are enabled in the core. Remove the #define for cpu_has_dc_aliases and leave it to be computed at runtime. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/4099/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h index d193fb6..966db4b 100644 --- a/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h @@ -48,7 +48,6 @@ #define cpu_has_userlocal 1 #define cpu_has_mips32r2 1 #define cpu_has_mips64r2 1 -#define cpu_has_dc_aliases 1 #else #error "Unknown Netlogic CPU" #endif -- cgit v0.10.2 From 93a029325979c4baa4cb03286e628b802614b5cb Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 24 Jul 2012 18:17:47 +0200 Subject: MIPS: Netlogic: Fix indentation of smpboot.S [ralf@linux-mips.org: I've folded most segments of this patch into those patches in -next that originally were causing the whitespace damage. This is just what's left over] Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/4094/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index d6431b7..a13355c 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -67,7 +67,7 @@ li t2, ~0xe /* S1RCM */ and t1, t1, t2 #endif - mtcr t1, t0 + mtcr t1, t0 #ifdef XLP_AX_WORKAROUND li t0, SCHED_DEFEATURE @@ -195,9 +195,9 @@ EXPORT(nlm_boot_siblings) bnez v1, 2f nop - li t0, MMU_SETUP - li t1, 0 - mtcr t1, t0 + li t0, MMU_SETUP + li t1, 0 + mtcr t1, t0 _ehb 2: beqz v0, 4f /* boot cpu (cpuid == 0)? */ -- cgit v0.10.2 From 7e6507ad76a212b961d2392d22a9610be9e4e053 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 16 Jul 2012 15:33:37 +0530 Subject: MIPS: Netlogic: early console fix In prom_putchar(), wait for just the TX empty bit to clear in the UART LSR. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Cc: Florian Fainelli Patchwork: https://patchwork.linux-mips.org/patch/4112/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/netlogic/common/earlycons.c b/arch/mips/netlogic/common/earlycons.c index f193f7b..1902fa2 100644 --- a/arch/mips/netlogic/common/earlycons.c +++ b/arch/mips/netlogic/common/earlycons.c @@ -54,7 +54,7 @@ void prom_putchar(char c) #elif defined(CONFIG_CPU_XLR) uartbase = nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); #endif - while (nlm_read_reg(uartbase, UART_LSR) == 0) + while ((nlm_read_reg(uartbase, UART_LSR) & UART_LSR_THRE) == 0) ; nlm_write_reg(uartbase, UART_TX, c); } -- cgit v0.10.2 From ca585cf9fb818bfcfcac6968c2b242dcd0693b08 Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Wed, 25 Jul 2012 16:17:24 +0200 Subject: MIPS: Loongson 1B: Add board support Adds basic platform devices for Loongson 1B, including serial port, ethernet, USB, RTC and interrupt handler. The Loongson 1B UART is compatible with NS16550A, the Loongson 1B GMAC is built around a Synopsys IP Core. Use normal instead of enhanced descriptors. Thanks to Giuseppe for updating the normal descriptor in stmmac driver. Thanks to Zhao Zhang for implementing the RTC driver. Signed-off-by: Kelvin Cheung Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: wuzhangjin@gmail.com Cc: zhzhl555@gmail.com Cc: Kelvin Cheung Patchwork: https://patchwork.linux-mips.org/patch/4133/ Patchwork: https://patchwork.linux-mips.org/patch/4134/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 5ce8029..d64786d 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -14,6 +14,7 @@ platforms += jz4740 platforms += lantiq platforms += lasat platforms += loongson +platforms += loongson1 platforms += mipssim platforms += mti-malta platforms += netlogic diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b3e10fd..73457d1 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -264,6 +264,16 @@ config MACH_LOONGSON Chinese Academy of Sciences (CAS) in the People's Republic of China. The chief architect is Professor Weiwu Hu. +config MACH_LOONGSON1 + bool "Loongson 1 family of machines" + select SYS_SUPPORTS_ZBOOT + help + This enables support for the Loongson 1 based machines. + + Loongson 1 is a family of 32-bit MIPS-compatible SoCs developed by + the ICT (Institute of Computing Technology) and the Chinese Academy + of Sciences. + config MIPS_MALTA bool "MIPS Malta board" select ARCH_MAY_HAVE_PC_FDC @@ -836,6 +846,7 @@ source "arch/mips/txx9/Kconfig" source "arch/mips/vr41xx/Kconfig" source "arch/mips/cavium-octeon/Kconfig" source "arch/mips/loongson/Kconfig" +source "arch/mips/loongson1/Kconfig" source "arch/mips/netlogic/Kconfig" endmenu @@ -1217,6 +1228,14 @@ config CPU_LOONGSON2F have a similar programming interface with FPGA northbridge used in Loongson2E. +config CPU_LOONGSON1B + bool "Loongson 1B" + depends on SYS_HAS_CPU_LOONGSON1B + select CPU_LOONGSON1 + help + The Loongson 1B is a 32-bit SoC, which implements the MIPS32 + release 2 instruction set. + config CPU_MIPS32_R1 bool "MIPS32 Release 1" depends on SYS_HAS_CPU_MIPS32_R1 @@ -1544,6 +1563,14 @@ config CPU_LOONGSON2 select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM +config CPU_LOONGSON1 + bool + select CPU_MIPS32 + select CPU_MIPSR2 + select CPU_HAS_PREFETCH + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + config CPU_BMIPS bool select CPU_MIPS32 @@ -1562,6 +1589,9 @@ config SYS_HAS_CPU_LOONGSON2F select CPU_SUPPORTS_ADDRWINCFG if 64BIT select CPU_SUPPORTS_UNCACHED_ACCELERATED +config SYS_HAS_CPU_LOONGSON1B + bool + config SYS_HAS_CPU_MIPS32_R1 bool diff --git a/arch/mips/include/asm/mach-loongson1/irq.h b/arch/mips/include/asm/mach-loongson1/irq.h new file mode 100644 index 0000000..da96ed4 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/irq.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * IRQ mappings for Loongson 1 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + + +#ifndef __ASM_MACH_LOONGSON1_IRQ_H +#define __ASM_MACH_LOONGSON1_IRQ_H + +/* + * CPU core Interrupt Numbers + */ +#define MIPS_CPU_IRQ_BASE 0 +#define MIPS_CPU_IRQ(x) (MIPS_CPU_IRQ_BASE + (x)) + +#define SOFTINT0_IRQ MIPS_CPU_IRQ(0) +#define SOFTINT1_IRQ MIPS_CPU_IRQ(1) +#define INT0_IRQ MIPS_CPU_IRQ(2) +#define INT1_IRQ MIPS_CPU_IRQ(3) +#define INT2_IRQ MIPS_CPU_IRQ(4) +#define INT3_IRQ MIPS_CPU_IRQ(5) +#define INT4_IRQ MIPS_CPU_IRQ(6) +#define TIMER_IRQ MIPS_CPU_IRQ(7) /* cpu timer */ + +#define MIPS_CPU_IRQS (MIPS_CPU_IRQ(7) + 1 - MIPS_CPU_IRQ_BASE) + +/* + * INT0~3 Interrupt Numbers + */ +#define LS1X_IRQ_BASE MIPS_CPU_IRQS +#define LS1X_IRQ(n, x) (LS1X_IRQ_BASE + (n << 5) + (x)) + +#define LS1X_UART0_IRQ LS1X_IRQ(0, 2) +#define LS1X_UART1_IRQ LS1X_IRQ(0, 3) +#define LS1X_UART2_IRQ LS1X_IRQ(0, 4) +#define LS1X_UART3_IRQ LS1X_IRQ(0, 5) +#define LS1X_CAN0_IRQ LS1X_IRQ(0, 6) +#define LS1X_CAN1_IRQ LS1X_IRQ(0, 7) +#define LS1X_SPI0_IRQ LS1X_IRQ(0, 8) +#define LS1X_SPI1_IRQ LS1X_IRQ(0, 9) +#define LS1X_AC97_IRQ LS1X_IRQ(0, 10) +#define LS1X_DMA0_IRQ LS1X_IRQ(0, 13) +#define LS1X_DMA1_IRQ LS1X_IRQ(0, 14) +#define LS1X_DMA2_IRQ LS1X_IRQ(0, 15) +#define LS1X_PWM0_IRQ LS1X_IRQ(0, 17) +#define LS1X_PWM1_IRQ LS1X_IRQ(0, 18) +#define LS1X_PWM2_IRQ LS1X_IRQ(0, 19) +#define LS1X_PWM3_IRQ LS1X_IRQ(0, 20) +#define LS1X_RTC_INT0_IRQ LS1X_IRQ(0, 21) +#define LS1X_RTC_INT1_IRQ LS1X_IRQ(0, 22) +#define LS1X_RTC_INT2_IRQ LS1X_IRQ(0, 23) +#define LS1X_TOY_INT0_IRQ LS1X_IRQ(0, 24) +#define LS1X_TOY_INT1_IRQ LS1X_IRQ(0, 25) +#define LS1X_TOY_INT2_IRQ LS1X_IRQ(0, 26) +#define LS1X_RTC_TICK_IRQ LS1X_IRQ(0, 27) +#define LS1X_TOY_TICK_IRQ LS1X_IRQ(0, 28) + +#define LS1X_EHCI_IRQ LS1X_IRQ(1, 0) +#define LS1X_OHCI_IRQ LS1X_IRQ(1, 1) +#define LS1X_GMAC0_IRQ LS1X_IRQ(1, 2) +#define LS1X_GMAC1_IRQ LS1X_IRQ(1, 3) + +#define LS1X_IRQS (LS1X_IRQ(4, 31) + 1 - LS1X_IRQ_BASE) + +#define NR_IRQS (MIPS_CPU_IRQS + LS1X_IRQS) + +#endif /* __ASM_MACH_LOONGSON1_IRQ_H */ diff --git a/arch/mips/include/asm/mach-loongson1/loongson1.h b/arch/mips/include/asm/mach-loongson1/loongson1.h new file mode 100644 index 0000000..4e18e88 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/loongson1.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * Register mappings for Loongson 1 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + + +#ifndef __ASM_MACH_LOONGSON1_LOONGSON1_H +#define __ASM_MACH_LOONGSON1_LOONGSON1_H + +#define DEFAULT_MEMSIZE 256 /* If no memsize provided */ + +/* Loongson 1 Register Bases */ +#define LS1X_INTC_BASE 0x1fd01040 +#define LS1X_EHCI_BASE 0x1fe00000 +#define LS1X_OHCI_BASE 0x1fe08000 +#define LS1X_GMAC0_BASE 0x1fe10000 +#define LS1X_GMAC1_BASE 0x1fe20000 + +#define LS1X_UART0_BASE 0x1fe40000 +#define LS1X_UART1_BASE 0x1fe44000 +#define LS1X_UART2_BASE 0x1fe48000 +#define LS1X_UART3_BASE 0x1fe4c000 +#define LS1X_CAN0_BASE 0x1fe50000 +#define LS1X_CAN1_BASE 0x1fe54000 +#define LS1X_I2C0_BASE 0x1fe58000 +#define LS1X_I2C1_BASE 0x1fe68000 +#define LS1X_I2C2_BASE 0x1fe70000 +#define LS1X_PWM_BASE 0x1fe5c000 +#define LS1X_WDT_BASE 0x1fe5c060 +#define LS1X_RTC_BASE 0x1fe64000 +#define LS1X_AC97_BASE 0x1fe74000 +#define LS1X_NAND_BASE 0x1fe78000 +#define LS1X_CLK_BASE 0x1fe78030 + +#include +#include + +#endif /* __ASM_MACH_LOONGSON1_LOONGSON1_H */ diff --git a/arch/mips/include/asm/mach-loongson1/platform.h b/arch/mips/include/asm/mach-loongson1/platform.h new file mode 100644 index 0000000..2f17161 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/platform.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + + +#ifndef __ASM_MACH_LOONGSON1_PLATFORM_H +#define __ASM_MACH_LOONGSON1_PLATFORM_H + +#include + +extern struct platform_device ls1x_uart_device; +extern struct platform_device ls1x_eth0_device; +extern struct platform_device ls1x_ehci_device; +extern struct platform_device ls1x_rtc_device; + +void ls1x_serial_setup(void); + +#endif /* __ASM_MACH_LOONGSON1_PLATFORM_H */ diff --git a/arch/mips/include/asm/mach-loongson1/prom.h b/arch/mips/include/asm/mach-loongson1/prom.h new file mode 100644 index 0000000..b871dc4 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/prom.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ASM_MACH_LOONGSON1_PROM_H +#define __ASM_MACH_LOONGSON1_PROM_H + +#include +#include +#include + +/* environment arguments from bootloader */ +extern unsigned long memsize, highmemsize; + +/* loongson-specific command line, env and memory initialization */ +extern char *prom_getenv(char *name); +extern void __init prom_init_cmdline(void); + +#endif /* __ASM_MACH_LOONGSON1_PROM_H */ diff --git a/arch/mips/include/asm/mach-loongson1/regs-clk.h b/arch/mips/include/asm/mach-loongson1/regs-clk.h new file mode 100644 index 0000000..8efa7fb --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/regs-clk.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * Loongson 1 Clock Register Definitions. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ASM_MACH_LOONGSON1_REGS_CLK_H +#define __ASM_MACH_LOONGSON1_REGS_CLK_H + +#define LS1X_CLK_REG(x) \ + ((void __iomem *)KSEG1ADDR(LS1X_CLK_BASE + (x))) + +#define LS1X_CLK_PLL_FREQ LS1X_CLK_REG(0x0) +#define LS1X_CLK_PLL_DIV LS1X_CLK_REG(0x4) + +/* Clock PLL Divisor Register Bits */ +#define DIV_DC_EN (0x1 << 31) +#define DIV_DC (0x1f << 26) +#define DIV_CPU_EN (0x1 << 25) +#define DIV_CPU (0x1f << 20) +#define DIV_DDR_EN (0x1 << 19) +#define DIV_DDR (0x1f << 14) + +#define DIV_DC_SHIFT 26 +#define DIV_CPU_SHIFT 20 +#define DIV_DDR_SHIFT 14 + +#endif /* __ASM_MACH_LOONGSON1_REGS_CLK_H */ diff --git a/arch/mips/include/asm/mach-loongson1/regs-wdt.h b/arch/mips/include/asm/mach-loongson1/regs-wdt.h new file mode 100644 index 0000000..f897de6 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/regs-wdt.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * Loongson 1 watchdog register definitions. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ASM_MACH_LOONGSON1_REGS_WDT_H +#define __ASM_MACH_LOONGSON1_REGS_WDT_H + +#define LS1X_WDT_REG(x) \ + ((void __iomem *)KSEG1ADDR(LS1X_WDT_BASE + (x))) + +#define LS1X_WDT_EN LS1X_WDT_REG(0x0) +#define LS1X_WDT_SET LS1X_WDT_REG(0x4) +#define LS1X_WDT_TIMER LS1X_WDT_REG(0x8) + +#endif /* __ASM_MACH_LOONGSON1_REGS_WDT_H */ diff --git a/arch/mips/include/asm/mach-loongson1/war.h b/arch/mips/include/asm/mach-loongson1/war.h new file mode 100644 index 0000000..e3680a8 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/war.h @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MACH_LOONGSON1_WAR_H +#define __ASM_MACH_LOONGSON1_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MACH_LOONGSON1_WAR_H */ diff --git a/arch/mips/loongson1/Kconfig b/arch/mips/loongson1/Kconfig new file mode 100644 index 0000000..237fa21 --- /dev/null +++ b/arch/mips/loongson1/Kconfig @@ -0,0 +1,21 @@ +if MACH_LOONGSON1 + +choice + prompt "Machine Type" + +config LOONGSON1_LS1B + bool "Loongson LS1B board" + select CEVT_R4K + select CSRC_R4K + select SYS_HAS_CPU_LOONGSON1B + select DMA_NONCOHERENT + select BOOT_ELF32 + select IRQ_CPU + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_HIGHMEM + select SYS_HAS_EARLY_PRINTK + +endchoice + +endif # MACH_LOONGSON1 diff --git a/arch/mips/loongson1/Makefile b/arch/mips/loongson1/Makefile new file mode 100644 index 0000000..9719c75 --- /dev/null +++ b/arch/mips/loongson1/Makefile @@ -0,0 +1,11 @@ +# +# Common code for all Loongson 1 based systems +# + +obj-$(CONFIG_MACH_LOONGSON1) += common/ + +# +# Loongson LS1B board +# + +obj-$(CONFIG_LOONGSON1_LS1B) += ls1b/ diff --git a/arch/mips/loongson1/Platform b/arch/mips/loongson1/Platform new file mode 100644 index 0000000..99bdefe --- /dev/null +++ b/arch/mips/loongson1/Platform @@ -0,0 +1,7 @@ +cflags-$(CONFIG_CPU_LOONGSON1) += \ + $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ + -Wa,-mips32r2 -Wa,--trap + +platform-$(CONFIG_MACH_LOONGSON1) += loongson1/ +cflags-$(CONFIG_MACH_LOONGSON1) += -I$(srctree)/arch/mips/include/asm/mach-loongson1 +load-$(CONFIG_LOONGSON1_LS1B) += 0xffffffff80100000 diff --git a/arch/mips/loongson1/common/Makefile b/arch/mips/loongson1/common/Makefile new file mode 100644 index 0000000..b279770 --- /dev/null +++ b/arch/mips/loongson1/common/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for common code of loongson1 based machines. +# + +obj-y += clock.o irq.o platform.o prom.o reset.o setup.o diff --git a/arch/mips/loongson1/common/clock.c b/arch/mips/loongson1/common/clock.c new file mode 100644 index 0000000..2d98fb0 --- /dev/null +++ b/arch/mips/loongson1/common/clock.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static LIST_HEAD(clocks); +static DEFINE_MUTEX(clocks_mutex); + +struct clk *clk_get(struct device *dev, const char *name) +{ + struct clk *c; + struct clk *ret = NULL; + + mutex_lock(&clocks_mutex); + list_for_each_entry(c, &clocks, node) { + if (!strcmp(c->name, name)) { + ret = c; + break; + } + } + mutex_unlock(&clocks_mutex); + + return ret; +} +EXPORT_SYMBOL(clk_get); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + +static void pll_clk_init(struct clk *clk) +{ + u32 pll; + + pll = __raw_readl(LS1X_CLK_PLL_FREQ); + clk->rate = (12 + (pll & 0x3f)) * 33 / 2 + + ((pll >> 8) & 0x3ff) * 33 / 1024 / 2; + clk->rate *= 1000000; +} + +static void cpu_clk_init(struct clk *clk) +{ + u32 pll, ctrl; + + pll = clk_get_rate(clk->parent); + ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_CPU; + clk->rate = pll / (ctrl >> DIV_CPU_SHIFT); +} + +static void ddr_clk_init(struct clk *clk) +{ + u32 pll, ctrl; + + pll = clk_get_rate(clk->parent); + ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_DDR; + clk->rate = pll / (ctrl >> DIV_DDR_SHIFT); +} + +static void dc_clk_init(struct clk *clk) +{ + u32 pll, ctrl; + + pll = clk_get_rate(clk->parent); + ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_DC; + clk->rate = pll / (ctrl >> DIV_DC_SHIFT); +} + +static struct clk_ops pll_clk_ops = { + .init = pll_clk_init, +}; + +static struct clk_ops cpu_clk_ops = { + .init = cpu_clk_init, +}; + +static struct clk_ops ddr_clk_ops = { + .init = ddr_clk_init, +}; + +static struct clk_ops dc_clk_ops = { + .init = dc_clk_init, +}; + +static struct clk pll_clk = { + .name = "pll", + .ops = &pll_clk_ops, +}; + +static struct clk cpu_clk = { + .name = "cpu", + .parent = &pll_clk, + .ops = &cpu_clk_ops, +}; + +static struct clk ddr_clk = { + .name = "ddr", + .parent = &pll_clk, + .ops = &ddr_clk_ops, +}; + +static struct clk dc_clk = { + .name = "dc", + .parent = &pll_clk, + .ops = &dc_clk_ops, +}; + +int clk_register(struct clk *clk) +{ + mutex_lock(&clocks_mutex); + list_add(&clk->node, &clocks); + if (clk->ops->init) + clk->ops->init(clk); + mutex_unlock(&clocks_mutex); + + return 0; +} +EXPORT_SYMBOL(clk_register); + +static struct clk *ls1x_clks[] = { + &pll_clk, + &cpu_clk, + &ddr_clk, + &dc_clk, +}; + +int __init ls1x_clock_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ls1x_clks); i++) + clk_register(ls1x_clks[i]); + + return 0; +} + +void __init plat_time_init(void) +{ + struct clk *clk; + + /* Initialize LS1X clocks */ + ls1x_clock_init(); + + /* setup mips r4k timer */ + clk = clk_get(NULL, "cpu"); + if (IS_ERR(clk)) + panic("unable to get dc clock, err=%ld", PTR_ERR(clk)); + + mips_hpt_frequency = clk_get_rate(clk) / 2; +} diff --git a/arch/mips/loongson1/common/irq.c b/arch/mips/loongson1/common/irq.c new file mode 100644 index 0000000..41bc8ff --- /dev/null +++ b/arch/mips/loongson1/common/irq.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include +#include + +#define LS1X_INTC_REG(n, x) \ + ((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x))) + +#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) +#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) +#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) +#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) +#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) +#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) + +static void ls1x_irq_ack(struct irq_data *d) +{ + unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; + unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + + __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) + | (1 << bit), LS1X_INTC_INTCLR(n)); +} + +static void ls1x_irq_mask(struct irq_data *d) +{ + unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; + unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + + __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) + & ~(1 << bit), LS1X_INTC_INTIEN(n)); +} + +static void ls1x_irq_mask_ack(struct irq_data *d) +{ + unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; + unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + + __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) + & ~(1 << bit), LS1X_INTC_INTIEN(n)); + __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) + | (1 << bit), LS1X_INTC_INTCLR(n)); +} + +static void ls1x_irq_unmask(struct irq_data *d) +{ + unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; + unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + + __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) + | (1 << bit), LS1X_INTC_INTIEN(n)); +} + +static struct irq_chip ls1x_irq_chip = { + .name = "LS1X-INTC", + .irq_ack = ls1x_irq_ack, + .irq_mask = ls1x_irq_mask, + .irq_mask_ack = ls1x_irq_mask_ack, + .irq_unmask = ls1x_irq_unmask, +}; + +static void ls1x_irq_dispatch(int n) +{ + u32 int_status, irq; + + /* Get pending sources, masked by current enables */ + int_status = __raw_readl(LS1X_INTC_INTISR(n)) & + __raw_readl(LS1X_INTC_INTIEN(n)); + + if (int_status) { + irq = LS1X_IRQ(n, __ffs(int_status)); + do_IRQ(irq); + } +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending; + + pending = read_c0_cause() & read_c0_status() & ST0_IM; + + if (pending & CAUSEF_IP7) + do_IRQ(TIMER_IRQ); + else if (pending & CAUSEF_IP2) + ls1x_irq_dispatch(0); /* INT0 */ + else if (pending & CAUSEF_IP3) + ls1x_irq_dispatch(1); /* INT1 */ + else if (pending & CAUSEF_IP4) + ls1x_irq_dispatch(2); /* INT2 */ + else if (pending & CAUSEF_IP5) + ls1x_irq_dispatch(3); /* INT3 */ + else if (pending & CAUSEF_IP6) + ls1x_irq_dispatch(4); /* INT4 */ + else + spurious_interrupt(); + +} + +struct irqaction cascade_irqaction = { + .handler = no_action, + .name = "cascade", + .flags = IRQF_NO_THREAD, +}; + +static void __init ls1x_irq_init(int base) +{ + int n; + + /* Disable interrupts and clear pending, + * setup all IRQs as high level triggered + */ + for (n = 0; n < 4; n++) { + __raw_writel(0x0, LS1X_INTC_INTIEN(n)); + __raw_writel(0xffffffff, LS1X_INTC_INTCLR(n)); + __raw_writel(0xffffffff, LS1X_INTC_INTPOL(n)); + /* set DMA0, DMA1 and DMA2 to edge trigger */ + __raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n)); + } + + + for (n = base; n < LS1X_IRQS; n++) { + irq_set_chip_and_handler(n, &ls1x_irq_chip, + handle_level_irq); + } + + setup_irq(INT0_IRQ, &cascade_irqaction); + setup_irq(INT1_IRQ, &cascade_irqaction); + setup_irq(INT2_IRQ, &cascade_irqaction); + setup_irq(INT3_IRQ, &cascade_irqaction); +} + +void __init arch_init_irq(void) +{ + mips_cpu_irq_init(); + ls1x_irq_init(LS1X_IRQ_BASE); +} diff --git a/arch/mips/loongson1/common/platform.c b/arch/mips/loongson1/common/platform.c new file mode 100644 index 0000000..e92d59c --- /dev/null +++ b/arch/mips/loongson1/common/platform.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LS1X_UART(_id) \ + { \ + .mapbase = LS1X_UART ## _id ## _BASE, \ + .irq = LS1X_UART ## _id ## _IRQ, \ + .iotype = UPIO_MEM, \ + .flags = UPF_IOREMAP | UPF_FIXED_TYPE, \ + .type = PORT_16550A, \ + } + +static struct plat_serial8250_port ls1x_serial8250_port[] = { + LS1X_UART(0), + LS1X_UART(1), + LS1X_UART(2), + LS1X_UART(3), + {}, +}; + +struct platform_device ls1x_uart_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = ls1x_serial8250_port, + }, +}; + +void __init ls1x_serial_setup(void) +{ + struct clk *clk; + struct plat_serial8250_port *p; + + clk = clk_get(NULL, "dc"); + if (IS_ERR(clk)) + panic("unable to get dc clock, err=%ld", PTR_ERR(clk)); + + for (p = ls1x_serial8250_port; p->flags != 0; ++p) + p->uartclk = clk_get_rate(clk); +} + +/* Synopsys Ethernet GMAC */ +static struct resource ls1x_eth0_resources[] = { + [0] = { + .start = LS1X_GMAC0_BASE, + .end = LS1X_GMAC0_BASE + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "macirq", + .start = LS1X_GMAC0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { + .bus_id = 0, + .phy_mask = 0, +}; + +static struct plat_stmmacenet_data ls1x_eth_data = { + .bus_id = 0, + .phy_addr = -1, + .mdio_bus_data = &ls1x_mdio_bus_data, + .has_gmac = 1, + .tx_coe = 1, +}; + +struct platform_device ls1x_eth0_device = { + .name = "stmmaceth", + .id = 0, + .num_resources = ARRAY_SIZE(ls1x_eth0_resources), + .resource = ls1x_eth0_resources, + .dev = { + .platform_data = &ls1x_eth_data, + }, +}; + +/* USB EHCI */ +static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32); + +static struct resource ls1x_ehci_resources[] = { + [0] = { + .start = LS1X_EHCI_BASE, + .end = LS1X_EHCI_BASE + SZ_32K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = LS1X_EHCI_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device ls1x_ehci_device = { + .name = "ls1x-ehci", + .id = -1, + .num_resources = ARRAY_SIZE(ls1x_ehci_resources), + .resource = ls1x_ehci_resources, + .dev = { + .dma_mask = &ls1x_ehci_dmamask, + }, +}; + +/* Real Time Clock */ +struct platform_device ls1x_rtc_device = { + .name = "ls1x-rtc", + .id = -1, +}; diff --git a/arch/mips/loongson1/common/prom.c b/arch/mips/loongson1/common/prom.c new file mode 100644 index 0000000..1f8e49f --- /dev/null +++ b/arch/mips/loongson1/common/prom.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * Modified from arch/mips/pnx833x/common/prom.c. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include + +#include +#include + +int prom_argc; +char **prom_argv, **prom_envp; +unsigned long memsize, highmemsize; + +char *prom_getenv(char *envname) +{ + char **env = prom_envp; + int i; + + i = strlen(envname); + + while (*env) { + if (strncmp(envname, *env, i) == 0 && *(*env+i) == '=') + return *env + i + 1; + env++; + } + + return 0; +} + +static inline unsigned long env_or_default(char *env, unsigned long dfl) +{ + char *str = prom_getenv(env); + return str ? simple_strtol(str, 0, 0) : dfl; +} + +void __init prom_init_cmdline(void) +{ + char *c = &(arcs_cmdline[0]); + int i; + + for (i = 1; i < prom_argc; i++) { + strcpy(c, prom_argv[i]); + c += strlen(prom_argv[i]); + if (i < prom_argc-1) + *c++ = ' '; + } + *c = 0; +} + +void __init prom_init(void) +{ + prom_argc = fw_arg0; + prom_argv = (char **)fw_arg1; + prom_envp = (char **)fw_arg2; + + prom_init_cmdline(); + + memsize = env_or_default("memsize", DEFAULT_MEMSIZE); + highmemsize = env_or_default("highmemsize", 0x0); +} + +void __init prom_free_prom_memory(void) +{ +} + +#define PORT(offset) (u8 *)(KSEG1ADDR(LS1X_UART0_BASE + offset)) + +void __init prom_putchar(char c) +{ + int timeout; + + timeout = 1024; + + while (((readb(PORT(UART_LSR)) & UART_LSR_THRE) == 0) + && (timeout-- > 0)) + ; + + writeb(c, PORT(UART_TX)); +} diff --git a/arch/mips/loongson1/common/reset.c b/arch/mips/loongson1/common/reset.c new file mode 100644 index 0000000..fb979a7 --- /dev/null +++ b/arch/mips/loongson1/common/reset.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include + +static void ls1x_restart(char *command) +{ + __raw_writel(0x1, LS1X_WDT_EN); + __raw_writel(0x5000000, LS1X_WDT_TIMER); + __raw_writel(0x1, LS1X_WDT_SET); +} + +static void ls1x_halt(void) +{ + while (1) { + if (cpu_wait) + cpu_wait(); + } +} + +static void ls1x_power_off(void) +{ + ls1x_halt(); +} + +static int __init ls1x_reboot_setup(void) +{ + _machine_restart = ls1x_restart; + _machine_halt = ls1x_halt; + pm_power_off = ls1x_power_off; + + return 0; +} + +arch_initcall(ls1x_reboot_setup); diff --git a/arch/mips/loongson1/common/setup.c b/arch/mips/loongson1/common/setup.c new file mode 100644 index 0000000..62128cc --- /dev/null +++ b/arch/mips/loongson1/common/setup.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include + +#include + +void __init plat_mem_setup(void) +{ + add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); +} + +const char *get_system_type(void) +{ + unsigned int processor_id = (¤t_cpu_data)->processor_id; + + switch (processor_id & PRID_REV_MASK) { + case PRID_REV_LOONGSON1B: + return "LOONGSON LS1B"; + default: + return "LOONGSON (unknown)"; + } +} diff --git a/arch/mips/loongson1/ls1b/Makefile b/arch/mips/loongson1/ls1b/Makefile new file mode 100644 index 0000000..891eac4 --- /dev/null +++ b/arch/mips/loongson1/ls1b/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for loongson1B based machines. +# + +obj-y += board.o diff --git a/arch/mips/loongson1/ls1b/board.c b/arch/mips/loongson1/ls1b/board.c new file mode 100644 index 0000000..295b1be --- /dev/null +++ b/arch/mips/loongson1/ls1b/board.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Zhang, Keguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include + +#include +#include + +static struct platform_device *ls1b_platform_devices[] __initdata = { + &ls1x_uart_device, + &ls1x_eth0_device, + &ls1x_ehci_device, + &ls1x_rtc_device, +}; + +static int __init ls1b_platform_init(void) +{ + int err; + + ls1x_serial_setup(); + + err = platform_add_devices(ls1b_platform_devices, + ARRAY_SIZE(ls1b_platform_devices)); + return err; +} + +arch_initcall(ls1b_platform_init); -- cgit v0.10.2 From 9afd40811538d82164f42dcdabdcf0f7065044a7 Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Wed, 25 Jul 2012 06:06:41 +0800 Subject: MIPS: Loongson 1B: Add defconfig Signed-off-by: Kelvin Cheung Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: wuzhangjin@gmail.com Cc: zhzhl555@gmail.com Cc: Kelvin Cheung Patchwork: https://patchwork.linux-mips.org/patch/4135/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/configs/ls1b_defconfig b/arch/mips/configs/ls1b_defconfig new file mode 100644 index 0000000..80cff8b --- /dev/null +++ b/arch/mips/configs/ls1b_defconfig @@ -0,0 +1,109 @@ +CONFIG_MACH_LOONGSON1=y +CONFIG_PREEMPT=y +# CONFIG_SECCOMP is not set +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_NAMESPACES=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_EXPERT=y +CONFIG_PERF_EVENTS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_SUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_SCSI=m +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=m +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_DA=y +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_WLAN is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_LEGACY_PTY_COUNT=8 +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_VGA_CONSOLE is not set +CONFIG_USB_HID=m +CONFIG_HID_GENERIC=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_STORAGE=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_LOONGSON1=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_ISO8859_1=m +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set +# CONFIG_EARLY_PRINTK is not set -- cgit v0.10.2