| .. SPDX-License-Identifier: GPL-2.0 | 
 |  | 
 | ======================== | 
 | Spear PCIe Gadget Driver | 
 | ======================== | 
 |  | 
 | Author | 
 | ====== | 
 | Pratyush Anand (pratyush.anand@gmail.com) | 
 |  | 
 | Location | 
 | ======== | 
 | driver/misc/spear13xx_pcie_gadget.c | 
 |  | 
 | Supported Chip: | 
 | =============== | 
 | SPEAr1300 | 
 | SPEAr1310 | 
 |  | 
 | Menuconfig option: | 
 | ================== | 
 | Device Drivers | 
 | 	Misc devices | 
 | 		PCIe gadget support for SPEAr13XX platform | 
 |  | 
 | purpose | 
 | ======= | 
 | This driver has several nodes which can be read/written by configfs interface. | 
 | Its main purpose is to configure selected dual mode PCIe controller as device | 
 | and then program its various registers to configure it as a particular device | 
 | type. This driver can be used to show spear's PCIe device capability. | 
 |  | 
 | Description of different nodes: | 
 | =============================== | 
 |  | 
 | read behavior of nodes: | 
 | ----------------------- | 
 |  | 
 | =============== ============================================================== | 
 | link 		gives ltssm status. | 
 | int_type 	type of supported interrupt | 
 | no_of_msi 	zero if MSI is not enabled by host. A positive value is the | 
 | 		number of MSI vector granted. | 
 | vendor_id	returns programmed vendor id (hex) | 
 | device_id	returns programmed device id(hex) | 
 | bar0_size:	returns size of bar0 in hex. | 
 | bar0_address	returns address of bar0 mapped area in hex. | 
 | bar0_rw_offset	returns offset of bar0 for which bar0_data will return value. | 
 | bar0_data	returns data at bar0_rw_offset. | 
 | =============== ============================================================== | 
 |  | 
 | write behavior of nodes: | 
 | ------------------------ | 
 |  | 
 | =============== ================================================================ | 
 | link 		write UP to enable ltsmm DOWN to disable | 
 | int_type	write interrupt type to be configured and (int_type could be | 
 | 		INTA, MSI or NO_INT). Select MSI only when you have programmed | 
 | 		no_of_msi node. | 
 | no_of_msi	number of MSI vector needed. | 
 | inta		write 1 to assert INTA and 0 to de-assert. | 
 | send_msi	write MSI vector to be sent. | 
 | vendor_id	write vendor id(hex) to be programmed. | 
 | device_id	write device id(hex) to be programmed. | 
 | bar0_size	write size of bar0 in hex. default bar0 size is 1000 (hex) | 
 | 		bytes. | 
 | bar0_address	write	address of bar0 mapped area in hex. (default mapping of | 
 | 		bar0 is SYSRAM1(E0800000). Always program bar size before bar | 
 | 		address. Kernel might modify bar size and address for alignment, | 
 | 		so read back bar size and address after writing to cross check. | 
 | bar0_rw_offset	write offset of bar0 for which	bar0_data will write value. | 
 | bar0_data	write data to be written at bar0_rw_offset. | 
 | =============== ================================================================ | 
 |  | 
 | Node programming example | 
 | ======================== | 
 |  | 
 | Program all PCIe registers in such a way that when this device is connected | 
 | to the PCIe host, then host sees this device as 1MB RAM. | 
 |  | 
 | :: | 
 |  | 
 |     #mount -t configfs none /Config | 
 |  | 
 | For nth PCIe Device Controller:: | 
 |  | 
 |     # cd /config/pcie_gadget.n/ | 
 |  | 
 | Now you have all the nodes in this directory. | 
 | program vendor id as 0x104a:: | 
 |  | 
 |     # echo 104A >> vendor_id | 
 |  | 
 | program device id as 0xCD80:: | 
 |  | 
 |     # echo CD80 >> device_id | 
 |  | 
 | program BAR0 size as 1MB:: | 
 |  | 
 |     # echo 100000 >> bar0_size | 
 |  | 
 | check for programmed bar0 size:: | 
 |  | 
 |     # cat bar0_size | 
 |  | 
 | Program BAR0 Address as DDR (0x2100000). This is the physical address of | 
 | memory, which is to be made visible to PCIe host. Similarly any other peripheral | 
 | can also be made visible to PCIe host. E.g., if you program base address of UART | 
 | as BAR0 address then when this device will be connected to a host, it will be | 
 | visible as UART. | 
 |  | 
 | :: | 
 |  | 
 |     # echo 2100000 >> bar0_address | 
 |  | 
 | program interrupt type : INTA:: | 
 |  | 
 |     # echo INTA >> int_type | 
 |  | 
 | go for link up now:: | 
 |  | 
 |     # echo UP >> link | 
 |  | 
 | It will have to be insured that, once link up is done on gadget, then only host | 
 | is initialized and start to search PCIe devices on its port. | 
 |  | 
 | :: | 
 |  | 
 |     /*wait till link is up*/ | 
 |     # cat link | 
 |  | 
 | Wait till it returns UP. | 
 |  | 
 | To assert INTA:: | 
 |  | 
 |     # echo 1 >> inta | 
 |  | 
 | To de-assert INTA:: | 
 |  | 
 |     # echo 0 >> inta | 
 |  | 
 | if MSI is to be used as interrupt, program no of msi vector needed (say4):: | 
 |  | 
 |     # echo 4 >> no_of_msi | 
 |  | 
 | select MSI as interrupt type:: | 
 |  | 
 |     # echo MSI >> int_type | 
 |  | 
 | go for link up now:: | 
 |  | 
 |     # echo UP >> link | 
 |  | 
 | wait till link is up:: | 
 |  | 
 |     # cat link | 
 |  | 
 | An application can repetitively read this node till link is found UP. It can | 
 | sleep between two read. | 
 |  | 
 | wait till msi is enabled:: | 
 |  | 
 |     # cat no_of_msi | 
 |  | 
 | Should return 4 (number of requested MSI vector) | 
 |  | 
 | to send msi vector 2:: | 
 |  | 
 |     # echo 2 >> send_msi | 
 |     # cd - |