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>
This commit is contained in:
parent
5f985d88ba
commit
c56f5f1de3
|
@ -330,6 +330,51 @@ static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
|
|||
mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
|
||||
}
|
||||
|
||||
static void mvs_94xx_sgpio_init(struct mvs_info *mvi)
|
||||
{
|
||||
void __iomem *regs = mvi->regs_ex - 0x10200;
|
||||
u32 tmp;
|
||||
|
||||
tmp = mr32(MVS_HST_CHIP_CONFIG);
|
||||
tmp |= 0x100;
|
||||
mw32(MVS_HST_CHIP_CONFIG, tmp);
|
||||
|
||||
mw32(MVS_SGPIO_CTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
|
||||
MVS_SGPIO_CTRL_SDOUT_AUTO << MVS_SGPIO_CTRL_SDOUT_SHIFT);
|
||||
|
||||
mw32(MVS_SGPIO_CFG1 + MVS_SGPIO_HOST_OFFSET * mvi->id,
|
||||
8 << MVS_SGPIO_CFG1_LOWA_SHIFT |
|
||||
8 << MVS_SGPIO_CFG1_HIA_SHIFT |
|
||||
4 << MVS_SGPIO_CFG1_LOWB_SHIFT |
|
||||
4 << MVS_SGPIO_CFG1_HIB_SHIFT |
|
||||
2 << MVS_SGPIO_CFG1_MAXACTON_SHIFT |
|
||||
1 << MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT
|
||||
);
|
||||
|
||||
mw32(MVS_SGPIO_CFG2 + MVS_SGPIO_HOST_OFFSET * mvi->id,
|
||||
(300000 / 100) << MVS_SGPIO_CFG2_CLK_SHIFT | /* 100kHz clock */
|
||||
66 << MVS_SGPIO_CFG2_BLINK_SHIFT /* (66 * 0,121 Hz?)*/
|
||||
);
|
||||
|
||||
mw32(MVS_SGPIO_CFG0 + MVS_SGPIO_HOST_OFFSET * mvi->id,
|
||||
MVS_SGPIO_CFG0_ENABLE |
|
||||
MVS_SGPIO_CFG0_BLINKA |
|
||||
MVS_SGPIO_CFG0_BLINKB |
|
||||
/* 3*4 data bits / PDU */
|
||||
(12 - 1) << MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT
|
||||
);
|
||||
|
||||
mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
|
||||
DEFAULT_SGPIO_BITS);
|
||||
|
||||
mw32(MVS_SGPIO_DSRC + MVS_SGPIO_HOST_OFFSET * mvi->id,
|
||||
((mvi->id * 4) + 3) << (8 * 3) |
|
||||
((mvi->id * 4) + 2) << (8 * 2) |
|
||||
((mvi->id * 4) + 1) << (8 * 1) |
|
||||
((mvi->id * 4) + 0) << (8 * 0));
|
||||
|
||||
}
|
||||
|
||||
static int mvs_94xx_init(struct mvs_info *mvi)
|
||||
{
|
||||
void __iomem *regs = mvi->regs;
|
||||
|
@ -533,6 +578,8 @@ static int mvs_94xx_init(struct mvs_info *mvi)
|
|||
/* Enable SRS interrupt */
|
||||
mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
|
||||
|
||||
mvs_94xx_sgpio_init(mvi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1005,6 +1052,92 @@ static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
|
|||
|
||||
}
|
||||
|
||||
static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
|
||||
u8 reg_type, u8 reg_index,
|
||||
u8 reg_count, u8 *write_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (reg_type) {
|
||||
|
||||
case SAS_GPIO_REG_TX_GP:
|
||||
if (reg_index == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (reg_count > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (reg_count == 0)
|
||||
return 0;
|
||||
|
||||
/* maximum supported bits = hosts * 4 drives * 3 bits */
|
||||
for (i = 0; i < mvs_prv->n_host * 4 * 3; i++) {
|
||||
|
||||
/* select host */
|
||||
struct mvs_info *mvi = mvs_prv->mvi[i/(4*3)];
|
||||
|
||||
void __iomem *regs = mvi->regs_ex - 0x10200;
|
||||
|
||||
int drive = (i/3) & (4-1); /* drive number on host */
|
||||
u32 block = mr32(MVS_SGPIO_DCTRL +
|
||||
MVS_SGPIO_HOST_OFFSET * mvi->id);
|
||||
|
||||
|
||||
/*
|
||||
* if bit is set then create a mask with the first
|
||||
* bit of the drive set in the mask ...
|
||||
*/
|
||||
u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ?
|
||||
1<<(24-drive*8) : 0;
|
||||
|
||||
/*
|
||||
* ... and then shift it to the right position based
|
||||
* on the led type (activity/id/fail)
|
||||
*/
|
||||
switch (i%3) {
|
||||
case 0: /* activity */
|
||||
block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT)
|
||||
<< (24-drive*8));
|
||||
/* hardwire activity bit to SOF */
|
||||
block |= LED_BLINKA_SOF << (
|
||||
MVS_SGPIO_DCTRL_ACT_SHIFT +
|
||||
(24-drive*8));
|
||||
break;
|
||||
case 1: /* id */
|
||||
block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT)
|
||||
<< (24-drive*8));
|
||||
block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT;
|
||||
break;
|
||||
case 2: /* fail */
|
||||
block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT)
|
||||
<< (24-drive*8));
|
||||
block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT;
|
||||
break;
|
||||
}
|
||||
|
||||
mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
|
||||
block);
|
||||
|
||||
}
|
||||
|
||||
return reg_count;
|
||||
|
||||
case SAS_GPIO_REG_TX:
|
||||
if (reg_index + reg_count > mvs_prv->n_host)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < reg_count; i++) {
|
||||
struct mvs_info *mvi = mvs_prv->mvi[i+reg_index];
|
||||
void __iomem *regs = mvi->regs_ex - 0x10200;
|
||||
|
||||
mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
|
||||
be32_to_cpu(((u32 *) write_data)[i]));
|
||||
}
|
||||
return reg_count;
|
||||
}
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
const struct mvs_dispatch mvs_94xx_dispatch = {
|
||||
"mv94xx",
|
||||
mvs_94xx_init,
|
||||
|
@ -1057,5 +1190,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
|
|||
mvs_94xx_fix_dma,
|
||||
mvs_94xx_tune_interrupt,
|
||||
mvs_94xx_non_spec_ncq_error,
|
||||
mvs_94xx_gpio_write,
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,10 @@ enum VANIR_REVISION_ID {
|
|||
VANIR_C2_REV = 0xC2,
|
||||
};
|
||||
|
||||
enum host_registers {
|
||||
MVS_HST_CHIP_CONFIG = 0x10104, /* chip configuration */
|
||||
};
|
||||
|
||||
enum hw_registers {
|
||||
MVS_GBL_CTL = 0x04, /* global control */
|
||||
MVS_GBL_INT_STAT = 0x00, /* global irq status */
|
||||
|
@ -239,6 +243,73 @@ struct mvs_prd {
|
|||
__le32 im_len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum sgpio_registers {
|
||||
MVS_SGPIO_HOST_OFFSET = 0x100, /* offset between hosts */
|
||||
|
||||
MVS_SGPIO_CFG0 = 0xc200,
|
||||
MVS_SGPIO_CFG0_ENABLE = (1 << 0), /* enable pins */
|
||||
MVS_SGPIO_CFG0_BLINKB = (1 << 1), /* blink generators */
|
||||
MVS_SGPIO_CFG0_BLINKA = (1 << 2),
|
||||
MVS_SGPIO_CFG0_INVSCLK = (1 << 3), /* invert signal? */
|
||||
MVS_SGPIO_CFG0_INVSLOAD = (1 << 4),
|
||||
MVS_SGPIO_CFG0_INVSDOUT = (1 << 5),
|
||||
MVS_SGPIO_CFG0_SLOAD_FALLEDGE = (1 << 6), /* rise/fall edge? */
|
||||
MVS_SGPIO_CFG0_SDOUT_FALLEDGE = (1 << 7),
|
||||
MVS_SGPIO_CFG0_SDIN_RISEEDGE = (1 << 8),
|
||||
MVS_SGPIO_CFG0_MAN_BITLEN_SHIFT = 18, /* bits/frame manual mode */
|
||||
MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT = 24, /* bits/frame auto mode */
|
||||
|
||||
MVS_SGPIO_CFG1 = 0xc204, /* blink timing register */
|
||||
MVS_SGPIO_CFG1_LOWA_SHIFT = 0, /* A off time */
|
||||
MVS_SGPIO_CFG1_HIA_SHIFT = 4, /* A on time */
|
||||
MVS_SGPIO_CFG1_LOWB_SHIFT = 8, /* B off time */
|
||||
MVS_SGPIO_CFG1_HIB_SHIFT = 12, /* B on time */
|
||||
MVS_SGPIO_CFG1_MAXACTON_SHIFT = 16, /* max activity on time */
|
||||
|
||||
/* force activity off time */
|
||||
MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT = 20,
|
||||
/* stretch activity on time */
|
||||
MVS_SGPIO_CFG1_STRCHACTON_SHIFT = 24,
|
||||
/* stretch activiity off time */
|
||||
MVS_SGPIO_CFG1_STRCHACTOFF_SHIFT = 28,
|
||||
|
||||
|
||||
MVS_SGPIO_CFG2 = 0xc208, /* clock speed register */
|
||||
MVS_SGPIO_CFG2_CLK_SHIFT = 0,
|
||||
MVS_SGPIO_CFG2_BLINK_SHIFT = 20,
|
||||
|
||||
MVS_SGPIO_CTRL = 0xc20c, /* SDOUT/SDIN mode control */
|
||||
MVS_SGPIO_CTRL_SDOUT_AUTO = 2,
|
||||
MVS_SGPIO_CTRL_SDOUT_SHIFT = 2,
|
||||
|
||||
MVS_SGPIO_DSRC = 0xc220, /* map ODn bits to drives */
|
||||
|
||||
MVS_SGPIO_DCTRL = 0xc238,
|
||||
MVS_SGPIO_DCTRL_ERR_SHIFT = 0,
|
||||
MVS_SGPIO_DCTRL_LOC_SHIFT = 3,
|
||||
MVS_SGPIO_DCTRL_ACT_SHIFT = 5,
|
||||
};
|
||||
|
||||
enum sgpio_led_status {
|
||||
LED_OFF = 0,
|
||||
LED_ON = 1,
|
||||
LED_BLINKA = 2,
|
||||
LED_BLINKA_INV = 3,
|
||||
LED_BLINKA_SOF = 4,
|
||||
LED_BLINKA_EOF = 5,
|
||||
LED_BLINKB = 6,
|
||||
LED_BLINKB_INV = 7,
|
||||
};
|
||||
|
||||
#define DEFAULT_SGPIO_BITS ((LED_BLINKA_SOF << \
|
||||
MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 3) | \
|
||||
(LED_BLINKA_SOF << \
|
||||
MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 2) | \
|
||||
(LED_BLINKA_SOF << \
|
||||
MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 1) | \
|
||||
(LED_BLINKA_SOF << \
|
||||
MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 0))
|
||||
|
||||
/*
|
||||
* these registers are accessed through port vendor
|
||||
* specific address/data registers
|
||||
|
|
|
@ -84,6 +84,8 @@ static struct sas_domain_function_template mvs_transport_ops = {
|
|||
.lldd_port_formed = mvs_port_formed,
|
||||
.lldd_port_deformed = mvs_port_deformed,
|
||||
|
||||
.lldd_write_gpio = mvs_gpio_write,
|
||||
|
||||
};
|
||||
|
||||
static void mvs_phy_init(struct mvs_info *mvi, int phy_id)
|
||||
|
|
|
@ -2105,3 +2105,16 @@ int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mvs_gpio_write(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index,
|
||||
u8 reg_count, u8 *write_data)
|
||||
{
|
||||
struct mvs_prv_info *mvs_prv = sha->lldd_ha;
|
||||
struct mvs_info *mvi = mvs_prv->mvi[0];
|
||||
|
||||
if (MVS_CHIP_DISP->gpio_write) {
|
||||
return MVS_CHIP_DISP->gpio_write(mvs_prv, reg_type,
|
||||
reg_index, reg_count, write_data);
|
||||
}
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ enum dev_reset {
|
|||
};
|
||||
|
||||
struct mvs_info;
|
||||
struct mvs_prv_info;
|
||||
|
||||
struct mvs_dispatch {
|
||||
char *name;
|
||||
|
@ -172,6 +173,8 @@ struct mvs_dispatch {
|
|||
int buf_len, int from, void *prd);
|
||||
void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
|
||||
void (*non_spec_ncq_error)(struct mvs_info *mvi);
|
||||
int (*gpio_write)(struct mvs_prv_info *mvs_prv, u8 reg_type,
|
||||
u8 reg_index, u8 reg_count, u8 *write_data);
|
||||
|
||||
};
|
||||
|
||||
|
@ -476,5 +479,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
|
|||
void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
|
||||
int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
|
||||
struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
|
||||
int mvs_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index,
|
||||
u8 reg_count, u8 *write_data);
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue