Skip to content

Commit c56f5f1

Browse files
Wilfried Weissmannmartinkpetersen
authored andcommitted
mvsas: Add SGPIO support to Marvell 94xx
Add SGPIO support to Marvell 94xx. Signed-off-by: Wilfried Weissmann <Wilfried.Weissmann@gmx.at> Reviewed-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 5f985d8 commit c56f5f1

File tree

5 files changed

+225
-0
lines changed

5 files changed

+225
-0
lines changed

drivers/scsi/mvsas/mv_94xx.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,51 @@ static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
330330
mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
331331
}
332332

333+
static void mvs_94xx_sgpio_init(struct mvs_info *mvi)
334+
{
335+
void __iomem *regs = mvi->regs_ex - 0x10200;
336+
u32 tmp;
337+
338+
tmp = mr32(MVS_HST_CHIP_CONFIG);
339+
tmp |= 0x100;
340+
mw32(MVS_HST_CHIP_CONFIG, tmp);
341+
342+
mw32(MVS_SGPIO_CTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
343+
MVS_SGPIO_CTRL_SDOUT_AUTO << MVS_SGPIO_CTRL_SDOUT_SHIFT);
344+
345+
mw32(MVS_SGPIO_CFG1 + MVS_SGPIO_HOST_OFFSET * mvi->id,
346+
8 << MVS_SGPIO_CFG1_LOWA_SHIFT |
347+
8 << MVS_SGPIO_CFG1_HIA_SHIFT |
348+
4 << MVS_SGPIO_CFG1_LOWB_SHIFT |
349+
4 << MVS_SGPIO_CFG1_HIB_SHIFT |
350+
2 << MVS_SGPIO_CFG1_MAXACTON_SHIFT |
351+
1 << MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT
352+
);
353+
354+
mw32(MVS_SGPIO_CFG2 + MVS_SGPIO_HOST_OFFSET * mvi->id,
355+
(300000 / 100) << MVS_SGPIO_CFG2_CLK_SHIFT | /* 100kHz clock */
356+
66 << MVS_SGPIO_CFG2_BLINK_SHIFT /* (66 * 0,121 Hz?)*/
357+
);
358+
359+
mw32(MVS_SGPIO_CFG0 + MVS_SGPIO_HOST_OFFSET * mvi->id,
360+
MVS_SGPIO_CFG0_ENABLE |
361+
MVS_SGPIO_CFG0_BLINKA |
362+
MVS_SGPIO_CFG0_BLINKB |
363+
/* 3*4 data bits / PDU */
364+
(12 - 1) << MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT
365+
);
366+
367+
mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
368+
DEFAULT_SGPIO_BITS);
369+
370+
mw32(MVS_SGPIO_DSRC + MVS_SGPIO_HOST_OFFSET * mvi->id,
371+
((mvi->id * 4) + 3) << (8 * 3) |
372+
((mvi->id * 4) + 2) << (8 * 2) |
373+
((mvi->id * 4) + 1) << (8 * 1) |
374+
((mvi->id * 4) + 0) << (8 * 0));
375+
376+
}
377+
333378
static int mvs_94xx_init(struct mvs_info *mvi)
334379
{
335380
void __iomem *regs = mvi->regs;
@@ -533,6 +578,8 @@ static int mvs_94xx_init(struct mvs_info *mvi)
533578
/* Enable SRS interrupt */
534579
mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
535580

581+
mvs_94xx_sgpio_init(mvi);
582+
536583
return 0;
537584
}
538585

@@ -1005,6 +1052,92 @@ static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
10051052

10061053
}
10071054

1055+
static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
1056+
u8 reg_type, u8 reg_index,
1057+
u8 reg_count, u8 *write_data)
1058+
{
1059+
int i;
1060+
1061+
switch (reg_type) {
1062+
1063+
case SAS_GPIO_REG_TX_GP:
1064+
if (reg_index == 0)
1065+
return -EINVAL;
1066+
1067+
if (reg_count > 1)
1068+
return -EINVAL;
1069+
1070+
if (reg_count == 0)
1071+
return 0;
1072+
1073+
/* maximum supported bits = hosts * 4 drives * 3 bits */
1074+
for (i = 0; i < mvs_prv->n_host * 4 * 3; i++) {
1075+
1076+
/* select host */
1077+
struct mvs_info *mvi = mvs_prv->mvi[i/(4*3)];
1078+
1079+
void __iomem *regs = mvi->regs_ex - 0x10200;
1080+
1081+
int drive = (i/3) & (4-1); /* drive number on host */
1082+
u32 block = mr32(MVS_SGPIO_DCTRL +
1083+
MVS_SGPIO_HOST_OFFSET * mvi->id);
1084+
1085+
1086+
/*
1087+
* if bit is set then create a mask with the first
1088+
* bit of the drive set in the mask ...
1089+
*/
1090+
u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ?
1091+
1<<(24-drive*8) : 0;
1092+
1093+
/*
1094+
* ... and then shift it to the right position based
1095+
* on the led type (activity/id/fail)
1096+
*/
1097+
switch (i%3) {
1098+
case 0: /* activity */
1099+
block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT)
1100+
<< (24-drive*8));
1101+
/* hardwire activity bit to SOF */
1102+
block |= LED_BLINKA_SOF << (
1103+
MVS_SGPIO_DCTRL_ACT_SHIFT +
1104+
(24-drive*8));
1105+
break;
1106+
case 1: /* id */
1107+
block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT)
1108+
<< (24-drive*8));
1109+
block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT;
1110+
break;
1111+
case 2: /* fail */
1112+
block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT)
1113+
<< (24-drive*8));
1114+
block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT;
1115+
break;
1116+
}
1117+
1118+
mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
1119+
block);
1120+
1121+
}
1122+
1123+
return reg_count;
1124+
1125+
case SAS_GPIO_REG_TX:
1126+
if (reg_index + reg_count > mvs_prv->n_host)
1127+
return -EINVAL;
1128+
1129+
for (i = 0; i < reg_count; i++) {
1130+
struct mvs_info *mvi = mvs_prv->mvi[i+reg_index];
1131+
void __iomem *regs = mvi->regs_ex - 0x10200;
1132+
1133+
mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
1134+
be32_to_cpu(((u32 *) write_data)[i]));
1135+
}
1136+
return reg_count;
1137+
}
1138+
return -ENOSYS;
1139+
}
1140+
10081141
const struct mvs_dispatch mvs_94xx_dispatch = {
10091142
"mv94xx",
10101143
mvs_94xx_init,
@@ -1057,5 +1190,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
10571190
mvs_94xx_fix_dma,
10581191
mvs_94xx_tune_interrupt,
10591192
mvs_94xx_non_spec_ncq_error,
1193+
mvs_94xx_gpio_write,
10601194
};
10611195

drivers/scsi/mvsas/mv_94xx.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ enum VANIR_REVISION_ID {
3838
VANIR_C2_REV = 0xC2,
3939
};
4040

41+
enum host_registers {
42+
MVS_HST_CHIP_CONFIG = 0x10104, /* chip configuration */
43+
};
44+
4145
enum hw_registers {
4246
MVS_GBL_CTL = 0x04, /* global control */
4347
MVS_GBL_INT_STAT = 0x00, /* global irq status */
@@ -239,6 +243,73 @@ struct mvs_prd {
239243
__le32 im_len;
240244
} __attribute__ ((packed));
241245

246+
enum sgpio_registers {
247+
MVS_SGPIO_HOST_OFFSET = 0x100, /* offset between hosts */
248+
249+
MVS_SGPIO_CFG0 = 0xc200,
250+
MVS_SGPIO_CFG0_ENABLE = (1 << 0), /* enable pins */
251+
MVS_SGPIO_CFG0_BLINKB = (1 << 1), /* blink generators */
252+
MVS_SGPIO_CFG0_BLINKA = (1 << 2),
253+
MVS_SGPIO_CFG0_INVSCLK = (1 << 3), /* invert signal? */
254+
MVS_SGPIO_CFG0_INVSLOAD = (1 << 4),
255+
MVS_SGPIO_CFG0_INVSDOUT = (1 << 5),
256+
MVS_SGPIO_CFG0_SLOAD_FALLEDGE = (1 << 6), /* rise/fall edge? */
257+
MVS_SGPIO_CFG0_SDOUT_FALLEDGE = (1 << 7),
258+
MVS_SGPIO_CFG0_SDIN_RISEEDGE = (1 << 8),
259+
MVS_SGPIO_CFG0_MAN_BITLEN_SHIFT = 18, /* bits/frame manual mode */
260+
MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT = 24, /* bits/frame auto mode */
261+
262+
MVS_SGPIO_CFG1 = 0xc204, /* blink timing register */
263+
MVS_SGPIO_CFG1_LOWA_SHIFT = 0, /* A off time */
264+
MVS_SGPIO_CFG1_HIA_SHIFT = 4, /* A on time */
265+
MVS_SGPIO_CFG1_LOWB_SHIFT = 8, /* B off time */
266+
MVS_SGPIO_CFG1_HIB_SHIFT = 12, /* B on time */
267+
MVS_SGPIO_CFG1_MAXACTON_SHIFT = 16, /* max activity on time */
268+
269+
/* force activity off time */
270+
MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT = 20,
271+
/* stretch activity on time */
272+
MVS_SGPIO_CFG1_STRCHACTON_SHIFT = 24,
273+
/* stretch activiity off time */
274+
MVS_SGPIO_CFG1_STRCHACTOFF_SHIFT = 28,
275+
276+
277+
MVS_SGPIO_CFG2 = 0xc208, /* clock speed register */
278+
MVS_SGPIO_CFG2_CLK_SHIFT = 0,
279+
MVS_SGPIO_CFG2_BLINK_SHIFT = 20,
280+
281+
MVS_SGPIO_CTRL = 0xc20c, /* SDOUT/SDIN mode control */
282+
MVS_SGPIO_CTRL_SDOUT_AUTO = 2,
283+
MVS_SGPIO_CTRL_SDOUT_SHIFT = 2,
284+
285+
MVS_SGPIO_DSRC = 0xc220, /* map ODn bits to drives */
286+
287+
MVS_SGPIO_DCTRL = 0xc238,
288+
MVS_SGPIO_DCTRL_ERR_SHIFT = 0,
289+
MVS_SGPIO_DCTRL_LOC_SHIFT = 3,
290+
MVS_SGPIO_DCTRL_ACT_SHIFT = 5,
291+
};
292+
293+
enum sgpio_led_status {
294+
LED_OFF = 0,
295+
LED_ON = 1,
296+
LED_BLINKA = 2,
297+
LED_BLINKA_INV = 3,
298+
LED_BLINKA_SOF = 4,
299+
LED_BLINKA_EOF = 5,
300+
LED_BLINKB = 6,
301+
LED_BLINKB_INV = 7,
302+
};
303+
304+
#define DEFAULT_SGPIO_BITS ((LED_BLINKA_SOF << \
305+
MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 3) | \
306+
(LED_BLINKA_SOF << \
307+
MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 2) | \
308+
(LED_BLINKA_SOF << \
309+
MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 1) | \
310+
(LED_BLINKA_SOF << \
311+
MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 0))
312+
242313
/*
243314
* these registers are accessed through port vendor
244315
* specific address/data registers

drivers/scsi/mvsas/mv_init.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ static struct sas_domain_function_template mvs_transport_ops = {
8484
.lldd_port_formed = mvs_port_formed,
8585
.lldd_port_deformed = mvs_port_deformed,
8686

87+
.lldd_write_gpio = mvs_gpio_write,
88+
8789
};
8890

8991
static void mvs_phy_init(struct mvs_info *mvi, int phy_id)

drivers/scsi/mvsas/mv_sas.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,3 +2105,16 @@ int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
21052105
return 0;
21062106
}
21072107

2108+
int mvs_gpio_write(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index,
2109+
u8 reg_count, u8 *write_data)
2110+
{
2111+
struct mvs_prv_info *mvs_prv = sha->lldd_ha;
2112+
struct mvs_info *mvi = mvs_prv->mvi[0];
2113+
2114+
if (MVS_CHIP_DISP->gpio_write) {
2115+
return MVS_CHIP_DISP->gpio_write(mvs_prv, reg_type,
2116+
reg_index, reg_count, write_data);
2117+
}
2118+
2119+
return -ENOSYS;
2120+
}

drivers/scsi/mvsas/mv_sas.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ enum dev_reset {
103103
};
104104

105105
struct mvs_info;
106+
struct mvs_prv_info;
106107

107108
struct mvs_dispatch {
108109
char *name;
@@ -172,6 +173,8 @@ struct mvs_dispatch {
172173
int buf_len, int from, void *prd);
173174
void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
174175
void (*non_spec_ncq_error)(struct mvs_info *mvi);
176+
int (*gpio_write)(struct mvs_prv_info *mvs_prv, u8 reg_type,
177+
u8 reg_index, u8 reg_count, u8 *write_data);
175178

176179
};
177180

@@ -476,5 +479,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
476479
void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
477480
int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
478481
struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
482+
int mvs_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index,
483+
u8 reg_count, u8 *write_data);
479484
#endif
480485

0 commit comments

Comments
 (0)