Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ST SPEAr: PCIE gadget suppport

This is a configurable gadget. can be configured by configfs interface.
Any IP available at PCIE bus can be programmed to be used by host
controller.It supoorts both INTX and MSI.

By default, the gadget is configured for INTX and SYSRAM1 is mapped to
BAR0 with size 0x1000

Signed-off-by: Pratyush Anand <pratyush.anand@st.com>
Cc: Randy Dunlap <randy.dunlap@oracle.com>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Viresh Kumar <viresh.kumar@st.com>
Cc: Shiraz Hashim <shiraz.hashim@st.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Pratyush Anand and committed by
Linus Torvalds
b9500546 45bff2ea

+1080
+31
Documentation/ABI/testing/configfs-spear-pcie-gadget
··· 1 + What: /config/pcie-gadget 2 + Date: Feb 2011 3 + KernelVersion: 2.6.37 4 + Contact: Pratyush Anand <pratyush.anand@st.com> 5 + Description: 6 + 7 + Interface is used to configure selected dual mode PCIe controller 8 + as device and then program its various registers to configure it 9 + as a particular device type. 10 + This interfaces can be used to show spear's PCIe device capability. 11 + 12 + Nodes are only visible when configfs is mounted. To mount configfs 13 + in /config directory use: 14 + # mount -t configfs none /config/ 15 + 16 + For nth PCIe Device Controller 17 + /config/pcie-gadget.n/ 18 + link ... used to enable ltssm and read its status. 19 + int_type ...used to configure and read type of supported 20 + interrupt 21 + no_of_msi ... used to configure number of MSI vector needed and 22 + to read no of MSI granted. 23 + inta ... write 1 to assert INTA and 0 to de-assert. 24 + send_msi ... write MSI vector to be sent. 25 + vendor_id ... used to write and read vendor id (hex) 26 + device_id ... used to write and read device id (hex) 27 + bar0_size ... used to write and read bar0_size 28 + bar0_address ... used to write and read bar0 mapped area in hex. 29 + bar0_rw_offset ... used to write and read offset of bar0 where 30 + bar0_data will be written or read. 31 + bar0_data ... used to write and read data at bar0_rw_offset.
+130
Documentation/misc-devices/spear-pcie-gadget.txt
··· 1 + Spear PCIe Gadget Driver: 2 + 3 + Author 4 + ============= 5 + Pratyush Anand (pratyush.anand@st.com) 6 + 7 + Location 8 + ============ 9 + driver/misc/spear13xx_pcie_gadget.c 10 + 11 + Supported Chip: 12 + =================== 13 + SPEAr1300 14 + SPEAr1310 15 + 16 + Menuconfig option: 17 + ========================== 18 + Device Drivers 19 + Misc devices 20 + PCIe gadget support for SPEAr13XX platform 21 + purpose 22 + =========== 23 + This driver has several nodes which can be read/written by configfs interface. 24 + Its main purpose is to configure selected dual mode PCIe controller as device 25 + and then program its various registers to configure it as a particular device 26 + type. This driver can be used to show spear's PCIe device capability. 27 + 28 + Description of different nodes: 29 + ================================= 30 + 31 + read behavior of nodes: 32 + ------------------------------ 33 + link :gives ltssm status. 34 + int_type :type of supported interrupt 35 + no_of_msi :zero if MSI is not enabled by host. A positive value is the 36 + number of MSI vector granted. 37 + vendor_id :returns programmed vendor id (hex) 38 + device_id :returns programmed device id(hex) 39 + bar0_size: :returns size of bar0 in hex. 40 + bar0_address :returns address of bar0 mapped area in hex. 41 + bar0_rw_offset :returns offset of bar0 for which bar0_data will return value. 42 + bar0_data :returns data at bar0_rw_offset. 43 + 44 + write behavior of nodes: 45 + ------------------------------ 46 + link :write UP to enable ltsmm DOWN to disable 47 + int_type :write interrupt type to be configured and (int_type could be 48 + INTA, MSI or NO_INT). Select MSI only when you have programmed 49 + no_of_msi node. 50 + no_of_msi :number of MSI vector needed. 51 + inta :write 1 to assert INTA and 0 to de-assert. 52 + send_msi :write MSI vector to be sent. 53 + vendor_id :write vendor id(hex) to be programmed. 54 + device_id :write device id(hex) to be programmed. 55 + bar0_size :write size of bar0 in hex. default bar0 size is 1000 (hex) 56 + bytes. 57 + bar0_address :write address of bar0 mapped area in hex. (default mapping of 58 + bar0 is SYSRAM1(E0800000). Always program bar size before bar 59 + address. Kernel might modify bar size and address for alignment, so 60 + read back bar size and address after writing to cross check. 61 + bar0_rw_offset :write offset of bar0 for which bar0_data will write value. 62 + bar0_data :write data to be written at bar0_rw_offset. 63 + 64 + Node programming example 65 + =========================== 66 + Program all PCIe registers in such a way that when this device is connected 67 + to the PCIe host, then host sees this device as 1MB RAM. 68 + #mount -t configfs none /Config 69 + For nth PCIe Device Controller 70 + # cd /config/pcie_gadget.n/ 71 + Now you have all the nodes in this directory. 72 + program vendor id as 0x104a 73 + # echo 104A >> vendor_id 74 + 75 + program device id as 0xCD80 76 + # echo CD80 >> device_id 77 + 78 + program BAR0 size as 1MB 79 + # echo 100000 >> bar0_size 80 + 81 + check for programmed bar0 size 82 + # cat bar0_size 83 + 84 + Program BAR0 Address as DDR (0x2100000). This is the physical address of 85 + memory, which is to be made visible to PCIe host. Similarly any other peripheral 86 + can also be made visible to PCIe host. E.g., if you program base address of UART 87 + as BAR0 address then when this device will be connected to a host, it will be 88 + visible as UART. 89 + # echo 2100000 >> bar0_address 90 + 91 + program interrupt type : INTA 92 + # echo INTA >> int_type 93 + 94 + go for link up now. 95 + # echo UP >> link 96 + 97 + It will have to be insured that, once link up is done on gadget, then only host 98 + is initialized and start to search PCIe devices on its port. 99 + 100 + /*wait till link is up*/ 101 + # cat link 102 + wait till it returns UP. 103 + 104 + To assert INTA 105 + # echo 1 >> inta 106 + 107 + To de-assert INTA 108 + # echo 0 >> inta 109 + 110 + if MSI is to be used as interrupt, program no of msi vector needed (say4) 111 + # echo 4 >> no_of_msi 112 + 113 + select MSI as interrupt type 114 + # echo MSI >> int_type 115 + 116 + go for link up now 117 + # echo UP >> link 118 + 119 + wait till link is up 120 + # cat link 121 + An application can repetitively read this node till link is found UP. It can 122 + sleep between two read. 123 + 124 + wait till msi is enabled 125 + # cat no_of_msi 126 + Should return 4 (number of requested MSI vector) 127 + 128 + to send msi vector 2 129 + # echo 2 >> send_msi 130 + #cd -
+10
drivers/misc/Kconfig
··· 402 402 This driver can also be built as a module. If so, the module 403 403 will be called ds1682. 404 404 405 + config SPEAR13XX_PCIE_GADGET 406 + bool "PCIe gadget support for SPEAr13XX platform" 407 + depends on ARCH_SPEAR13XX 408 + default n 409 + help 410 + This option enables gadget support for PCIe controller. If 411 + board file defines any controller as PCIe endpoint then a sysfs 412 + entry will be created for that controller. User can use these 413 + sysfs node to configure PCIe EP as per his requirements. 414 + 405 415 config TI_DAC7512 406 416 tristate "Texas Instruments DAC7512" 407 417 depends on SPI && SYSFS
+1
drivers/misc/Makefile
··· 37 37 obj-$(CONFIG_HMC6352) += hmc6352.o 38 38 obj-y += eeprom/ 39 39 obj-y += cb710/ 40 + obj-$(CONFIG_SPEAR13XX_PCIE_GADGET) += spear13xx_pcie_gadget.o 40 41 obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o 41 42 obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o 42 43 obj-$(CONFIG_PCH_PHUB) += pch_phub.o
+908
drivers/misc/spear13xx_pcie_gadget.c
··· 1 + /* 2 + * drivers/misc/spear13xx_pcie_gadget.c 3 + * 4 + * Copyright (C) 2010 ST Microelectronics 5 + * Pratyush Anand<pratyush.anand@st.com> 6 + * 7 + * This file is licensed under the terms of the GNU General Public 8 + * License version 2. This program is licensed "as is" without any 9 + * warranty of any kind, whether express or implied. 10 + */ 11 + 12 + #include <linux/clk.h> 13 + #include <linux/slab.h> 14 + #include <linux/delay.h> 15 + #include <linux/io.h> 16 + #include <linux/interrupt.h> 17 + #include <linux/irq.h> 18 + #include <linux/kernel.h> 19 + #include <linux/module.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/pci_regs.h> 22 + #include <linux/configfs.h> 23 + #include <mach/pcie.h> 24 + #include <mach/misc_regs.h> 25 + 26 + #define IN0_MEM_SIZE (200 * 1024 * 1024 - 1) 27 + /* In current implementation address translation is done using IN0 only. 28 + * So IN1 start address and IN0 end address has been kept same 29 + */ 30 + #define IN1_MEM_SIZE (0 * 1024 * 1024 - 1) 31 + #define IN_IO_SIZE (20 * 1024 * 1024 - 1) 32 + #define IN_CFG0_SIZE (12 * 1024 * 1024 - 1) 33 + #define IN_CFG1_SIZE (12 * 1024 * 1024 - 1) 34 + #define IN_MSG_SIZE (12 * 1024 * 1024 - 1) 35 + /* Keep default BAR size as 4K*/ 36 + /* AORAM would be mapped by default*/ 37 + #define INBOUND_ADDR_MASK (SPEAR13XX_SYSRAM1_SIZE - 1) 38 + 39 + #define INT_TYPE_NO_INT 0 40 + #define INT_TYPE_INTX 1 41 + #define INT_TYPE_MSI 2 42 + struct spear_pcie_gadget_config { 43 + void __iomem *base; 44 + void __iomem *va_app_base; 45 + void __iomem *va_dbi_base; 46 + char int_type[10]; 47 + ulong requested_msi; 48 + ulong configured_msi; 49 + ulong bar0_size; 50 + ulong bar0_rw_offset; 51 + void __iomem *va_bar0_address; 52 + }; 53 + 54 + struct pcie_gadget_target { 55 + struct configfs_subsystem subsys; 56 + struct spear_pcie_gadget_config config; 57 + }; 58 + 59 + struct pcie_gadget_target_attr { 60 + struct configfs_attribute attr; 61 + ssize_t (*show)(struct spear_pcie_gadget_config *config, 62 + char *buf); 63 + ssize_t (*store)(struct spear_pcie_gadget_config *config, 64 + const char *buf, 65 + size_t count); 66 + }; 67 + 68 + static void enable_dbi_access(struct pcie_app_reg __iomem *app_reg) 69 + { 70 + /* Enable DBI access */ 71 + writel(readl(&app_reg->slv_armisc) | (1 << AXI_OP_DBI_ACCESS_ID), 72 + &app_reg->slv_armisc); 73 + writel(readl(&app_reg->slv_awmisc) | (1 << AXI_OP_DBI_ACCESS_ID), 74 + &app_reg->slv_awmisc); 75 + 76 + } 77 + 78 + static void disable_dbi_access(struct pcie_app_reg __iomem *app_reg) 79 + { 80 + /* disable DBI access */ 81 + writel(readl(&app_reg->slv_armisc) & ~(1 << AXI_OP_DBI_ACCESS_ID), 82 + &app_reg->slv_armisc); 83 + writel(readl(&app_reg->slv_awmisc) & ~(1 << AXI_OP_DBI_ACCESS_ID), 84 + &app_reg->slv_awmisc); 85 + 86 + } 87 + 88 + static void spear_dbi_read_reg(struct spear_pcie_gadget_config *config, 89 + int where, int size, u32 *val) 90 + { 91 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 92 + ulong va_address; 93 + 94 + /* Enable DBI access */ 95 + enable_dbi_access(app_reg); 96 + 97 + va_address = (ulong)config->va_dbi_base + (where & ~0x3); 98 + 99 + *val = readl(va_address); 100 + 101 + if (size == 1) 102 + *val = (*val >> (8 * (where & 3))) & 0xff; 103 + else if (size == 2) 104 + *val = (*val >> (8 * (where & 3))) & 0xffff; 105 + 106 + /* Disable DBI access */ 107 + disable_dbi_access(app_reg); 108 + } 109 + 110 + static void spear_dbi_write_reg(struct spear_pcie_gadget_config *config, 111 + int where, int size, u32 val) 112 + { 113 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 114 + ulong va_address; 115 + 116 + /* Enable DBI access */ 117 + enable_dbi_access(app_reg); 118 + 119 + va_address = (ulong)config->va_dbi_base + (where & ~0x3); 120 + 121 + if (size == 4) 122 + writel(val, va_address); 123 + else if (size == 2) 124 + writew(val, va_address + (where & 2)); 125 + else if (size == 1) 126 + writeb(val, va_address + (where & 3)); 127 + 128 + /* Disable DBI access */ 129 + disable_dbi_access(app_reg); 130 + } 131 + 132 + #define PCI_FIND_CAP_TTL 48 133 + 134 + static int pci_find_own_next_cap_ttl(struct spear_pcie_gadget_config *config, 135 + u32 pos, int cap, int *ttl) 136 + { 137 + u32 id; 138 + 139 + while ((*ttl)--) { 140 + spear_dbi_read_reg(config, pos, 1, &pos); 141 + if (pos < 0x40) 142 + break; 143 + pos &= ~3; 144 + spear_dbi_read_reg(config, pos + PCI_CAP_LIST_ID, 1, &id); 145 + if (id == 0xff) 146 + break; 147 + if (id == cap) 148 + return pos; 149 + pos += PCI_CAP_LIST_NEXT; 150 + } 151 + return 0; 152 + } 153 + 154 + static int pci_find_own_next_cap(struct spear_pcie_gadget_config *config, 155 + u32 pos, int cap) 156 + { 157 + int ttl = PCI_FIND_CAP_TTL; 158 + 159 + return pci_find_own_next_cap_ttl(config, pos, cap, &ttl); 160 + } 161 + 162 + static int pci_find_own_cap_start(struct spear_pcie_gadget_config *config, 163 + u8 hdr_type) 164 + { 165 + u32 status; 166 + 167 + spear_dbi_read_reg(config, PCI_STATUS, 2, &status); 168 + if (!(status & PCI_STATUS_CAP_LIST)) 169 + return 0; 170 + 171 + switch (hdr_type) { 172 + case PCI_HEADER_TYPE_NORMAL: 173 + case PCI_HEADER_TYPE_BRIDGE: 174 + return PCI_CAPABILITY_LIST; 175 + case PCI_HEADER_TYPE_CARDBUS: 176 + return PCI_CB_CAPABILITY_LIST; 177 + default: 178 + return 0; 179 + } 180 + 181 + return 0; 182 + } 183 + 184 + /* 185 + * Tell if a device supports a given PCI capability. 186 + * Returns the address of the requested capability structure within the 187 + * device's PCI configuration space or 0 in case the device does not 188 + * support it. Possible values for @cap: 189 + * 190 + * %PCI_CAP_ID_PM Power Management 191 + * %PCI_CAP_ID_AGP Accelerated Graphics Port 192 + * %PCI_CAP_ID_VPD Vital Product Data 193 + * %PCI_CAP_ID_SLOTID Slot Identification 194 + * %PCI_CAP_ID_MSI Message Signalled Interrupts 195 + * %PCI_CAP_ID_CHSWP CompactPCI HotSwap 196 + * %PCI_CAP_ID_PCIX PCI-X 197 + * %PCI_CAP_ID_EXP PCI Express 198 + */ 199 + static int pci_find_own_capability(struct spear_pcie_gadget_config *config, 200 + int cap) 201 + { 202 + u32 pos; 203 + u32 hdr_type; 204 + 205 + spear_dbi_read_reg(config, PCI_HEADER_TYPE, 1, &hdr_type); 206 + 207 + pos = pci_find_own_cap_start(config, hdr_type); 208 + if (pos) 209 + pos = pci_find_own_next_cap(config, pos, cap); 210 + 211 + return pos; 212 + } 213 + 214 + static irqreturn_t spear_pcie_gadget_irq(int irq, void *dev_id) 215 + { 216 + return 0; 217 + } 218 + 219 + /* 220 + * configfs interfaces show/store functions 221 + */ 222 + static ssize_t pcie_gadget_show_link( 223 + struct spear_pcie_gadget_config *config, 224 + char *buf) 225 + { 226 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 227 + 228 + if (readl(&app_reg->app_status_1) & ((u32)1 << XMLH_LINK_UP_ID)) 229 + return sprintf(buf, "UP"); 230 + else 231 + return sprintf(buf, "DOWN"); 232 + } 233 + 234 + static ssize_t pcie_gadget_store_link( 235 + struct spear_pcie_gadget_config *config, 236 + const char *buf, size_t count) 237 + { 238 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 239 + 240 + if (sysfs_streq(buf, "UP")) 241 + writel(readl(&app_reg->app_ctrl_0) | (1 << APP_LTSSM_ENABLE_ID), 242 + &app_reg->app_ctrl_0); 243 + else if (sysfs_streq(buf, "DOWN")) 244 + writel(readl(&app_reg->app_ctrl_0) 245 + & ~(1 << APP_LTSSM_ENABLE_ID), 246 + &app_reg->app_ctrl_0); 247 + else 248 + return -EINVAL; 249 + return count; 250 + } 251 + 252 + static ssize_t pcie_gadget_show_int_type( 253 + struct spear_pcie_gadget_config *config, 254 + char *buf) 255 + { 256 + return sprintf(buf, "%s", config->int_type); 257 + } 258 + 259 + static ssize_t pcie_gadget_store_int_type( 260 + struct spear_pcie_gadget_config *config, 261 + const char *buf, size_t count) 262 + { 263 + u32 cap, vec, flags; 264 + ulong vector; 265 + 266 + if (sysfs_streq(buf, "INTA")) 267 + spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); 268 + 269 + else if (sysfs_streq(buf, "MSI")) { 270 + vector = config->requested_msi; 271 + vec = 0; 272 + while (vector > 1) { 273 + vector /= 2; 274 + vec++; 275 + } 276 + spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 0); 277 + cap = pci_find_own_capability(config, PCI_CAP_ID_MSI); 278 + spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags); 279 + flags &= ~PCI_MSI_FLAGS_QMASK; 280 + flags |= vec << 1; 281 + spear_dbi_write_reg(config, cap + PCI_MSI_FLAGS, 1, flags); 282 + } else 283 + return -EINVAL; 284 + 285 + strcpy(config->int_type, buf); 286 + 287 + return count; 288 + } 289 + 290 + static ssize_t pcie_gadget_show_no_of_msi( 291 + struct spear_pcie_gadget_config *config, 292 + char *buf) 293 + { 294 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 295 + u32 cap, vec, flags; 296 + ulong vector; 297 + 298 + if ((readl(&app_reg->msg_status) & (1 << CFG_MSI_EN_ID)) 299 + != (1 << CFG_MSI_EN_ID)) 300 + vector = 0; 301 + else { 302 + cap = pci_find_own_capability(config, PCI_CAP_ID_MSI); 303 + spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags); 304 + flags &= ~PCI_MSI_FLAGS_QSIZE; 305 + vec = flags >> 4; 306 + vector = 1; 307 + while (vec--) 308 + vector *= 2; 309 + } 310 + config->configured_msi = vector; 311 + 312 + return sprintf(buf, "%lu", vector); 313 + } 314 + 315 + static ssize_t pcie_gadget_store_no_of_msi( 316 + struct spear_pcie_gadget_config *config, 317 + const char *buf, size_t count) 318 + { 319 + if (strict_strtoul(buf, 0, &config->requested_msi)) 320 + return -EINVAL; 321 + if (config->requested_msi > 32) 322 + config->requested_msi = 32; 323 + 324 + return count; 325 + } 326 + 327 + static ssize_t pcie_gadget_store_inta( 328 + struct spear_pcie_gadget_config *config, 329 + const char *buf, size_t count) 330 + { 331 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 332 + ulong en; 333 + 334 + if (strict_strtoul(buf, 0, &en)) 335 + return -EINVAL; 336 + 337 + if (en) 338 + writel(readl(&app_reg->app_ctrl_0) | (1 << SYS_INT_ID), 339 + &app_reg->app_ctrl_0); 340 + else 341 + writel(readl(&app_reg->app_ctrl_0) & ~(1 << SYS_INT_ID), 342 + &app_reg->app_ctrl_0); 343 + 344 + return count; 345 + } 346 + 347 + static ssize_t pcie_gadget_store_send_msi( 348 + struct spear_pcie_gadget_config *config, 349 + const char *buf, size_t count) 350 + { 351 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 352 + ulong vector; 353 + u32 ven_msi; 354 + 355 + if (strict_strtoul(buf, 0, &vector)) 356 + return -EINVAL; 357 + 358 + if (!config->configured_msi) 359 + return -EINVAL; 360 + 361 + if (vector >= config->configured_msi) 362 + return -EINVAL; 363 + 364 + ven_msi = readl(&app_reg->ven_msi_1); 365 + ven_msi &= ~VEN_MSI_FUN_NUM_MASK; 366 + ven_msi |= 0 << VEN_MSI_FUN_NUM_ID; 367 + ven_msi &= ~VEN_MSI_TC_MASK; 368 + ven_msi |= 0 << VEN_MSI_TC_ID; 369 + ven_msi &= ~VEN_MSI_VECTOR_MASK; 370 + ven_msi |= vector << VEN_MSI_VECTOR_ID; 371 + 372 + /* generating interrupt for msi vector */ 373 + ven_msi |= VEN_MSI_REQ_EN; 374 + writel(ven_msi, &app_reg->ven_msi_1); 375 + udelay(1); 376 + ven_msi &= ~VEN_MSI_REQ_EN; 377 + writel(ven_msi, &app_reg->ven_msi_1); 378 + 379 + return count; 380 + } 381 + 382 + static ssize_t pcie_gadget_show_vendor_id( 383 + struct spear_pcie_gadget_config *config, 384 + char *buf) 385 + { 386 + u32 id; 387 + 388 + spear_dbi_read_reg(config, PCI_VENDOR_ID, 2, &id); 389 + 390 + return sprintf(buf, "%x", id); 391 + } 392 + 393 + static ssize_t pcie_gadget_store_vendor_id( 394 + struct spear_pcie_gadget_config *config, 395 + const char *buf, size_t count) 396 + { 397 + ulong id; 398 + 399 + if (strict_strtoul(buf, 0, &id)) 400 + return -EINVAL; 401 + 402 + spear_dbi_write_reg(config, PCI_VENDOR_ID, 2, id); 403 + 404 + return count; 405 + } 406 + 407 + static ssize_t pcie_gadget_show_device_id( 408 + struct spear_pcie_gadget_config *config, 409 + char *buf) 410 + { 411 + u32 id; 412 + 413 + spear_dbi_read_reg(config, PCI_DEVICE_ID, 2, &id); 414 + 415 + return sprintf(buf, "%x", id); 416 + } 417 + 418 + static ssize_t pcie_gadget_store_device_id( 419 + struct spear_pcie_gadget_config *config, 420 + const char *buf, size_t count) 421 + { 422 + ulong id; 423 + 424 + if (strict_strtoul(buf, 0, &id)) 425 + return -EINVAL; 426 + 427 + spear_dbi_write_reg(config, PCI_DEVICE_ID, 2, id); 428 + 429 + return count; 430 + } 431 + 432 + static ssize_t pcie_gadget_show_bar0_size( 433 + struct spear_pcie_gadget_config *config, 434 + char *buf) 435 + { 436 + return sprintf(buf, "%lx", config->bar0_size); 437 + } 438 + 439 + static ssize_t pcie_gadget_store_bar0_size( 440 + struct spear_pcie_gadget_config *config, 441 + const char *buf, size_t count) 442 + { 443 + ulong size; 444 + u32 pos, pos1; 445 + u32 no_of_bit = 0; 446 + 447 + if (strict_strtoul(buf, 0, &size)) 448 + return -EINVAL; 449 + /* min bar size is 256 */ 450 + if (size <= 0x100) 451 + size = 0x100; 452 + /* max bar size is 1MB*/ 453 + else if (size >= 0x100000) 454 + size = 0x100000; 455 + else { 456 + pos = 0; 457 + pos1 = 0; 458 + while (pos < 21) { 459 + pos = find_next_bit((ulong *)&size, 21, pos); 460 + if (pos != 21) 461 + pos1 = pos + 1; 462 + pos++; 463 + no_of_bit++; 464 + } 465 + if (no_of_bit == 2) 466 + pos1--; 467 + 468 + size = 1 << pos1; 469 + } 470 + config->bar0_size = size; 471 + spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, size - 1); 472 + 473 + return count; 474 + } 475 + 476 + static ssize_t pcie_gadget_show_bar0_address( 477 + struct spear_pcie_gadget_config *config, 478 + char *buf) 479 + { 480 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 481 + 482 + u32 address = readl(&app_reg->pim0_mem_addr_start); 483 + 484 + return sprintf(buf, "%x", address); 485 + } 486 + 487 + static ssize_t pcie_gadget_store_bar0_address( 488 + struct spear_pcie_gadget_config *config, 489 + const char *buf, size_t count) 490 + { 491 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 492 + ulong address; 493 + 494 + if (strict_strtoul(buf, 0, &address)) 495 + return -EINVAL; 496 + 497 + address &= ~(config->bar0_size - 1); 498 + if (config->va_bar0_address) 499 + iounmap(config->va_bar0_address); 500 + config->va_bar0_address = ioremap(address, config->bar0_size); 501 + if (!config->va_bar0_address) 502 + return -ENOMEM; 503 + 504 + writel(address, &app_reg->pim0_mem_addr_start); 505 + 506 + return count; 507 + } 508 + 509 + static ssize_t pcie_gadget_show_bar0_rw_offset( 510 + struct spear_pcie_gadget_config *config, 511 + char *buf) 512 + { 513 + return sprintf(buf, "%lx", config->bar0_rw_offset); 514 + } 515 + 516 + static ssize_t pcie_gadget_store_bar0_rw_offset( 517 + struct spear_pcie_gadget_config *config, 518 + const char *buf, size_t count) 519 + { 520 + ulong offset; 521 + 522 + if (strict_strtoul(buf, 0, &offset)) 523 + return -EINVAL; 524 + 525 + if (offset % 4) 526 + return -EINVAL; 527 + 528 + config->bar0_rw_offset = offset; 529 + 530 + return count; 531 + } 532 + 533 + static ssize_t pcie_gadget_show_bar0_data( 534 + struct spear_pcie_gadget_config *config, 535 + char *buf) 536 + { 537 + ulong data; 538 + 539 + if (!config->va_bar0_address) 540 + return -ENOMEM; 541 + 542 + data = readl((ulong)config->va_bar0_address + config->bar0_rw_offset); 543 + 544 + return sprintf(buf, "%lx", data); 545 + } 546 + 547 + static ssize_t pcie_gadget_store_bar0_data( 548 + struct spear_pcie_gadget_config *config, 549 + const char *buf, size_t count) 550 + { 551 + ulong data; 552 + 553 + if (strict_strtoul(buf, 0, &data)) 554 + return -EINVAL; 555 + 556 + if (!config->va_bar0_address) 557 + return -ENOMEM; 558 + 559 + writel(data, (ulong)config->va_bar0_address + config->bar0_rw_offset); 560 + 561 + return count; 562 + } 563 + 564 + /* 565 + * Attribute definitions. 566 + */ 567 + 568 + #define PCIE_GADGET_TARGET_ATTR_RO(_name) \ 569 + static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ 570 + __CONFIGFS_ATTR(_name, S_IRUGO, pcie_gadget_show_##_name, NULL) 571 + 572 + #define PCIE_GADGET_TARGET_ATTR_WO(_name) \ 573 + static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ 574 + __CONFIGFS_ATTR(_name, S_IWUSR, NULL, pcie_gadget_store_##_name) 575 + 576 + #define PCIE_GADGET_TARGET_ATTR_RW(_name) \ 577 + static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ 578 + __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, pcie_gadget_show_##_name, \ 579 + pcie_gadget_store_##_name) 580 + PCIE_GADGET_TARGET_ATTR_RW(link); 581 + PCIE_GADGET_TARGET_ATTR_RW(int_type); 582 + PCIE_GADGET_TARGET_ATTR_RW(no_of_msi); 583 + PCIE_GADGET_TARGET_ATTR_WO(inta); 584 + PCIE_GADGET_TARGET_ATTR_WO(send_msi); 585 + PCIE_GADGET_TARGET_ATTR_RW(vendor_id); 586 + PCIE_GADGET_TARGET_ATTR_RW(device_id); 587 + PCIE_GADGET_TARGET_ATTR_RW(bar0_size); 588 + PCIE_GADGET_TARGET_ATTR_RW(bar0_address); 589 + PCIE_GADGET_TARGET_ATTR_RW(bar0_rw_offset); 590 + PCIE_GADGET_TARGET_ATTR_RW(bar0_data); 591 + 592 + static struct configfs_attribute *pcie_gadget_target_attrs[] = { 593 + &pcie_gadget_target_link.attr, 594 + &pcie_gadget_target_int_type.attr, 595 + &pcie_gadget_target_no_of_msi.attr, 596 + &pcie_gadget_target_inta.attr, 597 + &pcie_gadget_target_send_msi.attr, 598 + &pcie_gadget_target_vendor_id.attr, 599 + &pcie_gadget_target_device_id.attr, 600 + &pcie_gadget_target_bar0_size.attr, 601 + &pcie_gadget_target_bar0_address.attr, 602 + &pcie_gadget_target_bar0_rw_offset.attr, 603 + &pcie_gadget_target_bar0_data.attr, 604 + NULL, 605 + }; 606 + 607 + static struct pcie_gadget_target *to_target(struct config_item *item) 608 + { 609 + return item ? 610 + container_of(to_configfs_subsystem(to_config_group(item)), 611 + struct pcie_gadget_target, subsys) : NULL; 612 + } 613 + 614 + /* 615 + * Item operations and type for pcie_gadget_target. 616 + */ 617 + 618 + static ssize_t pcie_gadget_target_attr_show(struct config_item *item, 619 + struct configfs_attribute *attr, 620 + char *buf) 621 + { 622 + ssize_t ret = -EINVAL; 623 + struct pcie_gadget_target *target = to_target(item); 624 + struct pcie_gadget_target_attr *t_attr = 625 + container_of(attr, struct pcie_gadget_target_attr, attr); 626 + 627 + if (t_attr->show) 628 + ret = t_attr->show(&target->config, buf); 629 + return ret; 630 + } 631 + 632 + static ssize_t pcie_gadget_target_attr_store(struct config_item *item, 633 + struct configfs_attribute *attr, 634 + const char *buf, 635 + size_t count) 636 + { 637 + ssize_t ret = -EINVAL; 638 + struct pcie_gadget_target *target = to_target(item); 639 + struct pcie_gadget_target_attr *t_attr = 640 + container_of(attr, struct pcie_gadget_target_attr, attr); 641 + 642 + if (t_attr->store) 643 + ret = t_attr->store(&target->config, buf, count); 644 + return ret; 645 + } 646 + 647 + static struct configfs_item_operations pcie_gadget_target_item_ops = { 648 + .show_attribute = pcie_gadget_target_attr_show, 649 + .store_attribute = pcie_gadget_target_attr_store, 650 + }; 651 + 652 + static struct config_item_type pcie_gadget_target_type = { 653 + .ct_attrs = pcie_gadget_target_attrs, 654 + .ct_item_ops = &pcie_gadget_target_item_ops, 655 + .ct_owner = THIS_MODULE, 656 + }; 657 + 658 + static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config) 659 + { 660 + struct pcie_app_reg __iomem *app_reg = config->va_app_base; 661 + 662 + /*setup registers for outbound translation */ 663 + 664 + writel(config->base, &app_reg->in0_mem_addr_start); 665 + writel(app_reg->in0_mem_addr_start + IN0_MEM_SIZE, 666 + &app_reg->in0_mem_addr_limit); 667 + writel(app_reg->in0_mem_addr_limit + 1, &app_reg->in1_mem_addr_start); 668 + writel(app_reg->in1_mem_addr_start + IN1_MEM_SIZE, 669 + &app_reg->in1_mem_addr_limit); 670 + writel(app_reg->in1_mem_addr_limit + 1, &app_reg->in_io_addr_start); 671 + writel(app_reg->in_io_addr_start + IN_IO_SIZE, 672 + &app_reg->in_io_addr_limit); 673 + writel(app_reg->in_io_addr_limit + 1, &app_reg->in_cfg0_addr_start); 674 + writel(app_reg->in_cfg0_addr_start + IN_CFG0_SIZE, 675 + &app_reg->in_cfg0_addr_limit); 676 + writel(app_reg->in_cfg0_addr_limit + 1, &app_reg->in_cfg1_addr_start); 677 + writel(app_reg->in_cfg1_addr_start + IN_CFG1_SIZE, 678 + &app_reg->in_cfg1_addr_limit); 679 + writel(app_reg->in_cfg1_addr_limit + 1, &app_reg->in_msg_addr_start); 680 + writel(app_reg->in_msg_addr_start + IN_MSG_SIZE, 681 + &app_reg->in_msg_addr_limit); 682 + 683 + writel(app_reg->in0_mem_addr_start, &app_reg->pom0_mem_addr_start); 684 + writel(app_reg->in1_mem_addr_start, &app_reg->pom1_mem_addr_start); 685 + writel(app_reg->in_io_addr_start, &app_reg->pom_io_addr_start); 686 + 687 + /*setup registers for inbound translation */ 688 + 689 + /* Keep AORAM mapped at BAR0 as default */ 690 + config->bar0_size = INBOUND_ADDR_MASK + 1; 691 + spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, INBOUND_ADDR_MASK); 692 + spear_dbi_write_reg(config, PCI_BASE_ADDRESS_0, 4, 0xC); 693 + config->va_bar0_address = ioremap(SPEAR13XX_SYSRAM1_BASE, 694 + config->bar0_size); 695 + 696 + writel(SPEAR13XX_SYSRAM1_BASE, &app_reg->pim0_mem_addr_start); 697 + writel(0, &app_reg->pim1_mem_addr_start); 698 + writel(INBOUND_ADDR_MASK + 1, &app_reg->mem0_addr_offset_limit); 699 + 700 + writel(0x0, &app_reg->pim_io_addr_start); 701 + writel(0x0, &app_reg->pim_io_addr_start); 702 + writel(0x0, &app_reg->pim_rom_addr_start); 703 + 704 + writel(DEVICE_TYPE_EP | (1 << MISCTRL_EN_ID) 705 + | ((u32)1 << REG_TRANSLATION_ENABLE), 706 + &app_reg->app_ctrl_0); 707 + /* disable all rx interrupts */ 708 + writel(0, &app_reg->int_mask); 709 + 710 + /* Select INTA as default*/ 711 + spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); 712 + } 713 + 714 + static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev) 715 + { 716 + struct resource *res0, *res1; 717 + unsigned int status = 0; 718 + int irq; 719 + struct clk *clk; 720 + static struct pcie_gadget_target *target; 721 + struct spear_pcie_gadget_config *config; 722 + struct config_item *cg_item; 723 + struct configfs_subsystem *subsys; 724 + 725 + /* get resource for application registers*/ 726 + 727 + res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 728 + if (!res0) { 729 + dev_err(&pdev->dev, "no resource defined\n"); 730 + return -EBUSY; 731 + } 732 + if (!request_mem_region(res0->start, resource_size(res0), 733 + pdev->name)) { 734 + dev_err(&pdev->dev, "pcie gadget region already claimed\n"); 735 + return -EBUSY; 736 + } 737 + /* get resource for dbi registers*/ 738 + 739 + res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 740 + if (!res1) { 741 + dev_err(&pdev->dev, "no resource defined\n"); 742 + goto err_rel_res0; 743 + } 744 + if (!request_mem_region(res1->start, resource_size(res1), 745 + pdev->name)) { 746 + dev_err(&pdev->dev, "pcie gadget region already claimed\n"); 747 + goto err_rel_res0; 748 + } 749 + 750 + target = kzalloc(sizeof(*target), GFP_KERNEL); 751 + if (!target) { 752 + dev_err(&pdev->dev, "out of memory\n"); 753 + status = -ENOMEM; 754 + goto err_rel_res; 755 + } 756 + 757 + cg_item = &target->subsys.su_group.cg_item; 758 + sprintf(cg_item->ci_namebuf, "pcie_gadget.%d", pdev->id); 759 + cg_item->ci_type = &pcie_gadget_target_type; 760 + config = &target->config; 761 + config->va_app_base = (void __iomem *)ioremap(res0->start, 762 + resource_size(res0)); 763 + if (!config->va_app_base) { 764 + dev_err(&pdev->dev, "ioremap fail\n"); 765 + status = -ENOMEM; 766 + goto err_kzalloc; 767 + } 768 + 769 + config->base = (void __iomem *)res1->start; 770 + 771 + config->va_dbi_base = (void __iomem *)ioremap(res1->start, 772 + resource_size(res1)); 773 + if (!config->va_dbi_base) { 774 + dev_err(&pdev->dev, "ioremap fail\n"); 775 + status = -ENOMEM; 776 + goto err_iounmap_app; 777 + } 778 + 779 + dev_set_drvdata(&pdev->dev, target); 780 + 781 + irq = platform_get_irq(pdev, 0); 782 + if (irq < 0) { 783 + dev_err(&pdev->dev, "no update irq?\n"); 784 + status = irq; 785 + goto err_iounmap; 786 + } 787 + 788 + status = request_irq(irq, spear_pcie_gadget_irq, 0, pdev->name, NULL); 789 + if (status) { 790 + dev_err(&pdev->dev, "pcie gadget interrupt IRQ%d already \ 791 + claimed\n", irq); 792 + goto err_iounmap; 793 + } 794 + 795 + /* Register configfs hooks */ 796 + subsys = &target->subsys; 797 + config_group_init(&subsys->su_group); 798 + mutex_init(&subsys->su_mutex); 799 + status = configfs_register_subsystem(subsys); 800 + if (status) 801 + goto err_irq; 802 + 803 + /* 804 + * init basic pcie application registers 805 + * do not enable clock if it is PCIE0.Ideally , all controller should 806 + * have been independent from others with respect to clock. But PCIE1 807 + * and 2 depends on PCIE0.So PCIE0 clk is provided during board init. 808 + */ 809 + if (pdev->id == 1) { 810 + /* 811 + * Ideally CFG Clock should have been also enabled here. But 812 + * it is done currently during board init routne 813 + */ 814 + clk = clk_get_sys("pcie1", NULL); 815 + if (IS_ERR(clk)) { 816 + pr_err("%s:couldn't get clk for pcie1\n", __func__); 817 + goto err_irq; 818 + } 819 + if (clk_enable(clk)) { 820 + pr_err("%s:couldn't enable clk for pcie1\n", __func__); 821 + goto err_irq; 822 + } 823 + } else if (pdev->id == 2) { 824 + /* 825 + * Ideally CFG Clock should have been also enabled here. But 826 + * it is done currently during board init routne 827 + */ 828 + clk = clk_get_sys("pcie2", NULL); 829 + if (IS_ERR(clk)) { 830 + pr_err("%s:couldn't get clk for pcie2\n", __func__); 831 + goto err_irq; 832 + } 833 + if (clk_enable(clk)) { 834 + pr_err("%s:couldn't enable clk for pcie2\n", __func__); 835 + goto err_irq; 836 + } 837 + } 838 + spear13xx_pcie_device_init(config); 839 + 840 + return 0; 841 + err_irq: 842 + free_irq(irq, NULL); 843 + err_iounmap: 844 + iounmap(config->va_dbi_base); 845 + err_iounmap_app: 846 + iounmap(config->va_app_base); 847 + err_kzalloc: 848 + kfree(config); 849 + err_rel_res: 850 + release_mem_region(res1->start, resource_size(res1)); 851 + err_rel_res0: 852 + release_mem_region(res0->start, resource_size(res0)); 853 + return status; 854 + } 855 + 856 + static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev) 857 + { 858 + struct resource *res0, *res1; 859 + static struct pcie_gadget_target *target; 860 + struct spear_pcie_gadget_config *config; 861 + int irq; 862 + 863 + res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 864 + res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 865 + irq = platform_get_irq(pdev, 0); 866 + target = dev_get_drvdata(&pdev->dev); 867 + config = &target->config; 868 + 869 + free_irq(irq, NULL); 870 + iounmap(config->va_dbi_base); 871 + iounmap(config->va_app_base); 872 + release_mem_region(res1->start, resource_size(res1)); 873 + release_mem_region(res0->start, resource_size(res0)); 874 + configfs_unregister_subsystem(&target->subsys); 875 + kfree(target); 876 + 877 + return 0; 878 + } 879 + 880 + static void spear_pcie_gadget_shutdown(struct platform_device *pdev) 881 + { 882 + } 883 + 884 + static struct platform_driver spear_pcie_gadget_driver = { 885 + .probe = spear_pcie_gadget_probe, 886 + .remove = spear_pcie_gadget_remove, 887 + .shutdown = spear_pcie_gadget_shutdown, 888 + .driver = { 889 + .name = "pcie-gadget-spear", 890 + .bus = &platform_bus_type 891 + }, 892 + }; 893 + 894 + static int __init spear_pcie_gadget_init(void) 895 + { 896 + return platform_driver_register(&spear_pcie_gadget_driver); 897 + } 898 + module_init(spear_pcie_gadget_init); 899 + 900 + static void __exit spear_pcie_gadget_exit(void) 901 + { 902 + platform_driver_unregister(&spear_pcie_gadget_driver); 903 + } 904 + module_exit(spear_pcie_gadget_exit); 905 + 906 + MODULE_ALIAS("pcie-gadget-spear"); 907 + MODULE_AUTHOR("Pratyush Anand"); 908 + MODULE_LICENSE("GPL");