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