xref: /openbmc/linux/drivers/scsi/aic94xx/aic94xx_reg.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*65c85c83SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22908d778SJames Bottomley /*
32908d778SJames Bottomley  * Aic94xx SAS/SATA driver register access.
42908d778SJames Bottomley  *
52908d778SJames Bottomley  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
62908d778SJames Bottomley  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
72908d778SJames Bottomley  */
82908d778SJames Bottomley 
92908d778SJames Bottomley #include <linux/pci.h>
102908d778SJames Bottomley #include "aic94xx_reg.h"
112908d778SJames Bottomley #include "aic94xx.h"
122908d778SJames Bottomley 
132908d778SJames Bottomley /* Writing to device address space.
142908d778SJames Bottomley  * Offset comes before value to remind that the operation of
152908d778SJames Bottomley  * this function is *offs = val.
162908d778SJames Bottomley  */
asd_write_byte(struct asd_ha_struct * asd_ha,unsigned long offs,u8 val)1781e56dedSAdrian Bunk static void asd_write_byte(struct asd_ha_struct *asd_ha,
182908d778SJames Bottomley 			   unsigned long offs, u8 val)
192908d778SJames Bottomley {
202908d778SJames Bottomley 	if (unlikely(asd_ha->iospace))
212908d778SJames Bottomley 		outb(val,
222908d778SJames Bottomley 		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
232908d778SJames Bottomley 	else
242908d778SJames Bottomley 		writeb(val, asd_ha->io_handle[0].addr + offs);
252908d778SJames Bottomley 	wmb();
262908d778SJames Bottomley }
272908d778SJames Bottomley 
asd_write_word(struct asd_ha_struct * asd_ha,unsigned long offs,u16 val)2881e56dedSAdrian Bunk static void asd_write_word(struct asd_ha_struct *asd_ha,
292908d778SJames Bottomley 			   unsigned long offs, u16 val)
302908d778SJames Bottomley {
312908d778SJames Bottomley 	if (unlikely(asd_ha->iospace))
322908d778SJames Bottomley 		outw(val,
332908d778SJames Bottomley 		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
342908d778SJames Bottomley 	else
352908d778SJames Bottomley 		writew(val, asd_ha->io_handle[0].addr + offs);
362908d778SJames Bottomley 	wmb();
372908d778SJames Bottomley }
382908d778SJames Bottomley 
asd_write_dword(struct asd_ha_struct * asd_ha,unsigned long offs,u32 val)3981e56dedSAdrian Bunk static void asd_write_dword(struct asd_ha_struct *asd_ha,
402908d778SJames Bottomley 			    unsigned long offs, u32 val)
412908d778SJames Bottomley {
422908d778SJames Bottomley 	if (unlikely(asd_ha->iospace))
432908d778SJames Bottomley 		outl(val,
442908d778SJames Bottomley 		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
452908d778SJames Bottomley 	else
462908d778SJames Bottomley 		writel(val, asd_ha->io_handle[0].addr + offs);
472908d778SJames Bottomley 	wmb();
482908d778SJames Bottomley }
492908d778SJames Bottomley 
502908d778SJames Bottomley /* Reading from device address space.
512908d778SJames Bottomley  */
asd_read_byte(struct asd_ha_struct * asd_ha,unsigned long offs)5281e56dedSAdrian Bunk static u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs)
532908d778SJames Bottomley {
542908d778SJames Bottomley 	u8 val;
552908d778SJames Bottomley 	if (unlikely(asd_ha->iospace))
562908d778SJames Bottomley 		val = inb((unsigned long) asd_ha->io_handle[0].addr
572908d778SJames Bottomley 			  + (offs & 0xFF));
582908d778SJames Bottomley 	else
592908d778SJames Bottomley 		val = readb(asd_ha->io_handle[0].addr + offs);
602908d778SJames Bottomley 	rmb();
612908d778SJames Bottomley 	return val;
622908d778SJames Bottomley }
632908d778SJames Bottomley 
asd_read_word(struct asd_ha_struct * asd_ha,unsigned long offs)6481e56dedSAdrian Bunk static u16 asd_read_word(struct asd_ha_struct *asd_ha,
652908d778SJames Bottomley 			 unsigned long offs)
662908d778SJames Bottomley {
672908d778SJames Bottomley 	u16 val;
682908d778SJames Bottomley 	if (unlikely(asd_ha->iospace))
692908d778SJames Bottomley 		val = inw((unsigned long)asd_ha->io_handle[0].addr
702908d778SJames Bottomley 			  + (offs & 0xFF));
712908d778SJames Bottomley 	else
722908d778SJames Bottomley 		val = readw(asd_ha->io_handle[0].addr + offs);
732908d778SJames Bottomley 	rmb();
742908d778SJames Bottomley 	return val;
752908d778SJames Bottomley }
762908d778SJames Bottomley 
asd_read_dword(struct asd_ha_struct * asd_ha,unsigned long offs)7781e56dedSAdrian Bunk static u32 asd_read_dword(struct asd_ha_struct *asd_ha,
782908d778SJames Bottomley 			  unsigned long offs)
792908d778SJames Bottomley {
802908d778SJames Bottomley 	u32 val;
812908d778SJames Bottomley 	if (unlikely(asd_ha->iospace))
822908d778SJames Bottomley 		val = inl((unsigned long) asd_ha->io_handle[0].addr
832908d778SJames Bottomley 			  + (offs & 0xFF));
842908d778SJames Bottomley 	else
852908d778SJames Bottomley 		val = readl(asd_ha->io_handle[0].addr + offs);
862908d778SJames Bottomley 	rmb();
872908d778SJames Bottomley 	return val;
882908d778SJames Bottomley }
892908d778SJames Bottomley 
asd_mem_offs_swa(void)902908d778SJames Bottomley static inline u32 asd_mem_offs_swa(void)
912908d778SJames Bottomley {
922908d778SJames Bottomley 	return 0;
932908d778SJames Bottomley }
942908d778SJames Bottomley 
asd_mem_offs_swc(void)952908d778SJames Bottomley static inline u32 asd_mem_offs_swc(void)
962908d778SJames Bottomley {
972908d778SJames Bottomley 	return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
982908d778SJames Bottomley }
992908d778SJames Bottomley 
asd_mem_offs_swb(void)1002908d778SJames Bottomley static inline u32 asd_mem_offs_swb(void)
1012908d778SJames Bottomley {
1022908d778SJames Bottomley 	return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
1032908d778SJames Bottomley }
1042908d778SJames Bottomley 
1052908d778SJames Bottomley /* We know that the register wanted is in the range
1062908d778SJames Bottomley  * of the sliding window.
1072908d778SJames Bottomley  */
1082908d778SJames Bottomley #define ASD_READ_SW(ww, type, ord)					\
10981e56dedSAdrian Bunk static type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha,		\
1102908d778SJames Bottomley 				   u32 reg)				\
1112908d778SJames Bottomley {									\
1122908d778SJames Bottomley 	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];	\
1132908d778SJames Bottomley 	u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
1142908d778SJames Bottomley 	return asd_read_##ord(asd_ha, (unsigned long)map_offs);	\
1152908d778SJames Bottomley }
1162908d778SJames Bottomley 
1172908d778SJames Bottomley #define ASD_WRITE_SW(ww, type, ord)					\
11881e56dedSAdrian Bunk static void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha,	\
1192908d778SJames Bottomley 				    u32 reg, type val)			\
1202908d778SJames Bottomley {									\
1212908d778SJames Bottomley 	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];	\
1222908d778SJames Bottomley 	u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
1232908d778SJames Bottomley 	asd_write_##ord(asd_ha, (unsigned long)map_offs, val);		\
1242908d778SJames Bottomley }
1252908d778SJames Bottomley 
1262908d778SJames Bottomley ASD_READ_SW(swa, u8,  byte);
1272908d778SJames Bottomley ASD_READ_SW(swa, u16, word);
1282908d778SJames Bottomley ASD_READ_SW(swa, u32, dword);
1292908d778SJames Bottomley 
1302908d778SJames Bottomley ASD_READ_SW(swb, u8,  byte);
1312908d778SJames Bottomley ASD_READ_SW(swb, u16, word);
1322908d778SJames Bottomley ASD_READ_SW(swb, u32, dword);
1332908d778SJames Bottomley 
1342908d778SJames Bottomley ASD_READ_SW(swc, u8,  byte);
1352908d778SJames Bottomley ASD_READ_SW(swc, u16, word);
1362908d778SJames Bottomley ASD_READ_SW(swc, u32, dword);
1372908d778SJames Bottomley 
1382908d778SJames Bottomley ASD_WRITE_SW(swa, u8,  byte);
1392908d778SJames Bottomley ASD_WRITE_SW(swa, u16, word);
1402908d778SJames Bottomley ASD_WRITE_SW(swa, u32, dword);
1412908d778SJames Bottomley 
1422908d778SJames Bottomley ASD_WRITE_SW(swb, u8,  byte);
1432908d778SJames Bottomley ASD_WRITE_SW(swb, u16, word);
1442908d778SJames Bottomley ASD_WRITE_SW(swb, u32, dword);
1452908d778SJames Bottomley 
1462908d778SJames Bottomley ASD_WRITE_SW(swc, u8,  byte);
1472908d778SJames Bottomley ASD_WRITE_SW(swc, u16, word);
1482908d778SJames Bottomley ASD_WRITE_SW(swc, u32, dword);
1492908d778SJames Bottomley 
1502908d778SJames Bottomley /*
1512908d778SJames Bottomley  * A word about sliding windows:
1522908d778SJames Bottomley  * MBAR0 is divided into sliding windows A, C and B, in that order.
1532908d778SJames Bottomley  * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
1542908d778SJames Bottomley  * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
1552908d778SJames Bottomley  * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
1562908d778SJames Bottomley  * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
1572908d778SJames Bottomley  * See asd_init_sw() in aic94xx_hwi.c
1582908d778SJames Bottomley  *
1592908d778SJames Bottomley  * We map the most common registers we'd access of the internal 4GB
1602908d778SJames Bottomley  * host adapter memory space.  If a register/internal memory location
1612908d778SJames Bottomley  * is wanted which is not mapped, we slide SWB, by paging it,
1622908d778SJames Bottomley  * see asd_move_swb() in aic94xx_reg.c.
1632908d778SJames Bottomley  */
1642908d778SJames Bottomley 
1652908d778SJames Bottomley /**
1662908d778SJames Bottomley  * asd_move_swb -- move sliding window B
1672908d778SJames Bottomley  * @asd_ha: pointer to host adapter structure
1682908d778SJames Bottomley  * @reg: register desired to be within range of the new window
1692908d778SJames Bottomley  */
asd_move_swb(struct asd_ha_struct * asd_ha,u32 reg)17081e56dedSAdrian Bunk static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
1712908d778SJames Bottomley {
1722908d778SJames Bottomley 	u32 base = reg & ~(MBAR0_SWB_SIZE-1);
1732908d778SJames Bottomley 	pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
1742908d778SJames Bottomley 	asd_ha->io_handle[0].swb_base = base;
1752908d778SJames Bottomley }
1762908d778SJames Bottomley 
__asd_write_reg_byte(struct asd_ha_struct * asd_ha,u32 reg,u8 val)1772908d778SJames Bottomley static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
1782908d778SJames Bottomley {
1792908d778SJames Bottomley 	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
1802908d778SJames Bottomley 	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
1812908d778SJames Bottomley 	if (io_handle->swa_base <= reg
1822908d778SJames Bottomley 	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
1832908d778SJames Bottomley 		asd_write_swa_byte (asd_ha, reg,val);
1842908d778SJames Bottomley 	else if (io_handle->swb_base <= reg
1852908d778SJames Bottomley 		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
1862908d778SJames Bottomley 		asd_write_swb_byte (asd_ha, reg, val);
1872908d778SJames Bottomley 	else if (io_handle->swc_base <= reg
1882908d778SJames Bottomley 		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
1892908d778SJames Bottomley 		asd_write_swc_byte (asd_ha, reg, val);
1902908d778SJames Bottomley 	else {
1912908d778SJames Bottomley 		/* Ok, we have to move SWB */
1922908d778SJames Bottomley 		asd_move_swb(asd_ha, reg);
1932908d778SJames Bottomley 		asd_write_swb_byte (asd_ha, reg, val);
1942908d778SJames Bottomley 	}
1952908d778SJames Bottomley }
1962908d778SJames Bottomley 
1972908d778SJames Bottomley #define ASD_WRITE_REG(type, ord)                                  \
1982908d778SJames Bottomley void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
1992908d778SJames Bottomley {                                                                 \
2002908d778SJames Bottomley 	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
2012908d778SJames Bottomley 	unsigned long flags;                                      \
2022908d778SJames Bottomley 	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
2032908d778SJames Bottomley 	spin_lock_irqsave(&asd_ha->iolock, flags);                \
2042908d778SJames Bottomley 	if (io_handle->swa_base <= reg                            \
2052908d778SJames Bottomley 	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
2062908d778SJames Bottomley 		asd_write_swa_##ord (asd_ha, reg,val);            \
2072908d778SJames Bottomley 	else if (io_handle->swb_base <= reg                       \
2082908d778SJames Bottomley 		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
2092908d778SJames Bottomley 		asd_write_swb_##ord (asd_ha, reg, val);           \
2102908d778SJames Bottomley 	else if (io_handle->swc_base <= reg                       \
2112908d778SJames Bottomley 		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
2122908d778SJames Bottomley 		asd_write_swc_##ord (asd_ha, reg, val);           \
2132908d778SJames Bottomley 	else {                                                    \
2142908d778SJames Bottomley 		/* Ok, we have to move SWB */                     \
2152908d778SJames Bottomley 		asd_move_swb(asd_ha, reg);                        \
2162908d778SJames Bottomley 		asd_write_swb_##ord (asd_ha, reg, val);           \
2172908d778SJames Bottomley 	}                                                         \
2182908d778SJames Bottomley 	spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
2192908d778SJames Bottomley }
2202908d778SJames Bottomley 
2212908d778SJames Bottomley ASD_WRITE_REG(u8, byte);
2222908d778SJames Bottomley ASD_WRITE_REG(u16,word);
2232908d778SJames Bottomley ASD_WRITE_REG(u32,dword);
2242908d778SJames Bottomley 
__asd_read_reg_byte(struct asd_ha_struct * asd_ha,u32 reg)2252908d778SJames Bottomley static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
2262908d778SJames Bottomley {
2272908d778SJames Bottomley 	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
2282908d778SJames Bottomley 	u8 val;
2292908d778SJames Bottomley 	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
2302908d778SJames Bottomley 	if (io_handle->swa_base <= reg
2312908d778SJames Bottomley 	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
2322908d778SJames Bottomley 		val = asd_read_swa_byte (asd_ha, reg);
2332908d778SJames Bottomley 	else if (io_handle->swb_base <= reg
2342908d778SJames Bottomley 		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
2352908d778SJames Bottomley 		val = asd_read_swb_byte (asd_ha, reg);
2362908d778SJames Bottomley 	else if (io_handle->swc_base <= reg
2372908d778SJames Bottomley 		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
2382908d778SJames Bottomley 		val = asd_read_swc_byte (asd_ha, reg);
2392908d778SJames Bottomley 	else {
2402908d778SJames Bottomley 		/* Ok, we have to move SWB */
2412908d778SJames Bottomley 		asd_move_swb(asd_ha, reg);
2422908d778SJames Bottomley 		val = asd_read_swb_byte (asd_ha, reg);
2432908d778SJames Bottomley 	}
2442908d778SJames Bottomley 	return val;
2452908d778SJames Bottomley }
2462908d778SJames Bottomley 
2472908d778SJames Bottomley #define ASD_READ_REG(type, ord)                                   \
2482908d778SJames Bottomley type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg)   \
2492908d778SJames Bottomley {                                                                 \
2502908d778SJames Bottomley 	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
2512908d778SJames Bottomley 	type val;                                                 \
2522908d778SJames Bottomley 	unsigned long flags;                                      \
2532908d778SJames Bottomley 	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
2542908d778SJames Bottomley 	spin_lock_irqsave(&asd_ha->iolock, flags);                \
2552908d778SJames Bottomley 	if (io_handle->swa_base <= reg                            \
2562908d778SJames Bottomley 	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
2572908d778SJames Bottomley 		val = asd_read_swa_##ord (asd_ha, reg);           \
2582908d778SJames Bottomley 	else if (io_handle->swb_base <= reg                       \
2592908d778SJames Bottomley 		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
2602908d778SJames Bottomley 		val = asd_read_swb_##ord (asd_ha, reg);           \
2612908d778SJames Bottomley 	else if (io_handle->swc_base <= reg                       \
2622908d778SJames Bottomley 		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
2632908d778SJames Bottomley 		val = asd_read_swc_##ord (asd_ha, reg);           \
2642908d778SJames Bottomley 	else {                                                    \
2652908d778SJames Bottomley 		/* Ok, we have to move SWB */                     \
2662908d778SJames Bottomley 		asd_move_swb(asd_ha, reg);                        \
2672908d778SJames Bottomley 		val = asd_read_swb_##ord (asd_ha, reg);           \
2682908d778SJames Bottomley 	}                                                         \
2692908d778SJames Bottomley 	spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
2702908d778SJames Bottomley 	return val;                                               \
2712908d778SJames Bottomley }
2722908d778SJames Bottomley 
2732908d778SJames Bottomley ASD_READ_REG(u8, byte);
2742908d778SJames Bottomley ASD_READ_REG(u16,word);
2752908d778SJames Bottomley ASD_READ_REG(u32,dword);
2762908d778SJames Bottomley 
2772908d778SJames Bottomley /**
2782908d778SJames Bottomley  * asd_read_reg_string -- read a string of bytes from io space memory
2792908d778SJames Bottomley  * @asd_ha: pointer to host adapter structure
2802908d778SJames Bottomley  * @dst: pointer to a destination buffer where data will be written to
2812908d778SJames Bottomley  * @offs: start offset (register) to read from
2822908d778SJames Bottomley  * @count: number of bytes to read
2832908d778SJames Bottomley  */
asd_read_reg_string(struct asd_ha_struct * asd_ha,void * dst,u32 offs,int count)2842908d778SJames Bottomley void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
2852908d778SJames Bottomley 			 u32 offs, int count)
2862908d778SJames Bottomley {
2872908d778SJames Bottomley 	u8 *p = dst;
2882908d778SJames Bottomley 	unsigned long flags;
2892908d778SJames Bottomley 
2902908d778SJames Bottomley 	spin_lock_irqsave(&asd_ha->iolock, flags);
2912908d778SJames Bottomley 	for ( ; count > 0; count--, offs++, p++)
2922908d778SJames Bottomley 		*p = __asd_read_reg_byte(asd_ha, offs);
2932908d778SJames Bottomley 	spin_unlock_irqrestore(&asd_ha->iolock, flags);
2942908d778SJames Bottomley }
2952908d778SJames Bottomley 
2962908d778SJames Bottomley /**
2972908d778SJames Bottomley  * asd_write_reg_string -- write a string of bytes to io space memory
2982908d778SJames Bottomley  * @asd_ha: pointer to host adapter structure
2992908d778SJames Bottomley  * @src: pointer to source buffer where data will be read from
3002908d778SJames Bottomley  * @offs: start offset (register) to write to
3012908d778SJames Bottomley  * @count: number of bytes to write
3022908d778SJames Bottomley  */
asd_write_reg_string(struct asd_ha_struct * asd_ha,void * src,u32 offs,int count)3032908d778SJames Bottomley void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
3042908d778SJames Bottomley 			  u32 offs, int count)
3052908d778SJames Bottomley {
3062908d778SJames Bottomley 	u8 *p = src;
3072908d778SJames Bottomley 	unsigned long flags;
3082908d778SJames Bottomley 
3092908d778SJames Bottomley 	spin_lock_irqsave(&asd_ha->iolock, flags);
3102908d778SJames Bottomley 	for ( ; count > 0; count--, offs++, p++)
3112908d778SJames Bottomley 		__asd_write_reg_byte(asd_ha, offs, *p);
3122908d778SJames Bottomley 	spin_unlock_irqrestore(&asd_ha->iolock, flags);
3132908d778SJames Bottomley }
314