1 /* 2 * Sonics Silicon Backplane SoC host related functions. 3 * Subsystem core 4 * 5 * Copyright 2005, Broadcom Corporation 6 * Copyright 2006, 2007, Michael Buesch <m@bues.ch> 7 * 8 * Licensed under the GNU/GPL. See COPYING for details. 9 */ 10 11 #include "ssb_private.h" 12 13 #include <linux/bcm47xx_nvram.h> 14 #include <linux/ssb/ssb.h> 15 16 static u8 ssb_host_soc_read8(struct ssb_device *dev, u16 offset) 17 { 18 struct ssb_bus *bus = dev->bus; 19 20 offset += dev->core_index * SSB_CORE_SIZE; 21 return readb(bus->mmio + offset); 22 } 23 24 static u16 ssb_host_soc_read16(struct ssb_device *dev, u16 offset) 25 { 26 struct ssb_bus *bus = dev->bus; 27 28 offset += dev->core_index * SSB_CORE_SIZE; 29 return readw(bus->mmio + offset); 30 } 31 32 static u32 ssb_host_soc_read32(struct ssb_device *dev, u16 offset) 33 { 34 struct ssb_bus *bus = dev->bus; 35 36 offset += dev->core_index * SSB_CORE_SIZE; 37 return readl(bus->mmio + offset); 38 } 39 40 #ifdef CONFIG_SSB_BLOCKIO 41 static void ssb_host_soc_block_read(struct ssb_device *dev, void *buffer, 42 size_t count, u16 offset, u8 reg_width) 43 { 44 struct ssb_bus *bus = dev->bus; 45 void __iomem *addr; 46 47 offset += dev->core_index * SSB_CORE_SIZE; 48 addr = bus->mmio + offset; 49 50 switch (reg_width) { 51 case sizeof(u8): { 52 u8 *buf = buffer; 53 54 while (count) { 55 *buf = __raw_readb(addr); 56 buf++; 57 count--; 58 } 59 break; 60 } 61 case sizeof(u16): { 62 __le16 *buf = buffer; 63 64 WARN_ON(count & 1); 65 while (count) { 66 *buf = (__force __le16)__raw_readw(addr); 67 buf++; 68 count -= 2; 69 } 70 break; 71 } 72 case sizeof(u32): { 73 __le32 *buf = buffer; 74 75 WARN_ON(count & 3); 76 while (count) { 77 *buf = (__force __le32)__raw_readl(addr); 78 buf++; 79 count -= 4; 80 } 81 break; 82 } 83 default: 84 WARN_ON(1); 85 } 86 } 87 #endif /* CONFIG_SSB_BLOCKIO */ 88 89 static void ssb_host_soc_write8(struct ssb_device *dev, u16 offset, u8 value) 90 { 91 struct ssb_bus *bus = dev->bus; 92 93 offset += dev->core_index * SSB_CORE_SIZE; 94 writeb(value, bus->mmio + offset); 95 } 96 97 static void ssb_host_soc_write16(struct ssb_device *dev, u16 offset, u16 value) 98 { 99 struct ssb_bus *bus = dev->bus; 100 101 offset += dev->core_index * SSB_CORE_SIZE; 102 writew(value, bus->mmio + offset); 103 } 104 105 static void ssb_host_soc_write32(struct ssb_device *dev, u16 offset, u32 value) 106 { 107 struct ssb_bus *bus = dev->bus; 108 109 offset += dev->core_index * SSB_CORE_SIZE; 110 writel(value, bus->mmio + offset); 111 } 112 113 #ifdef CONFIG_SSB_BLOCKIO 114 static void ssb_host_soc_block_write(struct ssb_device *dev, const void *buffer, 115 size_t count, u16 offset, u8 reg_width) 116 { 117 struct ssb_bus *bus = dev->bus; 118 void __iomem *addr; 119 120 offset += dev->core_index * SSB_CORE_SIZE; 121 addr = bus->mmio + offset; 122 123 switch (reg_width) { 124 case sizeof(u8): { 125 const u8 *buf = buffer; 126 127 while (count) { 128 __raw_writeb(*buf, addr); 129 buf++; 130 count--; 131 } 132 break; 133 } 134 case sizeof(u16): { 135 const __le16 *buf = buffer; 136 137 WARN_ON(count & 1); 138 while (count) { 139 __raw_writew((__force u16)(*buf), addr); 140 buf++; 141 count -= 2; 142 } 143 break; 144 } 145 case sizeof(u32): { 146 const __le32 *buf = buffer; 147 148 WARN_ON(count & 3); 149 while (count) { 150 __raw_writel((__force u32)(*buf), addr); 151 buf++; 152 count -= 4; 153 } 154 break; 155 } 156 default: 157 WARN_ON(1); 158 } 159 } 160 #endif /* CONFIG_SSB_BLOCKIO */ 161 162 /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ 163 const struct ssb_bus_ops ssb_host_soc_ops = { 164 .read8 = ssb_host_soc_read8, 165 .read16 = ssb_host_soc_read16, 166 .read32 = ssb_host_soc_read32, 167 .write8 = ssb_host_soc_write8, 168 .write16 = ssb_host_soc_write16, 169 .write32 = ssb_host_soc_write32, 170 #ifdef CONFIG_SSB_BLOCKIO 171 .block_read = ssb_host_soc_block_read, 172 .block_write = ssb_host_soc_block_write, 173 #endif 174 }; 175 176 int ssb_host_soc_get_invariants(struct ssb_bus *bus, 177 struct ssb_init_invariants *iv) 178 { 179 char buf[20]; 180 int len, err; 181 182 /* Fill boardinfo structure */ 183 memset(&iv->boardinfo, 0, sizeof(struct ssb_boardinfo)); 184 185 len = bcm47xx_nvram_getenv("boardvendor", buf, sizeof(buf)); 186 if (len > 0) { 187 err = kstrtou16(strim(buf), 0, &iv->boardinfo.vendor); 188 if (err) 189 pr_warn("Couldn't parse nvram board vendor entry with value \"%s\"\n", 190 buf); 191 } 192 if (!iv->boardinfo.vendor) 193 iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; 194 195 len = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf)); 196 if (len > 0) { 197 err = kstrtou16(strim(buf), 0, &iv->boardinfo.type); 198 if (err) 199 pr_warn("Couldn't parse nvram board type entry with value \"%s\"\n", 200 buf); 201 } 202 203 memset(&iv->sprom, 0, sizeof(struct ssb_sprom)); 204 ssb_fill_sprom_with_fallback(bus, &iv->sprom); 205 206 if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) 207 iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); 208 209 return 0; 210 } 211