1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Aic94xx SAS/SATA driver register access.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
6*4882a593Smuzhiyun * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/pci.h>
10*4882a593Smuzhiyun #include "aic94xx_reg.h"
11*4882a593Smuzhiyun #include "aic94xx.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /* Writing to device address space.
14*4882a593Smuzhiyun * Offset comes before value to remind that the operation of
15*4882a593Smuzhiyun * this function is *offs = val.
16*4882a593Smuzhiyun */
asd_write_byte(struct asd_ha_struct * asd_ha,unsigned long offs,u8 val)17*4882a593Smuzhiyun static void asd_write_byte(struct asd_ha_struct *asd_ha,
18*4882a593Smuzhiyun unsigned long offs, u8 val)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun if (unlikely(asd_ha->iospace))
21*4882a593Smuzhiyun outb(val,
22*4882a593Smuzhiyun (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
23*4882a593Smuzhiyun else
24*4882a593Smuzhiyun writeb(val, asd_ha->io_handle[0].addr + offs);
25*4882a593Smuzhiyun wmb();
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
asd_write_word(struct asd_ha_struct * asd_ha,unsigned long offs,u16 val)28*4882a593Smuzhiyun static void asd_write_word(struct asd_ha_struct *asd_ha,
29*4882a593Smuzhiyun unsigned long offs, u16 val)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun if (unlikely(asd_ha->iospace))
32*4882a593Smuzhiyun outw(val,
33*4882a593Smuzhiyun (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
34*4882a593Smuzhiyun else
35*4882a593Smuzhiyun writew(val, asd_ha->io_handle[0].addr + offs);
36*4882a593Smuzhiyun wmb();
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun
asd_write_dword(struct asd_ha_struct * asd_ha,unsigned long offs,u32 val)39*4882a593Smuzhiyun static void asd_write_dword(struct asd_ha_struct *asd_ha,
40*4882a593Smuzhiyun unsigned long offs, u32 val)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun if (unlikely(asd_ha->iospace))
43*4882a593Smuzhiyun outl(val,
44*4882a593Smuzhiyun (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
45*4882a593Smuzhiyun else
46*4882a593Smuzhiyun writel(val, asd_ha->io_handle[0].addr + offs);
47*4882a593Smuzhiyun wmb();
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* Reading from device address space.
51*4882a593Smuzhiyun */
asd_read_byte(struct asd_ha_struct * asd_ha,unsigned long offs)52*4882a593Smuzhiyun static u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun u8 val;
55*4882a593Smuzhiyun if (unlikely(asd_ha->iospace))
56*4882a593Smuzhiyun val = inb((unsigned long) asd_ha->io_handle[0].addr
57*4882a593Smuzhiyun + (offs & 0xFF));
58*4882a593Smuzhiyun else
59*4882a593Smuzhiyun val = readb(asd_ha->io_handle[0].addr + offs);
60*4882a593Smuzhiyun rmb();
61*4882a593Smuzhiyun return val;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
asd_read_word(struct asd_ha_struct * asd_ha,unsigned long offs)64*4882a593Smuzhiyun static u16 asd_read_word(struct asd_ha_struct *asd_ha,
65*4882a593Smuzhiyun unsigned long offs)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun u16 val;
68*4882a593Smuzhiyun if (unlikely(asd_ha->iospace))
69*4882a593Smuzhiyun val = inw((unsigned long)asd_ha->io_handle[0].addr
70*4882a593Smuzhiyun + (offs & 0xFF));
71*4882a593Smuzhiyun else
72*4882a593Smuzhiyun val = readw(asd_ha->io_handle[0].addr + offs);
73*4882a593Smuzhiyun rmb();
74*4882a593Smuzhiyun return val;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
asd_read_dword(struct asd_ha_struct * asd_ha,unsigned long offs)77*4882a593Smuzhiyun static u32 asd_read_dword(struct asd_ha_struct *asd_ha,
78*4882a593Smuzhiyun unsigned long offs)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun u32 val;
81*4882a593Smuzhiyun if (unlikely(asd_ha->iospace))
82*4882a593Smuzhiyun val = inl((unsigned long) asd_ha->io_handle[0].addr
83*4882a593Smuzhiyun + (offs & 0xFF));
84*4882a593Smuzhiyun else
85*4882a593Smuzhiyun val = readl(asd_ha->io_handle[0].addr + offs);
86*4882a593Smuzhiyun rmb();
87*4882a593Smuzhiyun return val;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
asd_mem_offs_swa(void)90*4882a593Smuzhiyun static inline u32 asd_mem_offs_swa(void)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun return 0;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
asd_mem_offs_swc(void)95*4882a593Smuzhiyun static inline u32 asd_mem_offs_swc(void)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
asd_mem_offs_swb(void)100*4882a593Smuzhiyun static inline u32 asd_mem_offs_swb(void)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* We know that the register wanted is in the range
106*4882a593Smuzhiyun * of the sliding window.
107*4882a593Smuzhiyun */
108*4882a593Smuzhiyun #define ASD_READ_SW(ww, type, ord) \
109*4882a593Smuzhiyun static type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha, \
110*4882a593Smuzhiyun u32 reg) \
111*4882a593Smuzhiyun { \
112*4882a593Smuzhiyun struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
113*4882a593Smuzhiyun u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
114*4882a593Smuzhiyun return asd_read_##ord(asd_ha, (unsigned long)map_offs); \
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun #define ASD_WRITE_SW(ww, type, ord) \
118*4882a593Smuzhiyun static void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha, \
119*4882a593Smuzhiyun u32 reg, type val) \
120*4882a593Smuzhiyun { \
121*4882a593Smuzhiyun struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
122*4882a593Smuzhiyun u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
123*4882a593Smuzhiyun asd_write_##ord(asd_ha, (unsigned long)map_offs, val); \
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun ASD_READ_SW(swa, u8, byte);
127*4882a593Smuzhiyun ASD_READ_SW(swa, u16, word);
128*4882a593Smuzhiyun ASD_READ_SW(swa, u32, dword);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun ASD_READ_SW(swb, u8, byte);
131*4882a593Smuzhiyun ASD_READ_SW(swb, u16, word);
132*4882a593Smuzhiyun ASD_READ_SW(swb, u32, dword);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun ASD_READ_SW(swc, u8, byte);
135*4882a593Smuzhiyun ASD_READ_SW(swc, u16, word);
136*4882a593Smuzhiyun ASD_READ_SW(swc, u32, dword);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun ASD_WRITE_SW(swa, u8, byte);
139*4882a593Smuzhiyun ASD_WRITE_SW(swa, u16, word);
140*4882a593Smuzhiyun ASD_WRITE_SW(swa, u32, dword);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun ASD_WRITE_SW(swb, u8, byte);
143*4882a593Smuzhiyun ASD_WRITE_SW(swb, u16, word);
144*4882a593Smuzhiyun ASD_WRITE_SW(swb, u32, dword);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun ASD_WRITE_SW(swc, u8, byte);
147*4882a593Smuzhiyun ASD_WRITE_SW(swc, u16, word);
148*4882a593Smuzhiyun ASD_WRITE_SW(swc, u32, dword);
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun * A word about sliding windows:
152*4882a593Smuzhiyun * MBAR0 is divided into sliding windows A, C and B, in that order.
153*4882a593Smuzhiyun * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
154*4882a593Smuzhiyun * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
155*4882a593Smuzhiyun * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
156*4882a593Smuzhiyun * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
157*4882a593Smuzhiyun * See asd_init_sw() in aic94xx_hwi.c
158*4882a593Smuzhiyun *
159*4882a593Smuzhiyun * We map the most common registers we'd access of the internal 4GB
160*4882a593Smuzhiyun * host adapter memory space. If a register/internal memory location
161*4882a593Smuzhiyun * is wanted which is not mapped, we slide SWB, by paging it,
162*4882a593Smuzhiyun * see asd_move_swb() in aic94xx_reg.c.
163*4882a593Smuzhiyun */
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /**
166*4882a593Smuzhiyun * asd_move_swb -- move sliding window B
167*4882a593Smuzhiyun * @asd_ha: pointer to host adapter structure
168*4882a593Smuzhiyun * @reg: register desired to be within range of the new window
169*4882a593Smuzhiyun */
asd_move_swb(struct asd_ha_struct * asd_ha,u32 reg)170*4882a593Smuzhiyun static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun u32 base = reg & ~(MBAR0_SWB_SIZE-1);
173*4882a593Smuzhiyun pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
174*4882a593Smuzhiyun asd_ha->io_handle[0].swb_base = base;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
__asd_write_reg_byte(struct asd_ha_struct * asd_ha,u32 reg,u8 val)177*4882a593Smuzhiyun static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
180*4882a593Smuzhiyun BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
181*4882a593Smuzhiyun if (io_handle->swa_base <= reg
182*4882a593Smuzhiyun && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
183*4882a593Smuzhiyun asd_write_swa_byte (asd_ha, reg,val);
184*4882a593Smuzhiyun else if (io_handle->swb_base <= reg
185*4882a593Smuzhiyun && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
186*4882a593Smuzhiyun asd_write_swb_byte (asd_ha, reg, val);
187*4882a593Smuzhiyun else if (io_handle->swc_base <= reg
188*4882a593Smuzhiyun && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
189*4882a593Smuzhiyun asd_write_swc_byte (asd_ha, reg, val);
190*4882a593Smuzhiyun else {
191*4882a593Smuzhiyun /* Ok, we have to move SWB */
192*4882a593Smuzhiyun asd_move_swb(asd_ha, reg);
193*4882a593Smuzhiyun asd_write_swb_byte (asd_ha, reg, val);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun #define ASD_WRITE_REG(type, ord) \
198*4882a593Smuzhiyun void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
199*4882a593Smuzhiyun { \
200*4882a593Smuzhiyun struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
201*4882a593Smuzhiyun unsigned long flags; \
202*4882a593Smuzhiyun BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
203*4882a593Smuzhiyun spin_lock_irqsave(&asd_ha->iolock, flags); \
204*4882a593Smuzhiyun if (io_handle->swa_base <= reg \
205*4882a593Smuzhiyun && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
206*4882a593Smuzhiyun asd_write_swa_##ord (asd_ha, reg,val); \
207*4882a593Smuzhiyun else if (io_handle->swb_base <= reg \
208*4882a593Smuzhiyun && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
209*4882a593Smuzhiyun asd_write_swb_##ord (asd_ha, reg, val); \
210*4882a593Smuzhiyun else if (io_handle->swc_base <= reg \
211*4882a593Smuzhiyun && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
212*4882a593Smuzhiyun asd_write_swc_##ord (asd_ha, reg, val); \
213*4882a593Smuzhiyun else { \
214*4882a593Smuzhiyun /* Ok, we have to move SWB */ \
215*4882a593Smuzhiyun asd_move_swb(asd_ha, reg); \
216*4882a593Smuzhiyun asd_write_swb_##ord (asd_ha, reg, val); \
217*4882a593Smuzhiyun } \
218*4882a593Smuzhiyun spin_unlock_irqrestore(&asd_ha->iolock, flags); \
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun ASD_WRITE_REG(u8, byte);
222*4882a593Smuzhiyun ASD_WRITE_REG(u16,word);
223*4882a593Smuzhiyun ASD_WRITE_REG(u32,dword);
224*4882a593Smuzhiyun
__asd_read_reg_byte(struct asd_ha_struct * asd_ha,u32 reg)225*4882a593Smuzhiyun static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
228*4882a593Smuzhiyun u8 val;
229*4882a593Smuzhiyun BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
230*4882a593Smuzhiyun if (io_handle->swa_base <= reg
231*4882a593Smuzhiyun && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
232*4882a593Smuzhiyun val = asd_read_swa_byte (asd_ha, reg);
233*4882a593Smuzhiyun else if (io_handle->swb_base <= reg
234*4882a593Smuzhiyun && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
235*4882a593Smuzhiyun val = asd_read_swb_byte (asd_ha, reg);
236*4882a593Smuzhiyun else if (io_handle->swc_base <= reg
237*4882a593Smuzhiyun && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
238*4882a593Smuzhiyun val = asd_read_swc_byte (asd_ha, reg);
239*4882a593Smuzhiyun else {
240*4882a593Smuzhiyun /* Ok, we have to move SWB */
241*4882a593Smuzhiyun asd_move_swb(asd_ha, reg);
242*4882a593Smuzhiyun val = asd_read_swb_byte (asd_ha, reg);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun return val;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun #define ASD_READ_REG(type, ord) \
248*4882a593Smuzhiyun type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \
249*4882a593Smuzhiyun { \
250*4882a593Smuzhiyun struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
251*4882a593Smuzhiyun type val; \
252*4882a593Smuzhiyun unsigned long flags; \
253*4882a593Smuzhiyun BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
254*4882a593Smuzhiyun spin_lock_irqsave(&asd_ha->iolock, flags); \
255*4882a593Smuzhiyun if (io_handle->swa_base <= reg \
256*4882a593Smuzhiyun && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
257*4882a593Smuzhiyun val = asd_read_swa_##ord (asd_ha, reg); \
258*4882a593Smuzhiyun else if (io_handle->swb_base <= reg \
259*4882a593Smuzhiyun && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
260*4882a593Smuzhiyun val = asd_read_swb_##ord (asd_ha, reg); \
261*4882a593Smuzhiyun else if (io_handle->swc_base <= reg \
262*4882a593Smuzhiyun && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
263*4882a593Smuzhiyun val = asd_read_swc_##ord (asd_ha, reg); \
264*4882a593Smuzhiyun else { \
265*4882a593Smuzhiyun /* Ok, we have to move SWB */ \
266*4882a593Smuzhiyun asd_move_swb(asd_ha, reg); \
267*4882a593Smuzhiyun val = asd_read_swb_##ord (asd_ha, reg); \
268*4882a593Smuzhiyun } \
269*4882a593Smuzhiyun spin_unlock_irqrestore(&asd_ha->iolock, flags); \
270*4882a593Smuzhiyun return val; \
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun ASD_READ_REG(u8, byte);
274*4882a593Smuzhiyun ASD_READ_REG(u16,word);
275*4882a593Smuzhiyun ASD_READ_REG(u32,dword);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /**
278*4882a593Smuzhiyun * asd_read_reg_string -- read a string of bytes from io space memory
279*4882a593Smuzhiyun * @asd_ha: pointer to host adapter structure
280*4882a593Smuzhiyun * @dst: pointer to a destination buffer where data will be written to
281*4882a593Smuzhiyun * @offs: start offset (register) to read from
282*4882a593Smuzhiyun * @count: number of bytes to read
283*4882a593Smuzhiyun */
asd_read_reg_string(struct asd_ha_struct * asd_ha,void * dst,u32 offs,int count)284*4882a593Smuzhiyun void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
285*4882a593Smuzhiyun u32 offs, int count)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun u8 *p = dst;
288*4882a593Smuzhiyun unsigned long flags;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun spin_lock_irqsave(&asd_ha->iolock, flags);
291*4882a593Smuzhiyun for ( ; count > 0; count--, offs++, p++)
292*4882a593Smuzhiyun *p = __asd_read_reg_byte(asd_ha, offs);
293*4882a593Smuzhiyun spin_unlock_irqrestore(&asd_ha->iolock, flags);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /**
297*4882a593Smuzhiyun * asd_write_reg_string -- write a string of bytes to io space memory
298*4882a593Smuzhiyun * @asd_ha: pointer to host adapter structure
299*4882a593Smuzhiyun * @src: pointer to source buffer where data will be read from
300*4882a593Smuzhiyun * @offs: start offset (register) to write to
301*4882a593Smuzhiyun * @count: number of bytes to write
302*4882a593Smuzhiyun */
asd_write_reg_string(struct asd_ha_struct * asd_ha,void * src,u32 offs,int count)303*4882a593Smuzhiyun void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
304*4882a593Smuzhiyun u32 offs, int count)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun u8 *p = src;
307*4882a593Smuzhiyun unsigned long flags;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun spin_lock_irqsave(&asd_ha->iolock, flags);
310*4882a593Smuzhiyun for ( ; count > 0; count--, offs++, p++)
311*4882a593Smuzhiyun __asd_write_reg_byte(asd_ha, offs, *p);
312*4882a593Smuzhiyun spin_unlock_irqrestore(&asd_ha->iolock, flags);
313*4882a593Smuzhiyun }
314