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:
Wilfried Weissmann 2015-12-27 20:21:19 +01:00 committed by Martin K. Petersen
parent 5f985d88ba
commit c56f5f1de3
5 changed files with 225 additions and 0 deletions

View File

@ -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,
};

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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