diff options
Diffstat (limited to 'arch/mips/bcm63xx')
| -rw-r--r-- | arch/mips/bcm63xx/Kconfig | 29 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/Makefile | 6 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/boards/Makefile | 2 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/boards/board_bcm963xx.c | 300 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/clk.c | 212 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/cpu.c | 419 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-dsp.c | 2 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-enet.c | 181 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-flash.c | 130 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-hsspi.c | 47 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-pcmcia.c | 4 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-rng.c | 40 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-spi.c | 102 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-uart.c | 3 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-usb-usbd.c | 65 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/dev-wdt.c | 2 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/early_printk.c | 7 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/gpio.c | 41 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/irq.c | 523 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/nvram.c | 127 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/prom.c | 58 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/reset.c | 278 | ||||
| -rw-r--r-- | arch/mips/bcm63xx/setup.c | 59 | 
23 files changed, 2151 insertions, 486 deletions
diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig index fb177d6df06..a057fdf111c 100644 --- a/arch/mips/bcm63xx/Kconfig +++ b/arch/mips/bcm63xx/Kconfig @@ -1,24 +1,43 @@  menu "CPU support"  	depends on BCM63XX +config BCM63XX_CPU_3368 +	bool "support 3368 CPU" +	select SYS_HAS_CPU_BMIPS4350 +	select HW_HAS_PCI + +config BCM63XX_CPU_6328 +	bool "support 6328 CPU" +	select SYS_HAS_CPU_BMIPS4350 +	select HW_HAS_PCI +  config BCM63XX_CPU_6338  	bool "support 6338 CPU" +	select SYS_HAS_CPU_BMIPS32_3300  	select HW_HAS_PCI -	select USB_ARCH_HAS_OHCI -	select USB_OHCI_BIG_ENDIAN_DESC -	select USB_OHCI_BIG_ENDIAN_MMIO  config BCM63XX_CPU_6345  	bool "support 6345 CPU" -	select USB_OHCI_BIG_ENDIAN_DESC -	select USB_OHCI_BIG_ENDIAN_MMIO +	select SYS_HAS_CPU_BMIPS32_3300  config BCM63XX_CPU_6348  	bool "support 6348 CPU" +	select SYS_HAS_CPU_BMIPS32_3300  	select HW_HAS_PCI  config BCM63XX_CPU_6358  	bool "support 6358 CPU" +	select SYS_HAS_CPU_BMIPS4350 +	select HW_HAS_PCI + +config BCM63XX_CPU_6362 +	bool "support 6362 CPU" +	select SYS_HAS_CPU_BMIPS4350 +	select HW_HAS_PCI + +config BCM63XX_CPU_6368 +	bool "support 6368 CPU" +	select SYS_HAS_CPU_BMIPS4350  	select HW_HAS_PCI  endmenu diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile index 6dfdc69928a..9019f54aee6 100644 --- a/arch/mips/bcm63xx/Makefile +++ b/arch/mips/bcm63xx/Makefile @@ -1,5 +1,7 @@ -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 +obj-y		+= clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \ +		   setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \ +		   dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \ +		   dev-wdt.o dev-usb-usbd.o  obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o  obj-y		+= boards/ diff --git a/arch/mips/bcm63xx/boards/Makefile b/arch/mips/bcm63xx/boards/Makefile index e5cc86dc1da..af07c1aa202 100644 --- a/arch/mips/bcm63xx/boards/Makefile +++ b/arch/mips/bcm63xx/boards/Makefile @@ -1,3 +1 @@  obj-$(CONFIG_BOARD_BCM963XX)		+= board_bcm963xx.o - -EXTRA_CFLAGS += -Werror diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index 8dba8cfb752..33727e7f0c7 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -11,9 +11,6 @@  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/platform_device.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/physmap.h>  #include <linux/ssb/ssb.h>  #include <asm/addrspace.h>  #include <bcm63xx_board.h> @@ -21,19 +18,106 @@  #include <bcm63xx_dev_uart.h>  #include <bcm63xx_regs.h>  #include <bcm63xx_io.h> +#include <bcm63xx_nvram.h>  #include <bcm63xx_dev_pci.h>  #include <bcm63xx_dev_enet.h>  #include <bcm63xx_dev_dsp.h> +#include <bcm63xx_dev_flash.h> +#include <bcm63xx_dev_hsspi.h>  #include <bcm63xx_dev_pcmcia.h> +#include <bcm63xx_dev_spi.h> +#include <bcm63xx_dev_usb_usbd.h>  #include <board_bcm963xx.h> +#include <uapi/linux/bcm933xx_hcs.h> +  #define PFX	"board_bcm963xx: " -static struct bcm963xx_nvram nvram; -static unsigned int mac_addr_used; +#define HCS_OFFSET_128K			0x20000 +  static struct board_info board;  /* + * known 3368 boards + */ +#ifdef CONFIG_BCM63XX_CPU_3368 +static struct board_info __initdata board_cvg834g = { +	.name				= "CVG834G_E15R3921", +	.expected_cpu_id		= 0x3368, + +	.has_uart0			= 1, +	.has_uart1			= 1, + +	.has_enet0			= 1, +	.has_pci			= 1, + +	.enet0 = { +		.has_phy		= 1, +		.use_internal_phy	= 1, +	}, + +	.leds = { +		{ +			.name		= "CVG834G:green:power", +			.gpio		= 37, +			.default_trigger= "default-on", +		}, +	}, + +	.ephy_reset_gpio		= 36, +	.ephy_reset_gpio_flags		= GPIOF_INIT_HIGH, +}; +#endif + +/* + * 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, +	.has_usbd			= 0, + +	.usbd = { +		.use_fullspeed		= 0, +		.port_no		= 0, +	}, + +	.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 @@ -359,9 +443,9 @@ static struct board_info __initdata board_FAST2404 = {  	.expected_cpu_id		= 0x6348,  	.has_uart0			= 1, -        .has_enet0			= 1, -        .has_enet1			= 1, -        .has_pci			= 1, +	.has_enet0			= 1, +	.has_enet1			= 1, +	.has_pci			= 1,  	.enet0 = {  		.has_phy		= 1, @@ -544,22 +628,22 @@ static struct board_info __initdata board_96358vw2 = {  };  static struct board_info __initdata board_AGPFS0 = { -	.name                           = "AGPF-S0", -	.expected_cpu_id                = 0x6358, +	.name				= "AGPF-S0", +	.expected_cpu_id		= 0x6358,  	.has_uart0			= 1, -	.has_enet0                      = 1, -	.has_enet1                      = 1, -	.has_pci                        = 1, +	.has_enet0			= 1, +	.has_enet1			= 1, +	.has_pci			= 1,  	.enet0 = { -		.has_phy                = 1, -		.use_internal_phy       = 1, +		.has_phy		= 1, +		.use_internal_phy	= 1,  	},  	.enet1 = { -		.force_speed_100        = 1, -		.force_duplex_full      = 1, +		.force_speed_100	= 1, +		.force_duplex_full	= 1,  	},  	.has_ohci0 = 1, @@ -591,7 +675,13 @@ static struct board_info __initdata board_DWVS0 = {  /*   * all boards   */ -static const struct board_info __initdata *bcm963xx_boards[] = { +static const struct board_info __initconst *bcm963xx_boards[] = { +#ifdef CONFIG_BCM63XX_CPU_3368 +	&board_cvg834g, +#endif +#ifdef CONFIG_BCM63XX_CPU_6328 +	&board_96328avng, +#endif  #ifdef CONFIG_BCM63XX_CPU_6338  	&board_96338gw,  	&board_96338w, @@ -627,7 +717,7 @@ static struct ssb_sprom bcm63xx_sprom = {  	.revision		= 0x02,  	.board_rev		= 0x17,  	.country_code		= 0x0, -	.ant_available_bg 	= 0x3, +	.ant_available_bg	= 0x3,  	.pa0b0			= 0x15ae,  	.pa0b1			= 0xfa85,  	.pa0b2			= 0xfe8d, @@ -643,6 +733,17 @@ static struct ssb_sprom bcm63xx_sprom = {  	.boardflags_lo		= 0x2848,  	.boardflags_hi		= 0x0000,  }; + +int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +{ +	if (bus->bustype == SSB_BUSTYPE_PCI) { +		memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom)); +		return 0; +	} else { +		printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n"); +		return -EINVAL; +	} +}  #endif  /* @@ -654,56 +755,23 @@ const char *board_get_name(void)  }  /* - * register & return a new board mac address - */ -static int board_get_mac_address(u8 *mac) -{ -	u8 *p; -	int count; - -	if (mac_addr_used >= nvram.mac_addr_count) { -		printk(KERN_ERR PFX "not enough mac address\n"); -		return -ENODEV; -	} - -	memcpy(mac, nvram.mac_addr_base, ETH_ALEN); -	p = mac + ETH_ALEN - 1; -	count = mac_addr_used; - -	while (count--) { -		do { -			(*p)++; -			if (*p != 0) -				break; -			p--; -		} while (p != mac); -	} - -	if (p == mac) { -		printk(KERN_ERR PFX "unable to fetch mac address\n"); -		return -ENODEV; -	} - -	mac_addr_used++; -	return 0; -} - -/*   * early init callback, read nvram data from flash and checksum it   */  void __init board_prom_init(void)  { -	unsigned int check_len, i; -	u8 *boot_addr, *cfe, *p; +	unsigned int i; +	u8 *boot_addr, *cfe;  	char cfe_version[32]; +	char *board_name = NULL;  	u32 val; +	struct bcm_hcs *hcs;  	/* read base address of boot chip select (0) -	 * 6345 does not have MPI but boots from standard -	 * MIPS Flash address */ -	if (BCMCPU_IS_6345()) -		val = 0x1fc00000; -	else { +	 * 6328/6362 do not have MPI but boot from a fixed address +	 */ +	if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) { +		val = 0x18000000; +	} else {  		val = bcm_mpi_readl(MPI_CSBASE_REG(0));  		val &= MPI_CSBASE_BASE_MASK;  	} @@ -718,27 +786,17 @@ void __init board_prom_init(void)  		strcpy(cfe_version, "unknown");  	printk(KERN_INFO PFX "CFE version: %s\n", cfe_version); -	/* extract nvram data */ -	memcpy(&nvram, boot_addr + BCM963XX_NVRAM_OFFSET, sizeof(nvram)); +	bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET); -	/* check checksum before using data */ -	if (nvram.version <= 4) -		check_len = offsetof(struct bcm963xx_nvram, checksum_old); -	else -		check_len = sizeof(nvram); -	val = 0; -	p = (u8 *)&nvram; -	while (check_len--) -		val += *p; -	if (val) { -		printk(KERN_ERR PFX "invalid nvram checksum\n"); -		return; +	if (BCMCPU_IS_3368()) { +		hcs = (struct bcm_hcs *)boot_addr; +		board_name = hcs->filename; +	} else { +		board_name = bcm63xx_nvram_get_name();  	} -  	/* find board by name */  	for (i = 0; i < ARRAY_SIZE(bcm963xx_boards); i++) { -		if (strncmp(nvram.name, bcm963xx_boards[i]->name, -			    sizeof(nvram.name))) +		if (strncmp(board_name, bcm963xx_boards[i]->name, 16))  			continue;  		/* copy, board desc array is marked initdata */  		memcpy(&board, bcm963xx_boards[i], sizeof(board)); @@ -748,7 +806,7 @@ void __init board_prom_init(void)  	/* bail out if board is not found, will complain later */  	if (!board.name[0]) {  		char name[17]; -		memcpy(name, nvram.name, 16); +		memcpy(name, board_name, 16);  		name[16] = 0;  		printk(KERN_ERR PFX "unknown bcm963xx board: %s\n",  		       name); @@ -786,17 +844,6 @@ void __init board_prom_init(void)  	}  	bcm_gpio_writel(val, GPIO_MODE_REG); - -	/* Generate MAC address for WLAN and -	 * register our SPROM */ -#ifdef CONFIG_SSB_PCIHOST -	if (!board_get_mac_address(bcm63xx_sprom.il0mac)) { -		memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); -		memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); -		if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0) -			printk(KERN_ERR "failed to register fallback SPROM\n"); -	} -#endif  }  /* @@ -814,37 +861,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 struct physmap_flash_data flash_data = { -	.width			= 2, -	.nr_parts		= ARRAY_SIZE(mtd_partitions), -	.parts			= mtd_partitions, -}; - -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 = { @@ -858,8 +874,6 @@ static struct platform_device bcm63xx_gpio_leds = {   */  int __init board_register_devices(void)  { -	u32 val; -  	if (board.has_uart0)  		bcm63xx_uart_register(0); @@ -870,32 +884,50 @@ int __init board_register_devices(void)  		bcm63xx_pcmcia_register();  	if (board.has_enet0 && -	    !board_get_mac_address(board.enet0.mac_addr)) +	    !bcm63xx_nvram_get_mac_address(board.enet0.mac_addr))  		bcm63xx_enet_register(0, &board.enet0);  	if (board.has_enet1 && -	    !board_get_mac_address(board.enet1.mac_addr)) +	    !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))  		bcm63xx_enet_register(1, &board.enet1); +	if (board.has_enetsw && +	    !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr)) +		bcm63xx_enetsw_register(&board.enetsw); + +	if (board.has_usbd) +		bcm63xx_usbd_register(&board.usbd); +  	if (board.has_dsp)  		bcm63xx_dsp_register(&board.dsp); -	/* read base address of boot chip select (0) */ -	if (BCMCPU_IS_6345()) -		val = 0x1fc00000; -	else { -		val = bcm_mpi_readl(MPI_CSBASE_REG(0)); -		val &= MPI_CSBASE_BASE_MASK; +	/* Generate MAC address for WLAN and register our SPROM, +	 * do this after registering enet devices +	 */ +#ifdef CONFIG_SSB_PCIHOST +	if (!bcm63xx_nvram_get_mac_address(bcm63xx_sprom.il0mac)) { +		memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); +		memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); +		if (ssb_arch_register_fallback_sprom( +				&bcm63xx_get_fallback_sprom) < 0) +			pr_err(PFX "failed to register fallback SPROM\n");  	} -	mtd_resources[0].start = val; -	mtd_resources[0].end = 0x1FFFFFFF; +#endif -	platform_device_register(&mtd_dev); +	bcm63xx_spi_register(); + +	bcm63xx_hsspi_register(); + +	bcm63xx_flash_register();  	bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);  	bcm63xx_led_data.leds = board.leds;  	platform_device_register(&bcm63xx_gpio_leds); +	if (board.ephy_reset_gpio && board.ephy_reset_gpio_flags) +		gpio_request_one(board.ephy_reset_gpio, +				board.ephy_reset_gpio_flags, "ephy-reset"); +  	return 0;  } diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c index 2c68ee9ccee..63756528473 100644 --- a/arch/mips/bcm63xx/clk.c +++ b/arch/mips/bcm63xx/clk.c @@ -10,10 +10,18 @@  #include <linux/mutex.h>  #include <linux/err.h>  #include <linux/clk.h> +#include <linux/delay.h>  #include <bcm63xx_cpu.h>  #include <bcm63xx_io.h>  #include <bcm63xx_regs.h> -#include <bcm63xx_clk.h> +#include <bcm63xx_reset.h> + +struct clk { +	void		(*set)(struct clk *, int); +	unsigned int	rate; +	unsigned int	usage; +	int		id; +};  static DEFINE_MUTEX(clocks_mutex); @@ -76,7 +84,7 @@ static void enetx_set(struct clk *clk, int enable)  	else  		clk_disable_unlocked(&clk_enet_misc); -	if (BCMCPU_IS_6358()) { +	if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {  		u32 mask;  		if (clk->id == 0) @@ -102,9 +110,8 @@ static struct clk clk_enet1 = {   */  static void ephy_set(struct clk *clk, int enable)  { -	if (!BCMCPU_IS_6358()) -		return; -	bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable); +	if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) +		bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);  } @@ -113,13 +120,44 @@ static struct clk clk_ephy = {  };  /* + * Ethernet switch clock + */ +static void enetsw_set(struct clk *clk, int enable) +{ +	if (BCMCPU_IS_6328()) +		bcm_hwclock_set(CKCTL_6328_ROBOSW_EN, enable); +	else if (BCMCPU_IS_6362()) +		bcm_hwclock_set(CKCTL_6362_ROBOSW_EN, enable); +	else if (BCMCPU_IS_6368()) +		bcm_hwclock_set(CKCTL_6368_ROBOSW_EN | +				CKCTL_6368_SWPKT_USB_EN | +				CKCTL_6368_SWPKT_SAR_EN, +				enable); +	else +		return; + +	if (enable) { +		/* reset switch core afer clock change */ +		bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1); +		msleep(10); +		bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0); +		msleep(10); +	} +} + +static struct clk clk_enetsw = { +	.set	= enetsw_set, +}; + +/*   * PCM clock   */  static void pcm_set(struct clk *clk, int enable)  { -	if (!BCMCPU_IS_6358()) -		return; -	bcm_hwclock_set(CKCTL_6358_PCM_EN, enable); +	if (BCMCPU_IS_3368()) +		bcm_hwclock_set(CKCTL_3368_PCM_EN, enable); +	if (BCMCPU_IS_6358()) +		bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);  }  static struct clk clk_pcm = { @@ -131,9 +169,14 @@ static struct clk clk_pcm = {   */  static void usbh_set(struct clk *clk, int enable)  { -	if (!BCMCPU_IS_6348()) -		return; -	bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); +	if (BCMCPU_IS_6328()) +		bcm_hwclock_set(CKCTL_6328_USBH_EN, enable); +	else if (BCMCPU_IS_6348()) +		bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); +	else if (BCMCPU_IS_6362()) +		bcm_hwclock_set(CKCTL_6362_USBH_EN, enable); +	else if (BCMCPU_IS_6368()) +		bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);  }  static struct clk clk_usbh = { @@ -141,6 +184,23 @@ static struct clk clk_usbh = {  };  /* + * USB device clock + */ +static void usbd_set(struct clk *clk, int enable) +{ +	if (BCMCPU_IS_6328()) +		bcm_hwclock_set(CKCTL_6328_USBD_EN, enable); +	else if (BCMCPU_IS_6362()) +		bcm_hwclock_set(CKCTL_6362_USBD_EN, enable); +	else if (BCMCPU_IS_6368()) +		bcm_hwclock_set(CKCTL_6368_USBD_EN, enable); +} + +static struct clk clk_usbd = { +	.set	= usbd_set, +}; + +/*   * SPI clock   */  static void spi_set(struct clk *clk, int enable) @@ -151,9 +211,13 @@ 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_3368() || BCMCPU_IS_6358())  		mask = CKCTL_6358_SPI_EN; +	else if (BCMCPU_IS_6362()) +		mask = CKCTL_6362_SPI_EN; +	else +		/* BCMCPU_IS_6368 */ +		mask = CKCTL_6368_SPI_EN;  	bcm_hwclock_set(mask, enable);  } @@ -162,6 +226,84 @@ static struct clk clk_spi = {  };  /* + * HSSPI clock + */ +static void hsspi_set(struct clk *clk, int enable) +{ +	u32 mask; + +	if (BCMCPU_IS_6328()) +		mask = CKCTL_6328_HSSPI_EN; +	else if (BCMCPU_IS_6362()) +		mask = CKCTL_6362_HSSPI_EN; +	else +		return; + +	bcm_hwclock_set(mask, enable); +} + +static struct clk clk_hsspi = { +	.set	= hsspi_set, +}; + + +/* + * XTM clock + */ +static void xtm_set(struct clk *clk, int enable) +{ +	if (!BCMCPU_IS_6368()) +		return; + +	bcm_hwclock_set(CKCTL_6368_SAR_EN | +			CKCTL_6368_SWPKT_SAR_EN, enable); + +	if (enable) { +		/* reset sar core afer clock change */ +		bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1); +		mdelay(1); +		bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0); +		mdelay(1); +	} +} + + +static struct clk clk_xtm = { +	.set	= xtm_set, +}; + +/* + * IPsec clock + */ +static void ipsec_set(struct clk *clk, int enable) +{ +	if (BCMCPU_IS_6362()) +		bcm_hwclock_set(CKCTL_6362_IPSEC_EN, enable); +	else if (BCMCPU_IS_6368()) +		bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable); +} + +static struct clk clk_ipsec = { +	.set	= ipsec_set, +}; + +/* + * PCIe clock + */ + +static void pcie_set(struct clk *clk, int enable) +{ +	if (BCMCPU_IS_6328()) +		bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable); +	else if (BCMCPU_IS_6362()) +		bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable); +} + +static struct clk clk_pcie = { +	.set	= pcie_set, +}; + +/*   * Internal peripheral clock   */  static struct clk clk_periph = { @@ -198,22 +340,46 @@ unsigned long clk_get_rate(struct clk *clk)  EXPORT_SYMBOL(clk_get_rate); +int clk_set_rate(struct clk *clk, unsigned long rate) +{ +	return 0; +} +EXPORT_SYMBOL_GPL(clk_set_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ +	return 0; +} +EXPORT_SYMBOL_GPL(clk_round_rate); +  struct clk *clk_get(struct device *dev, const char *id)  {  	if (!strcmp(id, "enet0"))  		return &clk_enet0;  	if (!strcmp(id, "enet1"))  		return &clk_enet1; +	if (!strcmp(id, "enetsw")) +		return &clk_enetsw;  	if (!strcmp(id, "ephy"))  		return &clk_ephy;  	if (!strcmp(id, "usbh"))  		return &clk_usbh; +	if (!strcmp(id, "usbd")) +		return &clk_usbd;  	if (!strcmp(id, "spi"))  		return &clk_spi; +	if (!strcmp(id, "hsspi")) +		return &clk_hsspi; +	if (!strcmp(id, "xtm")) +		return &clk_xtm;  	if (!strcmp(id, "periph"))  		return &clk_periph; -	if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) +	if ((BCMCPU_IS_3368() || BCMCPU_IS_6358()) && !strcmp(id, "pcm"))  		return &clk_pcm; +	if ((BCMCPU_IS_6362() || BCMCPU_IS_6368()) && !strcmp(id, "ipsec")) +		return &clk_ipsec; +	if ((BCMCPU_IS_6328() || BCMCPU_IS_6362()) && !strcmp(id, "pcie")) +		return &clk_pcie;  	return ERR_PTR(-ENOENT);  } @@ -224,3 +390,21 @@ void clk_put(struct clk *clk)  }  EXPORT_SYMBOL(clk_put); + +#define HSSPI_PLL_HZ_6328	133333333 +#define HSSPI_PLL_HZ_6362	400000000 + +static int __init bcm63xx_clk_init(void) +{ +	switch (bcm63xx_get_cpu_id()) { +	case BCM6328_CPU_ID: +		clk_hsspi.rate = HSSPI_PLL_HZ_6328; +		break; +	case BCM6362_CPU_ID: +		clk_hsspi.rate = HSSPI_PLL_HZ_6362; +		break; +	} + +	return 0; +} +arch_initcall(bcm63xx_clk_init); diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c index 7c7e4d4486c..fd4e76c00a4 100644 --- a/arch/mips/bcm63xx/cpu.c +++ b/arch/mips/bcm63xx/cpu.c @@ -25,170 +25,76 @@ const int *bcm63xx_irqs;  EXPORT_SYMBOL(bcm63xx_irqs);  static u16 bcm63xx_cpu_id; -static u16 bcm63xx_cpu_rev; +static u8 bcm63xx_cpu_rev;  static unsigned int bcm63xx_cpu_freq;  static unsigned int bcm63xx_memory_size; -/* - * 6338 register sets and irqs - */ -static const unsigned long bcm96338_regs_base[] = { -	[RSET_DSL_LMEM]		= BCM_6338_DSL_LMEM_BASE, -	[RSET_PERF]		= BCM_6338_PERF_BASE, -	[RSET_TIMER]		= BCM_6338_TIMER_BASE, -	[RSET_WDT]		= BCM_6338_WDT_BASE, -	[RSET_UART0]		= BCM_6338_UART0_BASE, -	[RSET_UART1]		= BCM_6338_UART1_BASE, -	[RSET_GPIO]		= BCM_6338_GPIO_BASE, -	[RSET_SPI]		= BCM_6338_SPI_BASE, -	[RSET_OHCI0]		= BCM_6338_OHCI0_BASE, -	[RSET_OHCI_PRIV]	= BCM_6338_OHCI_PRIV_BASE, -	[RSET_USBH_PRIV]	= BCM_6338_USBH_PRIV_BASE, -	[RSET_UDC0]		= BCM_6338_UDC0_BASE, -	[RSET_MPI]		= BCM_6338_MPI_BASE, -	[RSET_PCMCIA]		= BCM_6338_PCMCIA_BASE, -	[RSET_SDRAM]		= BCM_6338_SDRAM_BASE, -	[RSET_DSL]		= BCM_6338_DSL_BASE, -	[RSET_ENET0]		= BCM_6338_ENET0_BASE, -	[RSET_ENET1]		= BCM_6338_ENET1_BASE, -	[RSET_ENETDMA]		= BCM_6338_ENETDMA_BASE, -	[RSET_MEMC]		= BCM_6338_MEMC_BASE, -	[RSET_DDR]		= BCM_6338_DDR_BASE, +static const unsigned long bcm3368_regs_base[] = { +	__GEN_CPU_REGS_TABLE(3368)  }; -static const int bcm96338_irqs[] = { -	[IRQ_TIMER]		= BCM_6338_TIMER_IRQ, -	[IRQ_UART0]		= BCM_6338_UART0_IRQ, -	[IRQ_DSL]		= BCM_6338_DSL_IRQ, -	[IRQ_ENET0]		= BCM_6338_ENET0_IRQ, -	[IRQ_ENET_PHY]		= BCM_6338_ENET_PHY_IRQ, -	[IRQ_ENET0_RXDMA]	= BCM_6338_ENET0_RXDMA_IRQ, -	[IRQ_ENET0_TXDMA]	= BCM_6338_ENET0_TXDMA_IRQ, +static const int bcm3368_irqs[] = { +	__GEN_CPU_IRQ_TABLE(3368)  }; -/* - * 6345 register sets and irqs - */ -static const unsigned long bcm96345_regs_base[] = { -	[RSET_DSL_LMEM]		= BCM_6345_DSL_LMEM_BASE, -	[RSET_PERF]		= BCM_6345_PERF_BASE, -	[RSET_TIMER]		= BCM_6345_TIMER_BASE, -	[RSET_WDT]		= BCM_6345_WDT_BASE, -	[RSET_UART0]		= BCM_6345_UART0_BASE, -	[RSET_UART1]		= BCM_6345_UART1_BASE, -	[RSET_GPIO]		= BCM_6345_GPIO_BASE, -	[RSET_SPI]		= BCM_6345_SPI_BASE, -	[RSET_UDC0]		= BCM_6345_UDC0_BASE, -	[RSET_OHCI0]		= BCM_6345_OHCI0_BASE, -	[RSET_OHCI_PRIV]	= BCM_6345_OHCI_PRIV_BASE, -	[RSET_USBH_PRIV]	= BCM_6345_USBH_PRIV_BASE, -	[RSET_MPI]		= BCM_6345_MPI_BASE, -	[RSET_PCMCIA]		= BCM_6345_PCMCIA_BASE, -	[RSET_DSL]		= BCM_6345_DSL_BASE, -	[RSET_ENET0]		= BCM_6345_ENET0_BASE, -	[RSET_ENET1]		= BCM_6345_ENET1_BASE, -	[RSET_ENETDMA]		= BCM_6345_ENETDMA_BASE, -	[RSET_EHCI0]		= BCM_6345_EHCI0_BASE, -	[RSET_SDRAM]		= BCM_6345_SDRAM_BASE, -	[RSET_MEMC]		= BCM_6345_MEMC_BASE, -	[RSET_DDR]		= BCM_6345_DDR_BASE, +static const unsigned long bcm6328_regs_base[] = { +	__GEN_CPU_REGS_TABLE(6328)  }; -static const int bcm96345_irqs[] = { -	[IRQ_TIMER]		= BCM_6345_TIMER_IRQ, -	[IRQ_UART0]		= BCM_6345_UART0_IRQ, -	[IRQ_DSL]		= BCM_6345_DSL_IRQ, -	[IRQ_ENET0]		= BCM_6345_ENET0_IRQ, -	[IRQ_ENET_PHY]		= BCM_6345_ENET_PHY_IRQ, -	[IRQ_ENET0_RXDMA]	= BCM_6345_ENET0_RXDMA_IRQ, -	[IRQ_ENET0_TXDMA]	= BCM_6345_ENET0_TXDMA_IRQ, +static const int bcm6328_irqs[] = { +	__GEN_CPU_IRQ_TABLE(6328)  }; -/* - * 6348 register sets and irqs - */ -static const unsigned long bcm96348_regs_base[] = { -	[RSET_DSL_LMEM]		= BCM_6348_DSL_LMEM_BASE, -	[RSET_PERF]		= BCM_6348_PERF_BASE, -	[RSET_TIMER]		= BCM_6348_TIMER_BASE, -	[RSET_WDT]		= BCM_6348_WDT_BASE, -	[RSET_UART0]		= BCM_6348_UART0_BASE, -	[RSET_UART1]		= BCM_6348_UART1_BASE, -	[RSET_GPIO]		= BCM_6348_GPIO_BASE, -	[RSET_SPI]		= BCM_6348_SPI_BASE, -	[RSET_OHCI0]		= BCM_6348_OHCI0_BASE, -	[RSET_OHCI_PRIV]	= BCM_6348_OHCI_PRIV_BASE, -	[RSET_USBH_PRIV]	= BCM_6348_USBH_PRIV_BASE, -	[RSET_MPI]		= BCM_6348_MPI_BASE, -	[RSET_PCMCIA]		= BCM_6348_PCMCIA_BASE, -	[RSET_SDRAM]		= BCM_6348_SDRAM_BASE, -	[RSET_DSL]		= BCM_6348_DSL_BASE, -	[RSET_ENET0]		= BCM_6348_ENET0_BASE, -	[RSET_ENET1]		= BCM_6348_ENET1_BASE, -	[RSET_ENETDMA]		= BCM_6348_ENETDMA_BASE, -	[RSET_MEMC]		= BCM_6348_MEMC_BASE, -	[RSET_DDR]		= BCM_6348_DDR_BASE, +static const unsigned long bcm6338_regs_base[] = { +	__GEN_CPU_REGS_TABLE(6338)  }; -static const int bcm96348_irqs[] = { -	[IRQ_TIMER]		= BCM_6348_TIMER_IRQ, -	[IRQ_UART0]		= BCM_6348_UART0_IRQ, -	[IRQ_DSL]		= BCM_6348_DSL_IRQ, -	[IRQ_ENET0]		= BCM_6348_ENET0_IRQ, -	[IRQ_ENET1]		= BCM_6348_ENET1_IRQ, -	[IRQ_ENET_PHY]		= BCM_6348_ENET_PHY_IRQ, -	[IRQ_OHCI0]		= BCM_6348_OHCI0_IRQ, -	[IRQ_PCMCIA]		= BCM_6348_PCMCIA_IRQ, -	[IRQ_ENET0_RXDMA]	= BCM_6348_ENET0_RXDMA_IRQ, -	[IRQ_ENET0_TXDMA]	= BCM_6348_ENET0_TXDMA_IRQ, -	[IRQ_ENET1_RXDMA]	= BCM_6348_ENET1_RXDMA_IRQ, -	[IRQ_ENET1_TXDMA]	= BCM_6348_ENET1_TXDMA_IRQ, -	[IRQ_PCI]		= BCM_6348_PCI_IRQ, +static const int bcm6338_irqs[] = { +	__GEN_CPU_IRQ_TABLE(6338)  }; -/* - * 6358 register sets and irqs - */ -static const unsigned long bcm96358_regs_base[] = { -	[RSET_DSL_LMEM]		= BCM_6358_DSL_LMEM_BASE, -	[RSET_PERF]		= BCM_6358_PERF_BASE, -	[RSET_TIMER]		= BCM_6358_TIMER_BASE, -	[RSET_WDT]		= BCM_6358_WDT_BASE, -	[RSET_UART0]		= BCM_6358_UART0_BASE, -	[RSET_UART1]		= BCM_6358_UART1_BASE, -	[RSET_GPIO]		= BCM_6358_GPIO_BASE, -	[RSET_SPI]		= BCM_6358_SPI_BASE, -	[RSET_OHCI0]		= BCM_6358_OHCI0_BASE, -	[RSET_EHCI0]		= BCM_6358_EHCI0_BASE, -	[RSET_OHCI_PRIV]	= BCM_6358_OHCI_PRIV_BASE, -	[RSET_USBH_PRIV]	= BCM_6358_USBH_PRIV_BASE, -	[RSET_MPI]		= BCM_6358_MPI_BASE, -	[RSET_PCMCIA]		= BCM_6358_PCMCIA_BASE, -	[RSET_SDRAM]		= BCM_6358_SDRAM_BASE, -	[RSET_DSL]		= BCM_6358_DSL_BASE, -	[RSET_ENET0]		= BCM_6358_ENET0_BASE, -	[RSET_ENET1]		= BCM_6358_ENET1_BASE, -	[RSET_ENETDMA]		= BCM_6358_ENETDMA_BASE, -	[RSET_MEMC]		= BCM_6358_MEMC_BASE, -	[RSET_DDR]		= BCM_6358_DDR_BASE, +static const unsigned long bcm6345_regs_base[] = { +	__GEN_CPU_REGS_TABLE(6345) +}; + +static const int bcm6345_irqs[] = { +	__GEN_CPU_IRQ_TABLE(6345) +}; + +static const unsigned long bcm6348_regs_base[] = { +	__GEN_CPU_REGS_TABLE(6348) +}; + +static const int bcm6348_irqs[] = { +	__GEN_CPU_IRQ_TABLE(6348) + +}; + +static const unsigned long bcm6358_regs_base[] = { +	__GEN_CPU_REGS_TABLE(6358) +}; + +static const int bcm6358_irqs[] = { +	__GEN_CPU_IRQ_TABLE(6358) + +}; + +static const unsigned long bcm6362_regs_base[] = { +	__GEN_CPU_REGS_TABLE(6362) +}; + +static const int bcm6362_irqs[] = { +	__GEN_CPU_IRQ_TABLE(6362) + +}; + +static const unsigned long bcm6368_regs_base[] = { +	__GEN_CPU_REGS_TABLE(6368)  }; -static const int bcm96358_irqs[] = { -	[IRQ_TIMER]		= BCM_6358_TIMER_IRQ, -	[IRQ_UART0]		= BCM_6358_UART0_IRQ, -	[IRQ_UART1]		= BCM_6358_UART1_IRQ, -	[IRQ_DSL]		= BCM_6358_DSL_IRQ, -	[IRQ_ENET0]		= BCM_6358_ENET0_IRQ, -	[IRQ_ENET1]		= BCM_6358_ENET1_IRQ, -	[IRQ_ENET_PHY]		= BCM_6358_ENET_PHY_IRQ, -	[IRQ_OHCI0]		= BCM_6358_OHCI0_IRQ, -	[IRQ_EHCI0]		= BCM_6358_EHCI0_IRQ, -	[IRQ_PCMCIA]		= BCM_6358_PCMCIA_IRQ, -	[IRQ_ENET0_RXDMA]	= BCM_6358_ENET0_RXDMA_IRQ, -	[IRQ_ENET0_TXDMA]	= BCM_6358_ENET0_TXDMA_IRQ, -	[IRQ_ENET1_RXDMA]	= BCM_6358_ENET1_RXDMA_IRQ, -	[IRQ_ENET1_TXDMA]	= BCM_6358_ENET1_TXDMA_IRQ, -	[IRQ_PCI]		= BCM_6358_PCI_IRQ, +static const int bcm6368_irqs[] = { +	__GEN_CPU_IRQ_TABLE(6368) +  };  u16 __bcm63xx_get_cpu_id(void) @@ -198,7 +104,7 @@ u16 __bcm63xx_get_cpu_id(void)  EXPORT_SYMBOL(__bcm63xx_get_cpu_id); -u16 bcm63xx_get_cpu_rev(void) +u8 bcm63xx_get_cpu_rev(void)  {  	return bcm63xx_cpu_rev;  } @@ -217,20 +123,51 @@ unsigned int bcm63xx_get_memory_size(void)  static unsigned int detect_cpu_clock(void)  { -	unsigned int tmp, n1 = 0, n2 = 0, m1 = 0; +	u16 cpu_id = bcm63xx_get_cpu_id(); + +	switch (cpu_id) { +	case BCM3368_CPU_ID: +		return 300000000; + +	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; +		} -	/* BCM6338 has a fixed 240 Mhz frequency */ -	if (BCMCPU_IS_6338()) +	} +	case BCM6338_CPU_ID: +		/* BCM6338 has a fixed 240 Mhz frequency */  		return 240000000; -	/* BCM6345 has a fixed 140Mhz frequency */ -	if (BCMCPU_IS_6345()) +	case BCM6345_CPU_ID: +		/* BCM6345 has a fixed 140Mhz frequency */  		return 140000000; -	/* -	 * frequency depends on PLL configuration: -	 */ -	if (BCMCPU_IS_6348()) { +	case BCM6348_CPU_ID: +	{ +		unsigned int tmp, n1, n2, m1; +  		/* 16MHz * (N1 + 1) * (N2 + 2) / (M1_CPU + 1) */  		tmp = bcm_perf_readl(PERF_MIPSPLLCTL_REG);  		n1 = (tmp & MIPSPLLCTL_N1_MASK) >> MIPSPLLCTL_N1_SHIFT; @@ -239,17 +176,83 @@ static unsigned int detect_cpu_clock(void)  		n1 += 1;  		n2 += 2;  		m1 += 1; +		return (16 * 1000000 * n1 * n2) / m1;  	} -	if (BCMCPU_IS_6358()) { +	case BCM6358_CPU_ID: +	{ +		unsigned int tmp, n1, n2, m1; +  		/* 16MHz * N1 * N2 / M1_CPU */  		tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_REG);  		n1 = (tmp & DMIPSPLLCFG_N1_MASK) >> DMIPSPLLCFG_N1_SHIFT;  		n2 = (tmp & DMIPSPLLCFG_N2_MASK) >> DMIPSPLLCFG_N2_SHIFT;  		m1 = (tmp & DMIPSPLLCFG_M1_MASK) >> DMIPSPLLCFG_M1_SHIFT; +		return (16 * 1000000 * n1 * n2) / m1; +	} + +	case BCM6362_CPU_ID: +	{ +		unsigned int tmp, mips_pll_fcvo; + +		tmp = bcm_misc_readl(MISC_STRAPBUS_6362_REG); +		mips_pll_fcvo = (tmp & STRAPBUS_6362_FCVO_MASK) +				>> STRAPBUS_6362_FCVO_SHIFT; +		switch (mips_pll_fcvo) { +		case 0x03: +		case 0x0b: +		case 0x13: +		case 0x1b: +			return 240000000; +		case 0x04: +		case 0x0c: +		case 0x14: +		case 0x1c: +			return 160000000; +		case 0x05: +		case 0x0e: +		case 0x16: +		case 0x1e: +		case 0x1f: +			return 400000000; +		case 0x06: +			return 440000000; +		case 0x07: +		case 0x17: +			return 384000000; +		case 0x15: +		case 0x1d: +			return 200000000; +		default: +			return 320000000; +		} +	} +	case BCM6368_CPU_ID: +	{ +		unsigned int tmp, p1, p2, ndiv, m1; + +		/* (64MHz / P1) * P2 * NDIV / M1_CPU */ +		tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_6368_REG); + +		p1 = (tmp & DMIPSPLLCFG_6368_P1_MASK) >> +			DMIPSPLLCFG_6368_P1_SHIFT; + +		p2 = (tmp & DMIPSPLLCFG_6368_P2_MASK) >> +			DMIPSPLLCFG_6368_P2_SHIFT; + +		ndiv = (tmp & DMIPSPLLCFG_6368_NDIV_MASK) >> +			DMIPSPLLCFG_6368_NDIV_SHIFT; + +		tmp = bcm_ddr_readl(DDR_DMIPSPLLDIV_6368_REG); +		m1 = (tmp & DMIPSPLLDIV_6368_MDIV_MASK) >> +			DMIPSPLLDIV_6368_MDIV_SHIFT; + +		return (((64 * 1000000) / p1) * p2 * ndiv) / m1;  	} -	return (16 * 1000000 * n1 * n2) / m1; +	default: +		panic("Failed to detect clock for CPU with id=%04X\n", cpu_id); +	}  }  /* @@ -260,8 +263,13 @@ static unsigned int detect_memory_size(void)  	unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;  	u32 val; -	if (BCMCPU_IS_6345()) -		return (8 * 1024 * 1024); +	if (BCMCPU_IS_6328() || BCMCPU_IS_6362()) +		return bcm_ddr_readl(DDR_CSEND_REG) << 24; + +	if (BCMCPU_IS_6345()) { +		val = bcm_sdram_readl(SDRAM_MBASE_REG); +		return (val * 8 * 1024 * 1024); +	}  	if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {  		val = bcm_sdram_readl(SDRAM_CFG_REG); @@ -271,7 +279,7 @@ static unsigned int detect_memory_size(void)  		banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1;  	} -	if (BCMCPU_IS_6358()) { +	if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6368()) {  		val = bcm_memc_readl(MEMC_CFG_REG);  		rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;  		cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT; @@ -290,35 +298,33 @@ static unsigned int detect_memory_size(void)  void __init bcm63xx_cpu_init(void)  { -	unsigned int tmp, expected_cpu_id; -	struct cpuinfo_mips *c = ¤t_cpu_data; +	unsigned int tmp;  	unsigned int cpu = smp_processor_id(); +	u32 chipid_reg;  	/* soc registers location depends on cpu type */ -	expected_cpu_id = 0; +	chipid_reg = 0; -	switch (c->cputype) { +	switch (current_cpu_type()) {  	case CPU_BMIPS3300: -		if ((read_c0_prid() & 0xff00) == PRID_IMP_BMIPS3300_ALT) { -			expected_cpu_id = BCM6348_CPU_ID; -			bcm63xx_regs_base = bcm96348_regs_base; -			bcm63xx_irqs = bcm96348_irqs; -		} else { +		if ((read_c0_prid() & PRID_IMP_MASK) != PRID_IMP_BMIPS3300_ALT)  			__cpu_name[cpu] = "Broadcom BCM6338"; -			expected_cpu_id = BCM6338_CPU_ID; -			bcm63xx_regs_base = bcm96338_regs_base; -			bcm63xx_irqs = bcm96338_irqs; -		} -		break; +		/* fall-through */  	case CPU_BMIPS32: -		expected_cpu_id = BCM6345_CPU_ID; -		bcm63xx_regs_base = bcm96345_regs_base; -		bcm63xx_irqs = bcm96345_irqs; +		chipid_reg = BCM_6345_PERF_BASE;  		break;  	case CPU_BMIPS4350: -		expected_cpu_id = BCM6358_CPU_ID; -		bcm63xx_regs_base = bcm96358_regs_base; -		bcm63xx_irqs = bcm96358_irqs; +		switch ((read_c0_prid() & PRID_REV_MASK)) { +		case 0x04: +			chipid_reg = BCM_3368_PERF_BASE; +			break; +		case 0x10: +			chipid_reg = BCM_6345_PERF_BASE; +			break; +		default: +			chipid_reg = BCM_6368_PERF_BASE; +			break; +		}  		break;  	} @@ -326,20 +332,51 @@ void __init bcm63xx_cpu_init(void)  	 * really early to panic, but delaying panic would not help since we  	 * will never get any working console  	 */ -	if (!expected_cpu_id) +	if (!chipid_reg)  		panic("unsupported Broadcom CPU"); -	/* -	 * bcm63xx_regs_base is set, we can access soc registers -	 */ - -	/* double check CPU type */ -	tmp = bcm_perf_readl(PERF_REV_REG); +	/* read out CPU type */ +	tmp = bcm_readl(chipid_reg);  	bcm63xx_cpu_id = (tmp & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;  	bcm63xx_cpu_rev = (tmp & REV_REVID_MASK) >> REV_REVID_SHIFT; -	if (bcm63xx_cpu_id != expected_cpu_id) -		panic("bcm63xx CPU id mismatch"); +	switch (bcm63xx_cpu_id) { +	case BCM3368_CPU_ID: +		bcm63xx_regs_base = bcm3368_regs_base; +		bcm63xx_irqs = bcm3368_irqs; +		break; +	case BCM6328_CPU_ID: +		bcm63xx_regs_base = bcm6328_regs_base; +		bcm63xx_irqs = bcm6328_irqs; +		break; +	case BCM6338_CPU_ID: +		bcm63xx_regs_base = bcm6338_regs_base; +		bcm63xx_irqs = bcm6338_irqs; +		break; +	case BCM6345_CPU_ID: +		bcm63xx_regs_base = bcm6345_regs_base; +		bcm63xx_irqs = bcm6345_irqs; +		break; +	case BCM6348_CPU_ID: +		bcm63xx_regs_base = bcm6348_regs_base; +		bcm63xx_irqs = bcm6348_irqs; +		break; +	case BCM6358_CPU_ID: +		bcm63xx_regs_base = bcm6358_regs_base; +		bcm63xx_irqs = bcm6358_irqs; +		break; +	case BCM6362_CPU_ID: +		bcm63xx_regs_base = bcm6362_regs_base; +		bcm63xx_irqs = bcm6362_irqs; +		break; +	case BCM6368_CPU_ID: +		bcm63xx_regs_base = bcm6368_regs_base; +		bcm63xx_irqs = bcm6368_irqs; +		break; +	default: +		panic("unsupported broadcom CPU %x", bcm63xx_cpu_id); +		break; +	}  	bcm63xx_cpu_freq = detect_cpu_clock();  	bcm63xx_memory_size = detect_memory_size(); diff --git a/arch/mips/bcm63xx/dev-dsp.c b/arch/mips/bcm63xx/dev-dsp.c index da46d1d3c77..5bb5b154c9b 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-enet.c b/arch/mips/bcm63xx/dev-enet.c index 39c23366c5c..52bc01df9bf 100644 --- a/arch/mips/bcm63xx/dev-enet.c +++ b/arch/mips/bcm63xx/dev-enet.c @@ -9,16 +9,60 @@  #include <linux/init.h>  #include <linux/kernel.h>  #include <linux/platform_device.h> +#include <linux/export.h>  #include <bcm63xx_dev_enet.h>  #include <bcm63xx_io.h>  #include <bcm63xx_regs.h> +#ifdef BCMCPU_RUNTIME_DETECT +static const unsigned long bcm6348_regs_enetdmac[] = { +	[ENETDMAC_CHANCFG]	= ENETDMAC_CHANCFG_REG, +	[ENETDMAC_IR]		= ENETDMAC_IR_REG, +	[ENETDMAC_IRMASK]	= ENETDMAC_IRMASK_REG, +	[ENETDMAC_MAXBURST]	= ENETDMAC_MAXBURST_REG, +}; + +static const unsigned long bcm6345_regs_enetdmac[] = { +	[ENETDMAC_CHANCFG]	= ENETDMA_6345_CHANCFG_REG, +	[ENETDMAC_IR]		= ENETDMA_6345_IR_REG, +	[ENETDMAC_IRMASK]	= ENETDMA_6345_IRMASK_REG, +	[ENETDMAC_MAXBURST]	= ENETDMA_6345_MAXBURST_REG, +	[ENETDMAC_BUFALLOC]	= ENETDMA_6345_BUFALLOC_REG, +	[ENETDMAC_RSTART]	= ENETDMA_6345_RSTART_REG, +	[ENETDMAC_FC]		= ENETDMA_6345_FC_REG, +	[ENETDMAC_LEN]		= ENETDMA_6345_LEN_REG, +}; + +const unsigned long *bcm63xx_regs_enetdmac; +EXPORT_SYMBOL(bcm63xx_regs_enetdmac); + +static __init void bcm63xx_enetdmac_regs_init(void) +{ +	if (BCMCPU_IS_6345()) +		bcm63xx_regs_enetdmac = bcm6345_regs_enetdmac; +	else +		bcm63xx_regs_enetdmac = bcm6348_regs_enetdmac; +} +#else +static __init void bcm63xx_enetdmac_regs_init(void) { } +#endif +  static struct resource shared_res[] = {  	{  		.start		= -1, /* filled at runtime */  		.end		= -1, /* filled at runtime */  		.flags		= IORESOURCE_MEM,  	}, +	{ +		.start		= -1, /* filled at runtime */ +		.end		= -1, /* filled at runtime */ +		.flags		= IORESOURCE_MEM, +	}, +	{ +		.start		= -1, /* filled at runtime */ +		.end		= -1, /* filled at runtime */ +		.flags		= IORESOURCE_MEM, +	},  };  static struct platform_device bcm63xx_enet_shared_device = { @@ -94,6 +138,71 @@ static struct platform_device bcm63xx_enet1_device = {  	},  }; +static struct resource enetsw_res[] = { +	{ +		/* start & end filled at runtime */ +		.flags		= IORESOURCE_MEM, +	}, +	{ +		/* start filled at runtime */ +		.flags		= IORESOURCE_IRQ, +	}, +	{ +		/* start filled at runtime */ +		.flags		= IORESOURCE_IRQ, +	}, +}; + +static struct bcm63xx_enetsw_platform_data enetsw_pd; + +static struct platform_device bcm63xx_enetsw_device = { +	.name		= "bcm63xx_enetsw", +	.num_resources	= ARRAY_SIZE(enetsw_res), +	.resource	= enetsw_res, +	.dev		= { +		.platform_data = &enetsw_pd, +	}, +}; + +static int __init register_shared(void) +{ +	int ret, chan_count; + +	if (shared_device_registered) +		return 0; + +	bcm63xx_enetdmac_regs_init(); + +	shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); +	shared_res[0].end = shared_res[0].start; +	if (BCMCPU_IS_6345()) +		shared_res[0].end += (RSET_6345_ENETDMA_SIZE) - 1; +	else +		shared_res[0].end += (RSET_ENETDMA_SIZE)  - 1; + +	if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) +		chan_count = 32; +	else if (BCMCPU_IS_6345()) +		chan_count = 8; +	else +		chan_count = 16; + +	shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC); +	shared_res[1].end = shared_res[1].start; +	shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count)  - 1; + +	shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS); +	shared_res[2].end = shared_res[2].start; +	shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count)  - 1; + +	ret = platform_device_register(&bcm63xx_enet_shared_device); +	if (ret) +		return ret; +	shared_device_registered = 1; + +	return 0; +} +  int __init bcm63xx_enet_register(int unit,  				 const struct bcm63xx_enet_platform_data *pd)  { @@ -104,22 +213,12 @@ int __init bcm63xx_enet_register(int unit,  	if (unit > 1)  		return -ENODEV; -	if (unit == 1 && BCMCPU_IS_6338()) +	if (unit == 1 && (BCMCPU_IS_6338() || BCMCPU_IS_6345()))  		return -ENODEV; -	if (!shared_device_registered) { -		shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); -		shared_res[0].end = shared_res[0].start; -		if (BCMCPU_IS_6338()) -			shared_res[0].end += (RSET_ENETDMA_SIZE / 2)  - 1; -		else -			shared_res[0].end += (RSET_ENETDMA_SIZE)  - 1; - -		ret = platform_device_register(&bcm63xx_enet_shared_device); -		if (ret) -			return ret; -		shared_device_registered = 1; -	} +	ret = register_shared(); +	if (ret) +		return ret;  	if (unit == 0) {  		enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0); @@ -155,8 +254,62 @@ int __init bcm63xx_enet_register(int unit,  		dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY);  	} +	dpd->dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK; +	dpd->dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK; +	if (BCMCPU_IS_6345()) { +		dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_CHAINING_MASK; +		dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_WRAP_EN_MASK; +		dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_FLOWC_EN_MASK; +		dpd->dma_chan_int_mask |= ENETDMA_IR_BUFDONE_MASK; +		dpd->dma_chan_int_mask |= ENETDMA_IR_NOTOWNER_MASK; +		dpd->dma_chan_width = ENETDMA_6345_CHAN_WIDTH; +		dpd->dma_desc_shift = ENETDMA_6345_DESC_SHIFT; +	} else { +		dpd->dma_has_sram = true; +		dpd->dma_chan_width = ENETDMA_CHAN_WIDTH; +	} +  	ret = platform_device_register(pdev);  	if (ret)  		return ret;  	return 0;  } + +int __init +bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd) +{ +	int ret; + +	if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368()) +		return -ENODEV; + +	ret = register_shared(); +	if (ret) +		return ret; + +	enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW); +	enetsw_res[0].end = enetsw_res[0].start; +	enetsw_res[0].end += RSET_ENETSW_SIZE - 1; +	enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0); +	enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0); +	if (!enetsw_res[2].start) +		enetsw_res[2].start = -1; + +	memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd)); + +	if (BCMCPU_IS_6328()) +		enetsw_pd.num_ports = ENETSW_PORTS_6328; +	else if (BCMCPU_IS_6362() || BCMCPU_IS_6368()) +		enetsw_pd.num_ports = ENETSW_PORTS_6368; + +	enetsw_pd.dma_has_sram = true; +	enetsw_pd.dma_chan_width = ENETDMA_CHAN_WIDTH; +	enetsw_pd.dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK; +	enetsw_pd.dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK; + +	ret = platform_device_register(&bcm63xx_enetsw_device); +	if (ret) +		return ret; + +	return 0; +} diff --git a/arch/mips/bcm63xx/dev-flash.c b/arch/mips/bcm63xx/dev-flash.c new file mode 100644 index 00000000000..172dd839717 --- /dev/null +++ b/arch/mips/bcm63xx/dev-flash.c @@ -0,0 +1,130 @@ +/* + * 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 <mbizon@freebox.fr> + * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com> + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> + +#include <bcm63xx_cpu.h> +#include <bcm63xx_dev_flash.h> +#include <bcm63xx_regs.h> +#include <bcm63xx_io.h> + +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, +	}, +}; + +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: +		/* no way to auto detect so assume parallel */ +		return BCM63XX_FLASH_TYPE_PARALLEL; +	case BCM3368_CPU_ID: +	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 BCM6362_CPU_ID: +		val = bcm_misc_readl(MISC_STRAPBUS_6362_REG); +		if (val & STRAPBUS_6362_BOOT_SEL_SERIAL) +			return BCM63XX_FLASH_TYPE_SERIAL; +		else +			return BCM63XX_FLASH_TYPE_NAND; +	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; + +	flash_type = bcm63xx_detect_flash_type(); + +	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; + +		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/bcm63xx/dev-hsspi.c b/arch/mips/bcm63xx/dev-hsspi.c new file mode 100644 index 00000000000..696abc48e3c --- /dev/null +++ b/arch/mips/bcm63xx/dev-hsspi.c @@ -0,0 +1,47 @@ +/* + * 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) 2012 Jonas Gorski <jonas.gorski@gmail.com> + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <bcm63xx_cpu.h> +#include <bcm63xx_dev_hsspi.h> +#include <bcm63xx_regs.h> + +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 platform_device bcm63xx_hsspi_device = { +	.name		= "bcm63xx-hsspi", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(spi_resources), +	.resource	= spi_resources, +}; + +int __init bcm63xx_hsspi_register(void) +{ +	if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362()) +		return -ENODEV; + +	spi_resources[0].start = bcm63xx_regset_address(RSET_HSSPI); +	spi_resources[0].end = spi_resources[0].start; +	spi_resources[0].end += RSET_HSSPI_SIZE - 1; +	spi_resources[1].start = bcm63xx_get_irq_number(IRQ_HSSPI); + +	return platform_device_register(&bcm63xx_hsspi_device); +} diff --git a/arch/mips/bcm63xx/dev-pcmcia.c b/arch/mips/bcm63xx/dev-pcmcia.c index de4d917fd54..a551bab5ecb 100644 --- a/arch/mips/bcm63xx/dev-pcmcia.c +++ b/arch/mips/bcm63xx/dev-pcmcia.c @@ -79,11 +79,11 @@ static int __init config_pcmcia_cs(unsigned int cs,  	return ret;  } -static const __initdata struct { +static const struct {  	unsigned int	cs;  	unsigned int	base;  	unsigned int	size; -} pcmcia_cs[3] = { +} pcmcia_cs[3] __initconst = {  	{  		.cs	= MPI_CS_PCMCIA_COMMON,  		.base	= BCM_PCMCIA_COMMON_BASE_PA, diff --git a/arch/mips/bcm63xx/dev-rng.c b/arch/mips/bcm63xx/dev-rng.c new file mode 100644 index 00000000000..d277b4dc6c6 --- /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 <florian@openwrt.org> + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <bcm63xx_cpu.h> + +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); diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c new file mode 100644 index 00000000000..d12daed749b --- /dev/null +++ b/arch/mips/bcm63xx/dev-spi.c @@ -0,0 +1,102 @@ +/* + * 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 <florian@openwrt.org> + * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com> + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/clk.h> + +#include <bcm63xx_cpu.h> +#include <bcm63xx_dev_spi.h> +#include <bcm63xx_regs.h> + +#ifdef BCMCPU_RUNTIME_DETECT +/* + * register offsets + */ +static const unsigned long bcm6348_regs_spi[] = { +	__GEN_SPI_REGS_TABLE(6348) +}; + +static const unsigned long bcm6358_regs_spi[] = { +	__GEN_SPI_REGS_TABLE(6358) +}; + +const unsigned long *bcm63xx_regs_spi; +EXPORT_SYMBOL(bcm63xx_regs_spi); + +static __init void bcm63xx_spi_regs_init(void) +{ +	if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) +		bcm63xx_regs_spi = bcm6348_regs_spi; +	if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || +		BCMCPU_IS_6362() || BCMCPU_IS_6368()) +		bcm63xx_regs_spi = bcm6358_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) +{ +	if (BCMCPU_IS_6328() || BCMCPU_IS_6345()) +		return -ENODEV; + +	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_6348_RSET_SPI_SIZE - 1; +		spi_pdata.fifo_size = SPI_6348_MSG_DATA_SIZE; +		spi_pdata.msg_type_shift = SPI_6348_MSG_TYPE_SHIFT; +		spi_pdata.msg_ctl_width = SPI_6348_MSG_CTL_WIDTH; +	} + +	if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6362() || +		BCMCPU_IS_6368()) { +		spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1; +		spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE; +		spi_pdata.msg_type_shift = SPI_6358_MSG_TYPE_SHIFT; +		spi_pdata.msg_ctl_width = SPI_6358_MSG_CTL_WIDTH; +	} + +	bcm63xx_spi_regs_init(); + +	return platform_device_register(&bcm63xx_spi_device); +} diff --git a/arch/mips/bcm63xx/dev-uart.c b/arch/mips/bcm63xx/dev-uart.c index c2963da0253..3bc7f3bfc9a 100644 --- a/arch/mips/bcm63xx/dev-uart.c +++ b/arch/mips/bcm63xx/dev-uart.c @@ -54,7 +54,8 @@ int __init bcm63xx_uart_register(unsigned int id)  	if (id >= ARRAY_SIZE(bcm63xx_uart_devices))  		return -ENODEV; -	if (id == 1 && !BCMCPU_IS_6358()) +	if (id == 1 && (!BCMCPU_IS_3368() && !BCMCPU_IS_6358() && +		!BCMCPU_IS_6368()))  		return -ENODEV;  	if (id == 0) { diff --git a/arch/mips/bcm63xx/dev-usb-usbd.c b/arch/mips/bcm63xx/dev-usb-usbd.c new file mode 100644 index 00000000000..508bd9d8df2 --- /dev/null +++ b/arch/mips/bcm63xx/dev-usb-usbd.c @@ -0,0 +1,65 @@ +/* + * 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 <mbizon@freebox.fr> + * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com> + * Copyright (C) 2012 Broadcom Corporation + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <bcm63xx_cpu.h> +#include <bcm63xx_dev_usb_usbd.h> + +#define NUM_MMIO		2 +#define NUM_IRQ			7 + +static struct resource usbd_resources[NUM_MMIO + NUM_IRQ]; + +static u64 usbd_dmamask = DMA_BIT_MASK(32); + +static struct platform_device bcm63xx_usbd_device = { +	.name		= "bcm63xx_udc", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(usbd_resources), +	.resource	= usbd_resources, +	.dev		= { +		.dma_mask		= &usbd_dmamask, +		.coherent_dma_mask	= DMA_BIT_MASK(32), +	}, +}; + +int __init bcm63xx_usbd_register(const struct bcm63xx_usbd_platform_data *pd) +{ +	const int irq_list[NUM_IRQ] = { IRQ_USBD, +		IRQ_USBD_RXDMA0, IRQ_USBD_TXDMA0, +		IRQ_USBD_RXDMA1, IRQ_USBD_TXDMA1, +		IRQ_USBD_RXDMA2, IRQ_USBD_TXDMA2 }; +	int i; + +	if (!BCMCPU_IS_6328() && !BCMCPU_IS_6368()) +		return 0; + +	usbd_resources[0].start = bcm63xx_regset_address(RSET_USBD); +	usbd_resources[0].end = usbd_resources[0].start + RSET_USBD_SIZE - 1; +	usbd_resources[0].flags = IORESOURCE_MEM; + +	usbd_resources[1].start = bcm63xx_regset_address(RSET_USBDMA); +	usbd_resources[1].end = usbd_resources[1].start + RSET_USBDMA_SIZE - 1; +	usbd_resources[1].flags = IORESOURCE_MEM; + +	for (i = 0; i < NUM_IRQ; i++) { +		struct resource *r = &usbd_resources[NUM_MMIO + i]; + +		r->start = r->end = bcm63xx_get_irq_number(irq_list[i]); +		r->flags = IORESOURCE_IRQ; +	} + +	platform_device_add_data(&bcm63xx_usbd_device, pd, sizeof(*pd)); + +	return platform_device_register(&bcm63xx_usbd_device); +} diff --git a/arch/mips/bcm63xx/dev-wdt.c b/arch/mips/bcm63xx/dev-wdt.c index 3e6c716a4c1..2a2346a99bc 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,  }; diff --git a/arch/mips/bcm63xx/early_printk.c b/arch/mips/bcm63xx/early_printk.c index bf353c937df..6092226a6d7 100644 --- a/arch/mips/bcm63xx/early_printk.c +++ b/arch/mips/bcm63xx/early_printk.c @@ -6,11 +6,10 @@   * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>   */ -#include <linux/init.h>  #include <bcm63xx_io.h> -#include <bcm63xx_regs.h> +#include <linux/serial_bcm63xx.h> -static void __init wait_xfered(void) +static void wait_xfered(void)  {  	unsigned int val; @@ -22,7 +21,7 @@ static void __init wait_xfered(void)  	} while (1);  } -void __init prom_putchar(char c) +void prom_putchar(char c)  {  	wait_xfered();  	bcm_uart0_writel(c, UART_FIFO_REG); diff --git a/arch/mips/bcm63xx/gpio.c b/arch/mips/bcm63xx/gpio.c index f560fe7d38d..a6c2135dbf3 100644 --- a/arch/mips/bcm63xx/gpio.c +++ b/arch/mips/bcm63xx/gpio.c @@ -4,7 +4,7 @@   * for more details.   *   * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> - * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>   */  #include <linux/kernel.h> @@ -18,6 +18,34 @@  #include <bcm63xx_io.h>  #include <bcm63xx_regs.h> +#ifndef BCMCPU_RUNTIME_DETECT +#define gpio_out_low_reg	GPIO_DATA_LO_REG +#ifdef CONFIG_BCM63XX_CPU_6345 +#ifdef gpio_out_low_reg +#undef gpio_out_low_reg +#define gpio_out_low_reg	GPIO_DATA_LO_REG_6345 +#endif /* gpio_out_low_reg */ +#endif /* CONFIG_BCM63XX_CPU_6345 */ + +static inline void bcm63xx_gpio_out_low_reg_init(void) +{ +} +#else /* ! BCMCPU_RUNTIME_DETECT */ +static u32 gpio_out_low_reg; + +static void bcm63xx_gpio_out_low_reg_init(void) +{ +	switch (bcm63xx_get_cpu_id()) { +	case BCM6345_CPU_ID: +		gpio_out_low_reg = GPIO_DATA_LO_REG_6345; +		break; +	default: +		gpio_out_low_reg = GPIO_DATA_LO_REG; +		break; +	} +} +#endif /* ! BCMCPU_RUNTIME_DETECT */ +  static DEFINE_SPINLOCK(bcm63xx_gpio_lock);  static u32 gpio_out_low, gpio_out_high; @@ -33,7 +61,7 @@ static void bcm63xx_gpio_set(struct gpio_chip *chip,  		BUG();  	if (gpio < 32) { -		reg = GPIO_DATA_LO_REG; +		reg = gpio_out_low_reg;  		mask = 1 << gpio;  		v = &gpio_out_low;  	} else { @@ -60,7 +88,7 @@ static int bcm63xx_gpio_get(struct gpio_chip *chip, unsigned gpio)  		BUG();  	if (gpio < 32) { -		reg = GPIO_DATA_LO_REG; +		reg = gpio_out_low_reg;  		mask = 1 << gpio;  	} else {  		reg = GPIO_DATA_HI_REG; @@ -125,8 +153,11 @@ static struct gpio_chip bcm63xx_gpio_chip = {  int __init bcm63xx_gpio_init(void)  { -	gpio_out_low = bcm_gpio_readl(GPIO_DATA_LO_REG); -	gpio_out_high = bcm_gpio_readl(GPIO_DATA_HI_REG); +	bcm63xx_gpio_out_low_reg_init(); + +	gpio_out_low = bcm_gpio_readl(gpio_out_low_reg); +	if (!BCMCPU_IS_6345()) +		gpio_out_high = bcm_gpio_readl(GPIO_DATA_HI_REG);  	bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count();  	pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio); diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 3be87f2422f..1525f8a3841 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -19,19 +19,251 @@  #include <bcm63xx_io.h>  #include <bcm63xx_irq.h> +static void __dispatch_internal(void) __maybe_unused; +static void __dispatch_internal_64(void) __maybe_unused; +static void __internal_irq_mask_32(unsigned int irq) __maybe_unused; +static void __internal_irq_mask_64(unsigned int irq) __maybe_unused; +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_3368 +#define irq_stat_reg		PERF_IRQSTAT_3368_REG +#define irq_mask_reg		PERF_IRQMASK_3368_REG +#define irq_bits		32 +#define is_ext_irq_cascaded	0 +#define ext_irq_start		0 +#define ext_irq_end		0 +#define ext_irq_count		4 +#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_3368 +#define ext_irq_cfg_reg2	0 +#endif +#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 +#define irq_bits		32 +#define is_ext_irq_cascaded	0 +#define ext_irq_start		0 +#define ext_irq_end		0 +#define ext_irq_count		4 +#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6338 +#define ext_irq_cfg_reg2	0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6345 +#define irq_stat_reg		PERF_IRQSTAT_6345_REG +#define irq_mask_reg		PERF_IRQMASK_6345_REG +#define irq_bits		32 +#define is_ext_irq_cascaded	0 +#define ext_irq_start		0 +#define ext_irq_end		0 +#define ext_irq_count		4 +#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6345 +#define ext_irq_cfg_reg2	0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6348 +#define irq_stat_reg		PERF_IRQSTAT_6348_REG +#define irq_mask_reg		PERF_IRQMASK_6348_REG +#define irq_bits		32 +#define is_ext_irq_cascaded	0 +#define ext_irq_start		0 +#define ext_irq_end		0 +#define ext_irq_count		4 +#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6348 +#define ext_irq_cfg_reg2	0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6358 +#define irq_stat_reg		PERF_IRQSTAT_6358_REG +#define irq_mask_reg		PERF_IRQMASK_6358_REG +#define irq_bits		32 +#define is_ext_irq_cascaded	1 +#define ext_irq_start		(BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE) +#define ext_irq_end		(BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE) +#define ext_irq_count		4 +#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6358 +#define ext_irq_cfg_reg2	0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6362 +#define irq_stat_reg		PERF_IRQSTAT_6362_REG +#define irq_mask_reg		PERF_IRQMASK_6362_REG +#define irq_bits		64 +#define is_ext_irq_cascaded	1 +#define ext_irq_start		(BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE) +#define ext_irq_end		(BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE) +#define ext_irq_count		4 +#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6362 +#define ext_irq_cfg_reg2	0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6368 +#define irq_stat_reg		PERF_IRQSTAT_6368_REG +#define irq_mask_reg		PERF_IRQMASK_6368_REG +#define irq_bits		64 +#define is_ext_irq_cascaded	1 +#define ext_irq_start		(BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE) +#define ext_irq_end		(BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE) +#define ext_irq_count		6 +#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6368 +#define ext_irq_cfg_reg2	PERF_EXTIRQ_CFG_REG2_6368 +#endif + +#if irq_bits == 32 +#define dispatch_internal			__dispatch_internal +#define internal_irq_mask			__internal_irq_mask_32 +#define internal_irq_unmask			__internal_irq_unmask_32 +#else +#define dispatch_internal			__dispatch_internal_64 +#define internal_irq_mask			__internal_irq_mask_64 +#define internal_irq_unmask			__internal_irq_unmask_64 +#endif + +#define irq_stat_addr	(bcm63xx_regset_address(RSET_PERF) + irq_stat_reg) +#define irq_mask_addr	(bcm63xx_regset_address(RSET_PERF) + irq_mask_reg) + +static inline void bcm63xx_init_irq(void) +{ +} +#else /* ! BCMCPU_RUNTIME_DETECT */ + +static u32 irq_stat_addr, irq_mask_addr; +static void (*dispatch_internal)(void); +static int is_ext_irq_cascaded; +static unsigned int ext_irq_count; +static unsigned int ext_irq_start, ext_irq_end; +static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; +static void (*internal_irq_mask)(unsigned int irq); +static void (*internal_irq_unmask)(unsigned int irq); + +static void bcm63xx_init_irq(void) +{ +	int irq_bits; + +	irq_stat_addr = bcm63xx_regset_address(RSET_PERF); +	irq_mask_addr = bcm63xx_regset_address(RSET_PERF); + +	switch (bcm63xx_get_cpu_id()) { +	case BCM3368_CPU_ID: +		irq_stat_addr += PERF_IRQSTAT_3368_REG; +		irq_mask_addr += PERF_IRQMASK_3368_REG; +		irq_bits = 32; +		ext_irq_count = 4; +		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368; +		break; +	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; +		irq_bits = 32; +		ext_irq_count = 4; +		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338; +		break; +	case BCM6345_CPU_ID: +		irq_stat_addr += PERF_IRQSTAT_6345_REG; +		irq_mask_addr += PERF_IRQMASK_6345_REG; +		irq_bits = 32; +		ext_irq_count = 4; +		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345; +		break; +	case BCM6348_CPU_ID: +		irq_stat_addr += PERF_IRQSTAT_6348_REG; +		irq_mask_addr += PERF_IRQMASK_6348_REG; +		irq_bits = 32; +		ext_irq_count = 4; +		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; +		break; +	case BCM6358_CPU_ID: +		irq_stat_addr += PERF_IRQSTAT_6358_REG; +		irq_mask_addr += PERF_IRQMASK_6358_REG; +		irq_bits = 32; +		ext_irq_count = 4; +		is_ext_irq_cascaded = 1; +		ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; +		ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; +		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; +		break; +	case BCM6362_CPU_ID: +		irq_stat_addr += PERF_IRQSTAT_6362_REG; +		irq_mask_addr += PERF_IRQMASK_6362_REG; +		irq_bits = 64; +		ext_irq_count = 4; +		is_ext_irq_cascaded = 1; +		ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE; +		ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE; +		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362; +		break; +	case BCM6368_CPU_ID: +		irq_stat_addr += PERF_IRQSTAT_6368_REG; +		irq_mask_addr += PERF_IRQMASK_6368_REG; +		irq_bits = 64; +		ext_irq_count = 6; +		is_ext_irq_cascaded = 1; +		ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE; +		ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE; +		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368; +		ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368; +		break; +	default: +		BUG(); +	} + +	if (irq_bits == 32) { +		dispatch_internal = __dispatch_internal; +		internal_irq_mask = __internal_irq_mask_32; +		internal_irq_unmask = __internal_irq_unmask_32; +	} else { +		dispatch_internal = __dispatch_internal_64; +		internal_irq_mask = __internal_irq_mask_64; +		internal_irq_unmask = __internal_irq_unmask_64; +	} +} +#endif /* ! BCMCPU_RUNTIME_DETECT */ + +static inline u32 get_ext_irq_perf_reg(int irq) +{ +	if (irq < 4) +		return ext_irq_cfg_reg1; +	return ext_irq_cfg_reg2; +} + +static inline void handle_internal(int intbit) +{ +	if (is_ext_irq_cascaded && +	    intbit >= ext_irq_start && intbit <= ext_irq_end) +		do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE); +	else +		do_IRQ(intbit + IRQ_INTERNAL_BASE); +} +  /*   * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not   * prioritize any interrupt relatively to another. the static counter   * will resume the loop where it ended the last time we left this   * function.   */ -static void bcm63xx_irq_dispatch_internal(void) +static void __dispatch_internal(void)  {  	u32 pending;  	static int i; -	pending = bcm_perf_readl(PERF_IRQMASK_REG) & -		bcm_perf_readl(PERF_IRQSTAT_REG); +	pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr);  	if (!pending)  		return ; @@ -41,7 +273,28 @@ static void bcm63xx_irq_dispatch_internal(void)  		i = (i + 1) & 0x1f;  		if (pending & (1 << to_call)) { -			do_IRQ(to_call + IRQ_INTERNAL_BASE); +			handle_internal(to_call); +			break; +		} +	} +} + +static void __dispatch_internal_64(void) +{ +	u64 pending; +	static int i; + +	pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr); + +	if (!pending) +		return ; + +	while (1) { +		int to_call = i; + +		i = (i + 1) & 0x3f; +		if (pending & (1ull << to_call)) { +			handle_internal(to_call);  			break;  		}  	} @@ -59,16 +312,22 @@ asmlinkage void plat_irq_dispatch(void)  		if (cause & CAUSEF_IP7)  			do_IRQ(7); +		if (cause & CAUSEF_IP0) +			do_IRQ(0); +		if (cause & CAUSEF_IP1) +			do_IRQ(1);  		if (cause & CAUSEF_IP2) -			bcm63xx_irq_dispatch_internal(); -		if (cause & CAUSEF_IP3) -			do_IRQ(IRQ_EXT_0); -		if (cause & CAUSEF_IP4) -			do_IRQ(IRQ_EXT_1); -		if (cause & CAUSEF_IP5) -			do_IRQ(IRQ_EXT_2); -		if (cause & CAUSEF_IP6) -			do_IRQ(IRQ_EXT_3); +			dispatch_internal(); +		if (!is_ext_irq_cascaded) { +			if (cause & CAUSEF_IP3) +				do_IRQ(IRQ_EXT_0); +			if (cause & CAUSEF_IP4) +				do_IRQ(IRQ_EXT_1); +			if (cause & CAUSEF_IP5) +				do_IRQ(IRQ_EXT_2); +			if (cause & CAUSEF_IP6) +				do_IRQ(IRQ_EXT_3); +		}  	} while (1);  } @@ -76,179 +335,249 @@ asmlinkage void plat_irq_dispatch(void)   * internal IRQs operations: only mask/unmask on PERF irq mask   * register.   */ -static inline void bcm63xx_internal_irq_mask(unsigned int irq) +static void __internal_irq_mask_32(unsigned int irq)  {  	u32 mask; -	irq -= IRQ_INTERNAL_BASE; -	mask = bcm_perf_readl(PERF_IRQMASK_REG); +	mask = bcm_readl(irq_mask_addr);  	mask &= ~(1 << irq); -	bcm_perf_writel(mask, PERF_IRQMASK_REG); +	bcm_writel(mask, irq_mask_addr); +} + +static void __internal_irq_mask_64(unsigned int irq) +{ +	u64 mask; + +	mask = bcm_readq(irq_mask_addr); +	mask &= ~(1ull << irq); +	bcm_writeq(mask, irq_mask_addr);  } -static void bcm63xx_internal_irq_unmask(unsigned int irq) +static void __internal_irq_unmask_32(unsigned int irq)  {  	u32 mask; -	irq -= IRQ_INTERNAL_BASE; -	mask = bcm_perf_readl(PERF_IRQMASK_REG); +	mask = bcm_readl(irq_mask_addr);  	mask |= (1 << irq); -	bcm_perf_writel(mask, PERF_IRQMASK_REG); +	bcm_writel(mask, irq_mask_addr); +} + +static void __internal_irq_unmask_64(unsigned int irq) +{ +	u64 mask; + +	mask = bcm_readq(irq_mask_addr); +	mask |= (1ull << irq); +	bcm_writeq(mask, irq_mask_addr);  } -static unsigned int bcm63xx_internal_irq_startup(unsigned int irq) +static void bcm63xx_internal_irq_mask(struct irq_data *d)  { -	bcm63xx_internal_irq_unmask(irq); -	return 0; +	internal_irq_mask(d->irq - IRQ_INTERNAL_BASE); +} + +static void bcm63xx_internal_irq_unmask(struct irq_data *d) +{ +	internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE);  }  /*   * external IRQs operations: mask/unmask and clear on PERF external   * irq control register.   */ -static void bcm63xx_external_irq_mask(unsigned int irq) +static void bcm63xx_external_irq_mask(struct irq_data *d)  { -	u32 reg; +	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; +	u32 reg, regaddr; -	irq -= IRQ_EXT_BASE; -	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); -	reg &= ~EXTIRQ_CFG_MASK(irq); -	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); -} +	regaddr = get_ext_irq_perf_reg(irq); +	reg = bcm_perf_readl(regaddr); -static void bcm63xx_external_irq_unmask(unsigned int irq) -{ -	u32 reg; +	if (BCMCPU_IS_6348()) +		reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4); +	else +		reg &= ~EXTIRQ_CFG_MASK(irq % 4); -	irq -= IRQ_EXT_BASE; -	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); -	reg |= EXTIRQ_CFG_MASK(irq); -	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); +	bcm_perf_writel(reg, regaddr); +	if (is_ext_irq_cascaded) +		internal_irq_mask(irq + ext_irq_start);  } -static void bcm63xx_external_irq_clear(unsigned int irq) +static void bcm63xx_external_irq_unmask(struct irq_data *d)  { -	u32 reg; +	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; +	u32 reg, regaddr; -	irq -= IRQ_EXT_BASE; -	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); -	reg |= EXTIRQ_CFG_CLEAR(irq); -	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); -} +	regaddr = get_ext_irq_perf_reg(irq); +	reg = bcm_perf_readl(regaddr); -static unsigned int bcm63xx_external_irq_startup(unsigned int irq) -{ -	set_c0_status(0x100 << (irq - IRQ_MIPS_BASE)); -	irq_enable_hazard(); -	bcm63xx_external_irq_unmask(irq); -	return 0; +	if (BCMCPU_IS_6348()) +		reg |= EXTIRQ_CFG_MASK_6348(irq % 4); +	else +		reg |= EXTIRQ_CFG_MASK(irq % 4); + +	bcm_perf_writel(reg, regaddr); + +	if (is_ext_irq_cascaded) +		internal_irq_unmask(irq + ext_irq_start);  } -static void bcm63xx_external_irq_shutdown(unsigned int irq) +static void bcm63xx_external_irq_clear(struct irq_data *d)  { -	bcm63xx_external_irq_mask(irq); -	clear_c0_status(0x100 << (irq - IRQ_MIPS_BASE)); -	irq_disable_hazard(); +	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; +	u32 reg, regaddr; + +	regaddr = get_ext_irq_perf_reg(irq); +	reg = bcm_perf_readl(regaddr); + +	if (BCMCPU_IS_6348()) +		reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4); +	else +		reg |= EXTIRQ_CFG_CLEAR(irq % 4); + +	bcm_perf_writel(reg, regaddr);  } -static int bcm63xx_external_irq_set_type(unsigned int irq, +static int bcm63xx_external_irq_set_type(struct irq_data *d,  					 unsigned int flow_type)  { -	u32 reg; -	struct irq_desc *desc = irq_desc + irq; - -	irq -= IRQ_EXT_BASE; +	unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; +	u32 reg, regaddr; +	int levelsense, sense, bothedge;  	flow_type &= IRQ_TYPE_SENSE_MASK;  	if (flow_type == IRQ_TYPE_NONE)  		flow_type = IRQ_TYPE_LEVEL_LOW; -	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); +	levelsense = sense = bothedge = 0;  	switch (flow_type) {  	case IRQ_TYPE_EDGE_BOTH: -		reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); -		reg |= EXTIRQ_CFG_BOTHEDGE(irq); +		bothedge = 1;  		break;  	case IRQ_TYPE_EDGE_RISING: -		reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); -		reg |= EXTIRQ_CFG_SENSE(irq); -		reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); +		sense = 1;  		break;  	case IRQ_TYPE_EDGE_FALLING: -		reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); -		reg &= ~EXTIRQ_CFG_SENSE(irq); -		reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);  		break;  	case IRQ_TYPE_LEVEL_HIGH: -		reg |= EXTIRQ_CFG_LEVELSENSE(irq); -		reg |= EXTIRQ_CFG_SENSE(irq); +		levelsense = 1; +		sense = 1;  		break;  	case IRQ_TYPE_LEVEL_LOW: -		reg |= EXTIRQ_CFG_LEVELSENSE(irq); -		reg &= ~EXTIRQ_CFG_SENSE(irq); +		levelsense = 1;  		break;  	default:  		printk(KERN_ERR "bogus flow type combination given !\n");  		return -EINVAL;  	} -	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); -	if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))  { -		desc->status |= IRQ_LEVEL; -		desc->handle_irq = handle_level_irq; -	} else { -		desc->handle_irq = handle_edge_irq; +	regaddr = get_ext_irq_perf_reg(irq); +	reg = bcm_perf_readl(regaddr); +	irq %= 4; + +	switch (bcm63xx_get_cpu_id()) { +	case BCM6348_CPU_ID: +		if (levelsense) +			reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq); +		else +			reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq); +		if (sense) +			reg |= EXTIRQ_CFG_SENSE_6348(irq); +		else +			reg &= ~EXTIRQ_CFG_SENSE_6348(irq); +		if (bothedge) +			reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq); +		else +			reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq); +		break; + +	case BCM3368_CPU_ID: +	case BCM6328_CPU_ID: +	case BCM6338_CPU_ID: +	case BCM6345_CPU_ID: +	case BCM6358_CPU_ID: +	case BCM6362_CPU_ID: +	case BCM6368_CPU_ID: +		if (levelsense) +			reg |= EXTIRQ_CFG_LEVELSENSE(irq); +		else +			reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); +		if (sense) +			reg |= EXTIRQ_CFG_SENSE(irq); +		else +			reg &= ~EXTIRQ_CFG_SENSE(irq); +		if (bothedge) +			reg |= EXTIRQ_CFG_BOTHEDGE(irq); +		else +			reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); +		break; +	default: +		BUG();  	} -	return 0; +	bcm_perf_writel(reg, regaddr); + +	irqd_set_trigger_type(d, flow_type); +	if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) +		__irq_set_handler_locked(d->irq, handle_level_irq); +	else +		__irq_set_handler_locked(d->irq, handle_edge_irq); + +	return IRQ_SET_MASK_OK_NOCOPY;  }  static struct irq_chip bcm63xx_internal_irq_chip = {  	.name		= "bcm63xx_ipic", -	.startup	= bcm63xx_internal_irq_startup, -	.shutdown	= bcm63xx_internal_irq_mask, - -	.mask		= bcm63xx_internal_irq_mask, -	.mask_ack	= bcm63xx_internal_irq_mask, -	.unmask		= bcm63xx_internal_irq_unmask, +	.irq_mask	= bcm63xx_internal_irq_mask, +	.irq_unmask	= bcm63xx_internal_irq_unmask,  };  static struct irq_chip bcm63xx_external_irq_chip = {  	.name		= "bcm63xx_epic", -	.startup	= bcm63xx_external_irq_startup, -	.shutdown	= bcm63xx_external_irq_shutdown, +	.irq_ack	= bcm63xx_external_irq_clear, -	.ack		= bcm63xx_external_irq_clear, +	.irq_mask	= bcm63xx_external_irq_mask, +	.irq_unmask	= bcm63xx_external_irq_unmask, -	.mask		= bcm63xx_external_irq_mask, -	.unmask		= bcm63xx_external_irq_unmask, - -	.set_type	= bcm63xx_external_irq_set_type, +	.irq_set_type	= bcm63xx_external_irq_set_type,  };  static struct irqaction cpu_ip2_cascade_action = {  	.handler	= no_action,  	.name		= "cascade_ip2", +	.flags		= IRQF_NO_THREAD, +}; + +static struct irqaction cpu_ext_cascade_action = { +	.handler	= no_action, +	.name		= "cascade_extirq", +	.flags		= IRQF_NO_THREAD,  };  void __init arch_init_irq(void)  {  	int i; +	bcm63xx_init_irq();  	mips_cpu_irq_init();  	for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i) -		set_irq_chip_and_handler(i, &bcm63xx_internal_irq_chip, +		irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,  					 handle_level_irq); -	for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i) -		set_irq_chip_and_handler(i, &bcm63xx_external_irq_chip, +	for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i) +		irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,  					 handle_edge_irq); -	setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action); +	if (!is_ext_irq_cascaded) { +		for (i = 3; i < 3 + ext_irq_count; ++i) +			setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action); +	} + +	setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action);  } diff --git a/arch/mips/bcm63xx/nvram.c b/arch/mips/bcm63xx/nvram.c new file mode 100644 index 00000000000..4b50d40f745 --- /dev/null +++ b/arch/mips/bcm63xx/nvram.c @@ -0,0 +1,127 @@ +/* + * 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 <mbizon@freebox.fr> + * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com> + */ + +#define pr_fmt(fmt) "bcm63xx_nvram: " fmt + +#include <linux/init.h> +#include <linux/crc32.h> +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/if_ether.h> + +#include <bcm63xx_nvram.h> + +/* + * nvram structure + */ +struct bcm963xx_nvram { +	u32	version; +	u8	reserved1[256]; +	u8	name[16]; +	u32	main_tp_number; +	u32	psi_size; +	u32	mac_addr_count; +	u8	mac_addr_base[ETH_ALEN]; +	u8	reserved2[2]; +	u32	checksum_old; +	u8	reserved3[720]; +	u32	checksum_high; +}; + +#define BCM63XX_DEFAULT_PSI_SIZE	64 + +static struct bcm963xx_nvram nvram; +static int mac_addr_used; + +void __init bcm63xx_nvram_init(void *addr) +{ +	unsigned int check_len; +	u32 crc, expected_crc; +	u8 hcs_mac_addr[ETH_ALEN] = { 0x00, 0x10, 0x18, 0xff, 0xff, 0xff }; + +	/* extract nvram data */ +	memcpy(&nvram, addr, sizeof(nvram)); + +	/* check checksum before using data */ +	if (nvram.version <= 4) { +		check_len = offsetof(struct bcm963xx_nvram, reserved3); +		expected_crc = nvram.checksum_old; +		nvram.checksum_old = 0; +	} else { +		check_len = sizeof(nvram); +		expected_crc = nvram.checksum_high; +		nvram.checksum_high = 0; +	} + +	crc = crc32_le(~0, (u8 *)&nvram, check_len); + +	if (crc != expected_crc) +		pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n", +			expected_crc, crc); + +	/* Cable modems have a different NVRAM which is embedded in the eCos +	 * firmware and not easily extractible, give at least a MAC address +	 * pool. +	 */ +	if (BCMCPU_IS_3368()) { +		memcpy(nvram.mac_addr_base, hcs_mac_addr, ETH_ALEN); +		nvram.mac_addr_count = 2; +	} +} + +u8 *bcm63xx_nvram_get_name(void) +{ +	return nvram.name; +} +EXPORT_SYMBOL(bcm63xx_nvram_get_name); + +int bcm63xx_nvram_get_mac_address(u8 *mac) +{ +	u8 *oui; +	int count; + +	if (mac_addr_used >= nvram.mac_addr_count) { +		pr_err("not enough mac addresses\n"); +		return -ENODEV; +	} + +	memcpy(mac, nvram.mac_addr_base, ETH_ALEN); +	oui = mac + ETH_ALEN/2 - 1; +	count = mac_addr_used; + +	while (count--) { +		u8 *p = mac + ETH_ALEN - 1; + +		do { +			(*p)++; +			if (*p != 0) +				break; +			p--; +		} while (p != oui); + +		if (p == oui) { +			pr_err("unable to fetch mac address\n"); +			return -ENODEV; +		} +	} + +	mac_addr_used++; +	return 0; +} +EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address); + +int bcm63xx_nvram_get_psi_size(void) +{ +	if (nvram.psi_size > 0) +		return nvram.psi_size; + +	return BCM63XX_DEFAULT_PSI_SIZE; +} +EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size); diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c index be252efa075..e1f27d653f6 100644 --- a/arch/mips/bcm63xx/prom.c +++ b/arch/mips/bcm63xx/prom.c @@ -8,7 +8,11 @@  #include <linux/init.h>  #include <linux/bootmem.h> +#include <linux/smp.h>  #include <asm/bootinfo.h> +#include <asm/bmips.h> +#include <asm/smp-ops.h> +#include <asm/mipsregs.h>  #include <bcm63xx_board.h>  #include <bcm63xx_cpu.h>  #include <bcm63xx_io.h> @@ -26,15 +30,24 @@ 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_3368()) +		mask = CKCTL_3368_ALL_SAFE_EN; +	else 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;  	else if (BCMCPU_IS_6348())  		mask = CKCTL_6348_ALL_SAFE_EN; -	else -		/* BCMCPU_IS_6358() */ +	else if (BCMCPU_IS_6358())  		mask = CKCTL_6358_ALL_SAFE_EN; +	else if (BCMCPU_IS_6362()) +		mask = CKCTL_6362_ALL_SAFE_EN; +	else if (BCMCPU_IS_6368()) +		mask = CKCTL_6368_ALL_SAFE_EN; +	else +		mask = 0;  	reg = bcm_perf_readl(PERF_CKCTL_REG);  	reg &= ~mask; @@ -45,6 +58,45 @@ void __init prom_init(void)  	/* do low level board init */  	board_prom_init(); + +	/* set up SMP */ +	if (!register_bmips_smp_ops()) { +		/* +		 * BCM6328 might not have its second CPU enabled, while BCM3368 +		 * and BCM6358 need special handling for their shared TLB, so +		 * disable SMP for now. +		 */ +		if (BCMCPU_IS_6328()) { +			reg = bcm_readl(BCM_6328_OTP_BASE + +					OTP_USER_BITS_6328_REG(3)); + +			if (reg & OTP_6328_REG3_TP1_DISABLED) +				bmips_smp_enabled = 0; +		} else if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) { +			bmips_smp_enabled = 0; +		} + +		if (!bmips_smp_enabled) +			return; + +		/* +		 * The bootloader has set up the CPU1 reset vector at +		 * 0xa000_0200. +		 * This conflicts with the special interrupt vector (IV). +		 * The bootloader has also set up CPU1 to respond to the wrong +		 * IPI interrupt. +		 * Here we will start up CPU1 in the background and ask it to +		 * reconfigure itself then go back to sleep. +		 */ +		memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20); +		__sync(); +		set_c0_cause(C_SW0); +		cpumask_set_cpu(1, &bmips_booted_mask); + +		/* +		 * FIXME: we really should have some sort of hazard barrier here +		 */ +	}  }  void __init prom_free_prom_memory(void) diff --git a/arch/mips/bcm63xx/reset.c b/arch/mips/bcm63xx/reset.c new file mode 100644 index 00000000000..acbeb1fe7c5 --- /dev/null +++ b/arch/mips/bcm63xx/reset.c @@ -0,0 +1,278 @@ +/* + * 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) 2012 Jonas Gorski <jonas.gorski@gmail.com> + */ + +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <bcm63xx_cpu.h> +#include <bcm63xx_io.h> +#include <bcm63xx_regs.h> +#include <bcm63xx_reset.h> + +#define __GEN_RESET_BITS_TABLE(__cpu)					\ +	[BCM63XX_RESET_SPI]		= BCM## __cpu ##_RESET_SPI,	\ +	[BCM63XX_RESET_ENET]		= BCM## __cpu ##_RESET_ENET,	\ +	[BCM63XX_RESET_USBH]		= BCM## __cpu ##_RESET_USBH,	\ +	[BCM63XX_RESET_USBD]		= BCM## __cpu ##_RESET_USBD,	\ +	[BCM63XX_RESET_DSL]		= BCM## __cpu ##_RESET_DSL,	\ +	[BCM63XX_RESET_SAR]		= BCM## __cpu ##_RESET_SAR,	\ +	[BCM63XX_RESET_EPHY]		= BCM## __cpu ##_RESET_EPHY,	\ +	[BCM63XX_RESET_ENETSW]		= BCM## __cpu ##_RESET_ENETSW,	\ +	[BCM63XX_RESET_PCM]		= BCM## __cpu ##_RESET_PCM,	\ +	[BCM63XX_RESET_MPI]		= BCM## __cpu ##_RESET_MPI,	\ +	[BCM63XX_RESET_PCIE]		= BCM## __cpu ##_RESET_PCIE,	\ +	[BCM63XX_RESET_PCIE_EXT]	= BCM## __cpu ##_RESET_PCIE_EXT, + +#define BCM3368_RESET_SPI	SOFTRESET_3368_SPI_MASK +#define BCM3368_RESET_ENET	SOFTRESET_3368_ENET_MASK +#define BCM3368_RESET_USBH	0 +#define BCM3368_RESET_USBD	SOFTRESET_3368_USBS_MASK +#define BCM3368_RESET_DSL	0 +#define BCM3368_RESET_SAR	0 +#define BCM3368_RESET_EPHY	SOFTRESET_3368_EPHY_MASK +#define BCM3368_RESET_ENETSW	0 +#define BCM3368_RESET_PCM	SOFTRESET_3368_PCM_MASK +#define BCM3368_RESET_MPI	SOFTRESET_3368_MPI_MASK +#define BCM3368_RESET_PCIE	0 +#define BCM3368_RESET_PCIE_EXT	0 + +#define BCM6328_RESET_SPI	SOFTRESET_6328_SPI_MASK +#define BCM6328_RESET_ENET	0 +#define BCM6328_RESET_USBH	SOFTRESET_6328_USBH_MASK +#define BCM6328_RESET_USBD	SOFTRESET_6328_USBS_MASK +#define BCM6328_RESET_DSL	0 +#define BCM6328_RESET_SAR	SOFTRESET_6328_SAR_MASK +#define BCM6328_RESET_EPHY	SOFTRESET_6328_EPHY_MASK +#define BCM6328_RESET_ENETSW	SOFTRESET_6328_ENETSW_MASK +#define BCM6328_RESET_PCM	SOFTRESET_6328_PCM_MASK +#define BCM6328_RESET_MPI	0 +#define BCM6328_RESET_PCIE	\ +				(SOFTRESET_6328_PCIE_MASK |		\ +				 SOFTRESET_6328_PCIE_CORE_MASK |	\ +				 SOFTRESET_6328_PCIE_HARD_MASK) +#define BCM6328_RESET_PCIE_EXT	SOFTRESET_6328_PCIE_EXT_MASK + +#define BCM6338_RESET_SPI	SOFTRESET_6338_SPI_MASK +#define BCM6338_RESET_ENET	SOFTRESET_6338_ENET_MASK +#define BCM6338_RESET_USBH	SOFTRESET_6338_USBH_MASK +#define BCM6338_RESET_USBD	SOFTRESET_6338_USBS_MASK +#define BCM6338_RESET_DSL	SOFTRESET_6338_ADSL_MASK +#define BCM6338_RESET_SAR	SOFTRESET_6338_SAR_MASK +#define BCM6338_RESET_EPHY	0 +#define BCM6338_RESET_ENETSW	0 +#define BCM6338_RESET_PCM	0 +#define BCM6338_RESET_MPI	0 +#define BCM6338_RESET_PCIE	0 +#define BCM6338_RESET_PCIE_EXT	0 + +#define BCM6348_RESET_SPI	SOFTRESET_6348_SPI_MASK +#define BCM6348_RESET_ENET	SOFTRESET_6348_ENET_MASK +#define BCM6348_RESET_USBH	SOFTRESET_6348_USBH_MASK +#define BCM6348_RESET_USBD	SOFTRESET_6348_USBS_MASK +#define BCM6348_RESET_DSL	SOFTRESET_6348_ADSL_MASK +#define BCM6348_RESET_SAR	SOFTRESET_6348_SAR_MASK +#define BCM6348_RESET_EPHY	0 +#define BCM6348_RESET_ENETSW	0 +#define BCM6348_RESET_PCM	0 +#define BCM6348_RESET_MPI	0 +#define BCM6348_RESET_PCIE	0 +#define BCM6348_RESET_PCIE_EXT	0 + +#define BCM6358_RESET_SPI	SOFTRESET_6358_SPI_MASK +#define BCM6358_RESET_ENET	SOFTRESET_6358_ENET_MASK +#define BCM6358_RESET_USBH	SOFTRESET_6358_USBH_MASK +#define BCM6358_RESET_USBD	0 +#define BCM6358_RESET_DSL	SOFTRESET_6358_ADSL_MASK +#define BCM6358_RESET_SAR	SOFTRESET_6358_SAR_MASK +#define BCM6358_RESET_EPHY	SOFTRESET_6358_EPHY_MASK +#define BCM6358_RESET_ENETSW	0 +#define BCM6358_RESET_PCM	SOFTRESET_6358_PCM_MASK +#define BCM6358_RESET_MPI	SOFTRESET_6358_MPI_MASK +#define BCM6358_RESET_PCIE	0 +#define BCM6358_RESET_PCIE_EXT	0 + +#define BCM6362_RESET_SPI	SOFTRESET_6362_SPI_MASK +#define BCM6362_RESET_ENET	0 +#define BCM6362_RESET_USBH	SOFTRESET_6362_USBH_MASK +#define BCM6362_RESET_USBD	SOFTRESET_6362_USBS_MASK +#define BCM6362_RESET_DSL	0 +#define BCM6362_RESET_SAR	SOFTRESET_6362_SAR_MASK +#define BCM6362_RESET_EPHY	SOFTRESET_6362_EPHY_MASK +#define BCM6362_RESET_ENETSW	SOFTRESET_6362_ENETSW_MASK +#define BCM6362_RESET_PCM	SOFTRESET_6362_PCM_MASK +#define BCM6362_RESET_MPI	0 +#define BCM6362_RESET_PCIE      (SOFTRESET_6362_PCIE_MASK | \ +				 SOFTRESET_6362_PCIE_CORE_MASK) +#define BCM6362_RESET_PCIE_EXT	SOFTRESET_6362_PCIE_EXT_MASK + +#define BCM6368_RESET_SPI	SOFTRESET_6368_SPI_MASK +#define BCM6368_RESET_ENET	0 +#define BCM6368_RESET_USBH	SOFTRESET_6368_USBH_MASK +#define BCM6368_RESET_USBD	SOFTRESET_6368_USBS_MASK +#define BCM6368_RESET_DSL	0 +#define BCM6368_RESET_SAR	SOFTRESET_6368_SAR_MASK +#define BCM6368_RESET_EPHY	SOFTRESET_6368_EPHY_MASK +#define BCM6368_RESET_ENETSW	0 +#define BCM6368_RESET_PCM	SOFTRESET_6368_PCM_MASK +#define BCM6368_RESET_MPI	SOFTRESET_6368_MPI_MASK +#define BCM6368_RESET_PCIE	0 +#define BCM6368_RESET_PCIE_EXT	0 + +#ifdef BCMCPU_RUNTIME_DETECT + +/* + * core reset bits + */ +static const u32 bcm3368_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(3368) +}; + +static const u32 bcm6328_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6328) +}; + +static const u32 bcm6338_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6338) +}; + +static const u32 bcm6348_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6348) +}; + +static const u32 bcm6358_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6358) +}; + +static const u32 bcm6362_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6362) +}; + +static const u32 bcm6368_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6368) +}; + +const u32 *bcm63xx_reset_bits; +static int reset_reg; + +static int __init bcm63xx_reset_bits_init(void) +{ +	if (BCMCPU_IS_3368()) { +		reset_reg = PERF_SOFTRESET_6358_REG; +		bcm63xx_reset_bits = bcm3368_reset_bits; +	} else if (BCMCPU_IS_6328()) { +		reset_reg = PERF_SOFTRESET_6328_REG; +		bcm63xx_reset_bits = bcm6328_reset_bits; +	} else if (BCMCPU_IS_6338()) { +		reset_reg = PERF_SOFTRESET_REG; +		bcm63xx_reset_bits = bcm6338_reset_bits; +	} else if (BCMCPU_IS_6348()) { +		reset_reg = PERF_SOFTRESET_REG; +		bcm63xx_reset_bits = bcm6348_reset_bits; +	} else if (BCMCPU_IS_6358()) { +		reset_reg = PERF_SOFTRESET_6358_REG; +		bcm63xx_reset_bits = bcm6358_reset_bits; +	} else if (BCMCPU_IS_6362()) { +		reset_reg = PERF_SOFTRESET_6362_REG; +		bcm63xx_reset_bits = bcm6362_reset_bits; +	} else if (BCMCPU_IS_6368()) { +		reset_reg = PERF_SOFTRESET_6368_REG; +		bcm63xx_reset_bits = bcm6368_reset_bits; +	} + +	return 0; +} +#else + +#ifdef CONFIG_BCM63XX_CPU_3368 +static const u32 bcm63xx_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(3368) +}; +#define reset_reg PERF_SOFTRESET_6358_REG +#endif + +#ifdef CONFIG_BCM63XX_CPU_6328 +static const u32 bcm63xx_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6328) +}; +#define reset_reg PERF_SOFTRESET_6328_REG +#endif + +#ifdef CONFIG_BCM63XX_CPU_6338 +static const u32 bcm63xx_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6338) +}; +#define reset_reg PERF_SOFTRESET_REG +#endif + +#ifdef CONFIG_BCM63XX_CPU_6345 +static const u32 bcm63xx_reset_bits[] = { }; +#define reset_reg 0 +#endif + +#ifdef CONFIG_BCM63XX_CPU_6348 +static const u32 bcm63xx_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6348) +}; +#define reset_reg PERF_SOFTRESET_REG +#endif + +#ifdef CONFIG_BCM63XX_CPU_6358 +static const u32 bcm63xx_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6358) +}; +#define reset_reg PERF_SOFTRESET_6358_REG +#endif + +#ifdef CONFIG_BCM63XX_CPU_6362 +static const u32 bcm63xx_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6362) +}; +#define reset_reg PERF_SOFTRESET_6362_REG +#endif + +#ifdef CONFIG_BCM63XX_CPU_6368 +static const u32 bcm63xx_reset_bits[] = { +	__GEN_RESET_BITS_TABLE(6368) +}; +#define reset_reg PERF_SOFTRESET_6368_REG +#endif + +static int __init bcm63xx_reset_bits_init(void) { return 0; } +#endif + +static DEFINE_SPINLOCK(reset_mutex); + +static void __bcm63xx_core_set_reset(u32 mask, int enable) +{ +	unsigned long flags; +	u32 val; + +	if (!mask) +		return; + +	spin_lock_irqsave(&reset_mutex, flags); +	val = bcm_perf_readl(reset_reg); + +	if (enable) +		val &= ~mask; +	else +		val |= mask; + +	bcm_perf_writel(val, reset_reg); +	spin_unlock_irqrestore(&reset_mutex, flags); +} + +void bcm63xx_core_set_reset(enum bcm63xx_core_reset core, int reset) +{ +	__bcm63xx_core_set_reset(bcm63xx_reset_bits[core], reset); +} +EXPORT_SYMBOL(bcm63xx_core_set_reset); + +postcore_initcall(bcm63xx_reset_bits_init); diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index d0056598fbf..6660c7ddf87 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -33,7 +33,7 @@ static void bcm6348_a1_reboot(void)  	u32 reg;  	/* soft reset all blocks */ -	printk(KERN_INFO "soft-reseting all blocks ...\n"); +	printk(KERN_INFO "soft-resetting all blocks ...\n");  	reg = bcm_perf_readl(PERF_SOFTRESET_REG);  	reg &= ~SOFTRESET_6348_ALL;  	bcm_perf_writel(reg, PERF_SOFTRESET_REG); @@ -63,21 +63,60 @@ static void bcm6348_a1_reboot(void)  void bcm63xx_machine_reboot(void)  { -	u32 reg; +	u32 reg, perf_regs[2] = { 0, 0 }; +	unsigned int i;  	/* mask and clear all external irq */ -	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); -	reg &= ~EXTIRQ_CFG_MASK_ALL; -	reg |= EXTIRQ_CFG_CLEAR_ALL; -	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); +	switch (bcm63xx_get_cpu_id()) { +	case BCM3368_CPU_ID: +		perf_regs[0] = PERF_EXTIRQ_CFG_REG_3368; +		break; +	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; +	case BCM6345_CPU_ID: +		perf_regs[0] = PERF_EXTIRQ_CFG_REG_6345; +		break; +	case BCM6348_CPU_ID: +		perf_regs[0] = PERF_EXTIRQ_CFG_REG_6348; +		break; +	case BCM6358_CPU_ID: +		perf_regs[0] = PERF_EXTIRQ_CFG_REG_6358; +		break; +	case BCM6362_CPU_ID: +		perf_regs[0] = PERF_EXTIRQ_CFG_REG_6362; +		break; +	} + +	for (i = 0; i < 2; i++) { +		if (!perf_regs[i]) +			break; + +		reg = bcm_perf_readl(perf_regs[i]); +		if (BCMCPU_IS_6348()) { +			reg &= ~EXTIRQ_CFG_MASK_ALL_6348; +			reg |= EXTIRQ_CFG_CLEAR_ALL_6348; +		} else { +			reg &= ~EXTIRQ_CFG_MASK_ALL; +			reg |= EXTIRQ_CFG_CLEAR_ALL; +		} +		bcm_perf_writel(reg, perf_regs[i]); +	}  	if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1))  		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)  		;  } @@ -93,7 +132,7 @@ static void __bcm63xx_machine_reboot(char *p)  const char *get_system_type(void)  {  	static char buf[128]; -	snprintf(buf, sizeof(buf), "bcm63xx/%s (0x%04x/0x%04X)", +	snprintf(buf, sizeof(buf), "bcm63xx/%s (0x%04x/0x%02X)",  		 board_get_name(),  		 bcm63xx_get_cpu_id(), bcm63xx_get_cpu_rev());  	return buf;  | 
