Message ID | 20180301204444.GA16781@xps13.dannf |
---|---|
State | New |
Headers | show |
Series | [Bionic,SRU,Artful] scsi: hisi_sas: directly attached disk LED feature for v2 hw | expand |
On 03/01/18 21:44, dann frazier wrote: > From: Xiaofei Tan <tanxiaofei@huawei.com> > > BugLink: https://bugs.launchpad.net/bugs/1752695 > > This patch implements LED feature of directly attached disk for v2 hw. > As libsas has provided an interface lldd_write_gpio() for this feature, > we just need realise the interface following SPGIO API. > > We use an CPLD to finish the hardware part of this feature, and the base > address of CPLD should be configured through ACPI or DT tables. > > Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com> > Signed-off-by: John Garry <john.garry@huawei.com> > Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> > (backported from commit 6379c56070b9ee32ae2b3efa51e121242042e72d) > [ dannf: trivial offset adjustment ] > Signed-off-by: dann frazier <dann.frazier@canonical.com> > --- > drivers/scsi/hisi_sas/hisi_sas.h | 3 +++ > drivers/scsi/hisi_sas/hisi_sas_main.c | 20 +++++++++++++++++ > drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 39 ++++++++++++++++++++++++++++++++++ > 3 files changed, 62 insertions(+) > > diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h > index 83357b0367d8..26882f583109 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas.h > +++ b/drivers/scsi/hisi_sas/hisi_sas.h > @@ -212,6 +212,8 @@ struct hisi_sas_hw { > struct domain_device *device); > int (*soft_reset)(struct hisi_hba *hisi_hba); > u32 (*get_phys_state)(struct hisi_hba *hisi_hba); > + int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data); > int max_command_entries; > int complete_hdr_size; > }; > @@ -225,6 +227,7 @@ struct hisi_hba { > struct device *dev; > > void __iomem *regs; > + void __iomem *sgpio_regs; > struct regmap *ctrl; > u32 ctrl_reset_reg; > u32 ctrl_reset_sts_reg; > diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c > index b5ce64a42660..632a288ab34d 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas_main.c > +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c > @@ -1507,6 +1507,18 @@ static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) > hisi_sas_port_notify_formed(sas_phy); > } > > +static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data) > +{ > + struct hisi_hba *hisi_hba = sha->lldd_ha; > + > + if (!hisi_hba->hw->write_gpio) > + return -EOPNOTSUPP; > + > + return hisi_hba->hw->write_gpio(hisi_hba, reg_type, > + reg_index, reg_count, write_data); > +} > + > static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy) > { > phy->phy_attached = 0; > @@ -1603,6 +1615,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { > .lldd_query_task = hisi_sas_query_task, > .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, > .lldd_port_formed = hisi_sas_port_formed, > + .lldd_write_gpio = hisi_sas_write_gpio, > }; > > void hisi_sas_init_mem(struct hisi_hba *hisi_hba) > @@ -1915,6 +1928,13 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, > if (IS_ERR(hisi_hba->regs)) > goto err_out; > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); > + if (res) { > + hisi_hba->sgpio_regs = devm_ioremap_resource(dev, res); > + if (IS_ERR(hisi_hba->sgpio_regs)) > + goto err_out; > + } > + > if (hisi_sas_alloc(hisi_hba, shost)) { > hisi_sas_free(hisi_hba); > goto err_out; > diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > index 5d3467fd728d..c19f4f67c71e 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > @@ -3408,6 +3408,44 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) > return 0; > } > > +static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data) > +{ > + struct device *dev = hisi_hba->dev; > + int phy_no, count; > + > + if (!hisi_hba->sgpio_regs) > + return -EOPNOTSUPP; > + > + switch (reg_type) { > + case SAS_GPIO_REG_TX: > + count = reg_count * 4; > + count = min(count, hisi_hba->n_phy); > + > + for (phy_no = 0; phy_no < count; phy_no++) { > + /* > + * GPIO_TX[n] register has the highest numbered drive > + * of the four in the first byte and the lowest > + * numbered drive in the fourth byte. > + * See SFF-8485 Rev. 0.7 Table 24. > + */ > + void __iomem *reg_addr = hisi_hba->sgpio_regs + > + reg_index * 4 + phy_no; > + int data_idx = phy_no + 3 - (phy_no % 4) * 2; > + > + writeb(write_data[data_idx], reg_addr); > + } > + > + break; > + default: > + dev_err(dev, "write gpio: unsupported or bad reg type %d\n", > + reg_type); > + return -EINVAL; > + } > + > + return 0; > +} > + > static const struct hisi_sas_hw hisi_sas_v2_hw = { > .hw_init = hisi_sas_v2_init, > .setup_itct = setup_itct_v2_hw, > @@ -3434,6 +3472,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { > .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr), > .soft_reset = soft_reset_v2_hw, > .get_phys_state = get_phys_state_v2_hw, > + .write_gpio = write_gpio_v2_hw, > }; > > static int hisi_sas_v2_probe(struct platform_device *pdev) > Limited to a specific driver, the change looks good to me. Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
On 01.03.2018 21:44, dann frazier wrote: > From: Xiaofei Tan <tanxiaofei@huawei.com> > > BugLink: https://bugs.launchpad.net/bugs/1752695 > > This patch implements LED feature of directly attached disk for v2 hw. > As libsas has provided an interface lldd_write_gpio() for this feature, > we just need realise the interface following SPGIO API. > > We use an CPLD to finish the hardware part of this feature, and the base > address of CPLD should be configured through ACPI or DT tables. > > Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com> > Signed-off-by: John Garry <john.garry@huawei.com> > Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> > (backported from commit 6379c56070b9ee32ae2b3efa51e121242042e72d) > [ dannf: trivial offset adjustment ] > Signed-off-by: dann frazier <dann.frazier@canonical.com> Acked-by: Stefan Bader <stefan.bader@canonical.com> > --- > drivers/scsi/hisi_sas/hisi_sas.h | 3 +++ > drivers/scsi/hisi_sas/hisi_sas_main.c | 20 +++++++++++++++++ > drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 39 ++++++++++++++++++++++++++++++++++ > 3 files changed, 62 insertions(+) > > diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h > index 83357b0367d8..26882f583109 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas.h > +++ b/drivers/scsi/hisi_sas/hisi_sas.h > @@ -212,6 +212,8 @@ struct hisi_sas_hw { > struct domain_device *device); > int (*soft_reset)(struct hisi_hba *hisi_hba); > u32 (*get_phys_state)(struct hisi_hba *hisi_hba); > + int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data); > int max_command_entries; > int complete_hdr_size; > }; > @@ -225,6 +227,7 @@ struct hisi_hba { > struct device *dev; > > void __iomem *regs; > + void __iomem *sgpio_regs; > struct regmap *ctrl; > u32 ctrl_reset_reg; > u32 ctrl_reset_sts_reg; > diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c > index b5ce64a42660..632a288ab34d 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas_main.c > +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c > @@ -1507,6 +1507,18 @@ static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) > hisi_sas_port_notify_formed(sas_phy); > } > > +static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data) > +{ > + struct hisi_hba *hisi_hba = sha->lldd_ha; > + > + if (!hisi_hba->hw->write_gpio) > + return -EOPNOTSUPP; > + > + return hisi_hba->hw->write_gpio(hisi_hba, reg_type, > + reg_index, reg_count, write_data); > +} > + > static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy) > { > phy->phy_attached = 0; > @@ -1603,6 +1615,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { > .lldd_query_task = hisi_sas_query_task, > .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, > .lldd_port_formed = hisi_sas_port_formed, > + .lldd_write_gpio = hisi_sas_write_gpio, > }; > > void hisi_sas_init_mem(struct hisi_hba *hisi_hba) > @@ -1915,6 +1928,13 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, > if (IS_ERR(hisi_hba->regs)) > goto err_out; > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); > + if (res) { > + hisi_hba->sgpio_regs = devm_ioremap_resource(dev, res); > + if (IS_ERR(hisi_hba->sgpio_regs)) > + goto err_out; > + } > + > if (hisi_sas_alloc(hisi_hba, shost)) { > hisi_sas_free(hisi_hba); > goto err_out; > diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > index 5d3467fd728d..c19f4f67c71e 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > @@ -3408,6 +3408,44 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) > return 0; > } > > +static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data) > +{ > + struct device *dev = hisi_hba->dev; > + int phy_no, count; > + > + if (!hisi_hba->sgpio_regs) > + return -EOPNOTSUPP; > + > + switch (reg_type) { > + case SAS_GPIO_REG_TX: > + count = reg_count * 4; > + count = min(count, hisi_hba->n_phy); > + > + for (phy_no = 0; phy_no < count; phy_no++) { > + /* > + * GPIO_TX[n] register has the highest numbered drive > + * of the four in the first byte and the lowest > + * numbered drive in the fourth byte. > + * See SFF-8485 Rev. 0.7 Table 24. > + */ > + void __iomem *reg_addr = hisi_hba->sgpio_regs + > + reg_index * 4 + phy_no; > + int data_idx = phy_no + 3 - (phy_no % 4) * 2; > + > + writeb(write_data[data_idx], reg_addr); > + } > + > + break; > + default: > + dev_err(dev, "write gpio: unsupported or bad reg type %d\n", > + reg_type); > + return -EINVAL; > + } > + > + return 0; > +} > + > static const struct hisi_sas_hw hisi_sas_v2_hw = { > .hw_init = hisi_sas_v2_init, > .setup_itct = setup_itct_v2_hw, > @@ -3434,6 +3472,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { > .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr), > .soft_reset = soft_reset_v2_hw, > .get_phys_state = get_phys_state_v2_hw, > + .write_gpio = write_gpio_v2_hw, > }; > > static int hisi_sas_v2_probe(struct platform_device *pdev) >
On 03/01/18 21:44, dann frazier wrote: > From: Xiaofei Tan <tanxiaofei@huawei.com> > > BugLink: https://bugs.launchpad.net/bugs/1752695 > > This patch implements LED feature of directly attached disk for v2 hw. > As libsas has provided an interface lldd_write_gpio() for this feature, > we just need realise the interface following SPGIO API. > > We use an CPLD to finish the hardware part of this feature, and the base > address of CPLD should be configured through ACPI or DT tables. > > Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com> > Signed-off-by: John Garry <john.garry@huawei.com> > Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> > (backported from commit 6379c56070b9ee32ae2b3efa51e121242042e72d) > [ dannf: trivial offset adjustment ] > Signed-off-by: dann frazier <dann.frazier@canonical.com> > --- > drivers/scsi/hisi_sas/hisi_sas.h | 3 +++ > drivers/scsi/hisi_sas/hisi_sas_main.c | 20 +++++++++++++++++ > drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 39 ++++++++++++++++++++++++++++++++++ > 3 files changed, 62 insertions(+) > > diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h > index 83357b0367d8..26882f583109 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas.h > +++ b/drivers/scsi/hisi_sas/hisi_sas.h > @@ -212,6 +212,8 @@ struct hisi_sas_hw { > struct domain_device *device); > int (*soft_reset)(struct hisi_hba *hisi_hba); > u32 (*get_phys_state)(struct hisi_hba *hisi_hba); > + int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data); > int max_command_entries; > int complete_hdr_size; > }; > @@ -225,6 +227,7 @@ struct hisi_hba { > struct device *dev; > > void __iomem *regs; > + void __iomem *sgpio_regs; > struct regmap *ctrl; > u32 ctrl_reset_reg; > u32 ctrl_reset_sts_reg; > diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c > index b5ce64a42660..632a288ab34d 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas_main.c > +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c > @@ -1507,6 +1507,18 @@ static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) > hisi_sas_port_notify_formed(sas_phy); > } > > +static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data) > +{ > + struct hisi_hba *hisi_hba = sha->lldd_ha; > + > + if (!hisi_hba->hw->write_gpio) > + return -EOPNOTSUPP; > + > + return hisi_hba->hw->write_gpio(hisi_hba, reg_type, > + reg_index, reg_count, write_data); > +} > + > static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy) > { > phy->phy_attached = 0; > @@ -1603,6 +1615,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { > .lldd_query_task = hisi_sas_query_task, > .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, > .lldd_port_formed = hisi_sas_port_formed, > + .lldd_write_gpio = hisi_sas_write_gpio, > }; > > void hisi_sas_init_mem(struct hisi_hba *hisi_hba) > @@ -1915,6 +1928,13 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, > if (IS_ERR(hisi_hba->regs)) > goto err_out; > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); > + if (res) { > + hisi_hba->sgpio_regs = devm_ioremap_resource(dev, res); > + if (IS_ERR(hisi_hba->sgpio_regs)) > + goto err_out; > + } > + > if (hisi_sas_alloc(hisi_hba, shost)) { > hisi_sas_free(hisi_hba); > goto err_out; > diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > index 5d3467fd728d..c19f4f67c71e 100644 > --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c > @@ -3408,6 +3408,44 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) > return 0; > } > > +static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, > + u8 reg_index, u8 reg_count, u8 *write_data) > +{ > + struct device *dev = hisi_hba->dev; > + int phy_no, count; > + > + if (!hisi_hba->sgpio_regs) > + return -EOPNOTSUPP; > + > + switch (reg_type) { > + case SAS_GPIO_REG_TX: > + count = reg_count * 4; > + count = min(count, hisi_hba->n_phy); > + > + for (phy_no = 0; phy_no < count; phy_no++) { > + /* > + * GPIO_TX[n] register has the highest numbered drive > + * of the four in the first byte and the lowest > + * numbered drive in the fourth byte. > + * See SFF-8485 Rev. 0.7 Table 24. > + */ > + void __iomem *reg_addr = hisi_hba->sgpio_regs + > + reg_index * 4 + phy_no; > + int data_idx = phy_no + 3 - (phy_no % 4) * 2; > + > + writeb(write_data[data_idx], reg_addr); > + } > + > + break; > + default: > + dev_err(dev, "write gpio: unsupported or bad reg type %d\n", > + reg_type); > + return -EINVAL; > + } > + > + return 0; > +} > + > static const struct hisi_sas_hw hisi_sas_v2_hw = { > .hw_init = hisi_sas_v2_init, > .setup_itct = setup_itct_v2_hw, > @@ -3434,6 +3472,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { > .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr), > .soft_reset = soft_reset_v2_hw, > .get_phys_state = get_phys_state_v2_hw, > + .write_gpio = write_gpio_v2_hw, > }; > > static int hisi_sas_v2_probe(struct platform_device *pdev) > Applied to artful/master-next-backlog branch. Thanks, Kleber
On Thu, Mar 01, 2018 at 01:44:44PM -0700, dann frazier wrote: > From: Xiaofei Tan <tanxiaofei@huawei.com> > > BugLink: https://bugs.launchpad.net/bugs/1752695 > > This patch implements LED feature of directly attached disk for v2 hw. > As libsas has provided an interface lldd_write_gpio() for this feature, > we just need realise the interface following SPGIO API. > > We use an CPLD to finish the hardware part of this feature, and the base > address of CPLD should be configured through ACPI or DT tables. > > Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com> > Signed-off-by: John Garry <john.garry@huawei.com> > Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> > (backported from commit 6379c56070b9ee32ae2b3efa51e121242042e72d) > [ dannf: trivial offset adjustment ] > Signed-off-by: dann frazier <dann.frazier@canonical.com> Applied to bionic/master-next, thanks!
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 83357b0367d8..26882f583109 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -212,6 +212,8 @@ struct hisi_sas_hw { struct domain_device *device); int (*soft_reset)(struct hisi_hba *hisi_hba); u32 (*get_phys_state)(struct hisi_hba *hisi_hba); + int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type, + u8 reg_index, u8 reg_count, u8 *write_data); int max_command_entries; int complete_hdr_size; }; @@ -225,6 +227,7 @@ struct hisi_hba { struct device *dev; void __iomem *regs; + void __iomem *sgpio_regs; struct regmap *ctrl; u32 ctrl_reset_reg; u32 ctrl_reset_sts_reg; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b5ce64a42660..632a288ab34d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1507,6 +1507,18 @@ static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) hisi_sas_port_notify_formed(sas_phy); } +static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type, + u8 reg_index, u8 reg_count, u8 *write_data) +{ + struct hisi_hba *hisi_hba = sha->lldd_ha; + + if (!hisi_hba->hw->write_gpio) + return -EOPNOTSUPP; + + return hisi_hba->hw->write_gpio(hisi_hba, reg_type, + reg_index, reg_count, write_data); +} + static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy) { phy->phy_attached = 0; @@ -1603,6 +1615,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { .lldd_query_task = hisi_sas_query_task, .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, .lldd_port_formed = hisi_sas_port_formed, + .lldd_write_gpio = hisi_sas_write_gpio, }; void hisi_sas_init_mem(struct hisi_hba *hisi_hba) @@ -1915,6 +1928,13 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, if (IS_ERR(hisi_hba->regs)) goto err_out; + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + hisi_hba->sgpio_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(hisi_hba->sgpio_regs)) + goto err_out; + } + if (hisi_sas_alloc(hisi_hba, shost)) { hisi_sas_free(hisi_hba); goto err_out; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 5d3467fd728d..c19f4f67c71e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -3408,6 +3408,44 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) return 0; } +static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, + u8 reg_index, u8 reg_count, u8 *write_data) +{ + struct device *dev = hisi_hba->dev; + int phy_no, count; + + if (!hisi_hba->sgpio_regs) + return -EOPNOTSUPP; + + switch (reg_type) { + case SAS_GPIO_REG_TX: + count = reg_count * 4; + count = min(count, hisi_hba->n_phy); + + for (phy_no = 0; phy_no < count; phy_no++) { + /* + * GPIO_TX[n] register has the highest numbered drive + * of the four in the first byte and the lowest + * numbered drive in the fourth byte. + * See SFF-8485 Rev. 0.7 Table 24. + */ + void __iomem *reg_addr = hisi_hba->sgpio_regs + + reg_index * 4 + phy_no; + int data_idx = phy_no + 3 - (phy_no % 4) * 2; + + writeb(write_data[data_idx], reg_addr); + } + + break; + default: + dev_err(dev, "write gpio: unsupported or bad reg type %d\n", + reg_type); + return -EINVAL; + } + + return 0; +} + static const struct hisi_sas_hw hisi_sas_v2_hw = { .hw_init = hisi_sas_v2_init, .setup_itct = setup_itct_v2_hw, @@ -3434,6 +3472,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr), .soft_reset = soft_reset_v2_hw, .get_phys_state = get_phys_state_v2_hw, + .write_gpio = write_gpio_v2_hw, }; static int hisi_sas_v2_probe(struct platform_device *pdev)