211 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Sonics Silicon Backplane SoC host related functions.
 | |
|  * Subsystem core
 | |
|  *
 | |
|  * Copyright 2005, Broadcom Corporation
 | |
|  * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 | |
|  *
 | |
|  * Licensed under the GNU/GPL. See COPYING for details.
 | |
|  */
 | |
| 
 | |
| #include "ssb_private.h"
 | |
| 
 | |
| #include <linux/bcm47xx_nvram.h>
 | |
| #include <linux/ssb/ssb.h>
 | |
| 
 | |
| static u8 ssb_host_soc_read8(struct ssb_device *dev, u16 offset)
 | |
| {
 | |
| 	struct ssb_bus *bus = dev->bus;
 | |
| 
 | |
| 	offset += dev->core_index * SSB_CORE_SIZE;
 | |
| 	return readb(bus->mmio + offset);
 | |
| }
 | |
| 
 | |
| static u16 ssb_host_soc_read16(struct ssb_device *dev, u16 offset)
 | |
| {
 | |
| 	struct ssb_bus *bus = dev->bus;
 | |
| 
 | |
| 	offset += dev->core_index * SSB_CORE_SIZE;
 | |
| 	return readw(bus->mmio + offset);
 | |
| }
 | |
| 
 | |
| static u32 ssb_host_soc_read32(struct ssb_device *dev, u16 offset)
 | |
| {
 | |
| 	struct ssb_bus *bus = dev->bus;
 | |
| 
 | |
| 	offset += dev->core_index * SSB_CORE_SIZE;
 | |
| 	return readl(bus->mmio + offset);
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_SSB_BLOCKIO
 | |
| static void ssb_host_soc_block_read(struct ssb_device *dev, void *buffer,
 | |
| 				    size_t count, u16 offset, u8 reg_width)
 | |
| {
 | |
| 	struct ssb_bus *bus = dev->bus;
 | |
| 	void __iomem *addr;
 | |
| 
 | |
| 	offset += dev->core_index * SSB_CORE_SIZE;
 | |
| 	addr = bus->mmio + offset;
 | |
| 
 | |
| 	switch (reg_width) {
 | |
| 	case sizeof(u8): {
 | |
| 		u8 *buf = buffer;
 | |
| 
 | |
| 		while (count) {
 | |
| 			*buf = __raw_readb(addr);
 | |
| 			buf++;
 | |
| 			count--;
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 	case sizeof(u16): {
 | |
| 		__le16 *buf = buffer;
 | |
| 
 | |
| 		WARN_ON(count & 1);
 | |
| 		while (count) {
 | |
| 			*buf = (__force __le16)__raw_readw(addr);
 | |
| 			buf++;
 | |
| 			count -= 2;
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 	case sizeof(u32): {
 | |
| 		__le32 *buf = buffer;
 | |
| 
 | |
| 		WARN_ON(count & 3);
 | |
| 		while (count) {
 | |
| 			*buf = (__force __le32)__raw_readl(addr);
 | |
| 			buf++;
 | |
| 			count -= 4;
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 	default:
 | |
| 		WARN_ON(1);
 | |
| 	}
 | |
| }
 | |
| #endif /* CONFIG_SSB_BLOCKIO */
 | |
| 
 | |
| static void ssb_host_soc_write8(struct ssb_device *dev, u16 offset, u8 value)
 | |
| {
 | |
| 	struct ssb_bus *bus = dev->bus;
 | |
| 
 | |
| 	offset += dev->core_index * SSB_CORE_SIZE;
 | |
| 	writeb(value, bus->mmio + offset);
 | |
| }
 | |
| 
 | |
| static void ssb_host_soc_write16(struct ssb_device *dev, u16 offset, u16 value)
 | |
| {
 | |
| 	struct ssb_bus *bus = dev->bus;
 | |
| 
 | |
| 	offset += dev->core_index * SSB_CORE_SIZE;
 | |
| 	writew(value, bus->mmio + offset);
 | |
| }
 | |
| 
 | |
| static void ssb_host_soc_write32(struct ssb_device *dev, u16 offset, u32 value)
 | |
| {
 | |
| 	struct ssb_bus *bus = dev->bus;
 | |
| 
 | |
| 	offset += dev->core_index * SSB_CORE_SIZE;
 | |
| 	writel(value, bus->mmio + offset);
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_SSB_BLOCKIO
 | |
| static void ssb_host_soc_block_write(struct ssb_device *dev, const void *buffer,
 | |
| 				     size_t count, u16 offset, u8 reg_width)
 | |
| {
 | |
| 	struct ssb_bus *bus = dev->bus;
 | |
| 	void __iomem *addr;
 | |
| 
 | |
| 	offset += dev->core_index * SSB_CORE_SIZE;
 | |
| 	addr = bus->mmio + offset;
 | |
| 
 | |
| 	switch (reg_width) {
 | |
| 	case sizeof(u8): {
 | |
| 		const u8 *buf = buffer;
 | |
| 
 | |
| 		while (count) {
 | |
| 			__raw_writeb(*buf, addr);
 | |
| 			buf++;
 | |
| 			count--;
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 	case sizeof(u16): {
 | |
| 		const __le16 *buf = buffer;
 | |
| 
 | |
| 		WARN_ON(count & 1);
 | |
| 		while (count) {
 | |
| 			__raw_writew((__force u16)(*buf), addr);
 | |
| 			buf++;
 | |
| 			count -= 2;
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 	case sizeof(u32): {
 | |
| 		const __le32 *buf = buffer;
 | |
| 
 | |
| 		WARN_ON(count & 3);
 | |
| 		while (count) {
 | |
| 			__raw_writel((__force u32)(*buf), addr);
 | |
| 			buf++;
 | |
| 			count -= 4;
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 	default:
 | |
| 		WARN_ON(1);
 | |
| 	}
 | |
| }
 | |
| #endif /* CONFIG_SSB_BLOCKIO */
 | |
| 
 | |
| /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
 | |
| const struct ssb_bus_ops ssb_host_soc_ops = {
 | |
| 	.read8		= ssb_host_soc_read8,
 | |
| 	.read16		= ssb_host_soc_read16,
 | |
| 	.read32		= ssb_host_soc_read32,
 | |
| 	.write8		= ssb_host_soc_write8,
 | |
| 	.write16	= ssb_host_soc_write16,
 | |
| 	.write32	= ssb_host_soc_write32,
 | |
| #ifdef CONFIG_SSB_BLOCKIO
 | |
| 	.block_read	= ssb_host_soc_block_read,
 | |
| 	.block_write	= ssb_host_soc_block_write,
 | |
| #endif
 | |
| };
 | |
| 
 | |
| int ssb_host_soc_get_invariants(struct ssb_bus *bus,
 | |
| 				struct ssb_init_invariants *iv)
 | |
| {
 | |
| 	char buf[20];
 | |
| 	int len, err;
 | |
| 
 | |
| 	/* Fill boardinfo structure */
 | |
| 	memset(&iv->boardinfo, 0, sizeof(struct ssb_boardinfo));
 | |
| 
 | |
| 	len = bcm47xx_nvram_getenv("boardvendor", buf, sizeof(buf));
 | |
| 	if (len > 0) {
 | |
| 		err = kstrtou16(strim(buf), 0, &iv->boardinfo.vendor);
 | |
| 		if (err)
 | |
| 			pr_warn("Couldn't parse nvram board vendor entry with value \"%s\"\n",
 | |
| 				buf);
 | |
| 	}
 | |
| 	if (!iv->boardinfo.vendor)
 | |
| 		iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
 | |
| 
 | |
| 	len = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
 | |
| 	if (len > 0) {
 | |
| 		err = kstrtou16(strim(buf), 0, &iv->boardinfo.type);
 | |
| 		if (err)
 | |
| 			pr_warn("Couldn't parse nvram board type entry with value \"%s\"\n",
 | |
| 				buf);
 | |
| 	}
 | |
| 
 | |
| 	memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
 | |
| 	ssb_fill_sprom_with_fallback(bus, &iv->sprom);
 | |
| 
 | |
| 	if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
 | |
| 		iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
 | |
| 
 | |
| 	return 0;
 | |
| }
 |