|  | /* | 
|  | * 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; | 
|  | } |