Skip to content

Commit 30e9195

Browse files
Nicolas FrattaroliYuryNorov
authored andcommitted
PCI: dw-rockchip: Switch to FIELD_PREP_WM16 macro
The era of hand-rolled HIWORD_UPDATE macros is over. Like many other Rockchip drivers, pcie-dw-rockchip brings with it its very own flavour of HIWORD_UPDATE. It's occasionally used without a constant mask, which complicates matters. HIWORD_UPDATE_BIT is a confusingly named addition, as it doesn't update the bit, it actually sets all bits in the value to 1. HIWORD_DISABLE_BIT is similarly confusing; it disables several bits at once by using the value as a mask and the inverse of value as the value, and the "disabling only these" effect comes from the hardware actually using the mask. The more obvious approach would've been HIWORD_UPDATE(val, 0) in my opinion. This is part of the motivation why this patch uses hw_bitfield.h's FIELD_PREP_WM16 instead, where possible. FIELD_PREP_WM16 requires a constant bit mask, which isn't possible where the irq number is used to generate a bit mask. For that purpose, we replace it with a more robust macro than what was there but that should also bring close to zero runtime overhead: we actually mask the IRQ number to make sure we're not writing garbage. For the remaining bits, there also are some caveats. For starters, the PCIE_CLIENT_ENABLE_LTSSM and PCIE_CLIENT_DISABLE_LTSSM were named in a manner that isn't quite truthful to what they do. Their modification actually spans not just the LTSSM bit but also another bit, flipping only the LTSSM one, but keeping the other (which according to the TRM has a reset value of 0) always enabled. This other bit is reserved as of the IP version RK3588 uses at least, and I have my doubts as to whether it was meant to be set, and whether it was meant to be set in that code path. Either way, it's confusing. Replace it with just writing either 1 or 0 to the LTSSM bit, using the new FIELD_PREP_WM16 macro from hw_bitfield.h, which grants us the benefit of better compile-time error checking. The change of no longer setting the reserved bit doesn't appear to change the behaviour on RK3568 in RC mode, where it's not marked as reserved. PCIE_CLIENT_RC_MODE/PCIE_CLIENT_EP_MODE was another field that wasn't super clear on what the bit field modification actually is. As far as I can tell, switching to RC mode doesn't actually write the correct value to the field if any of its bits have been set previously, as it only updates one bit of a 4 bit field. Replace it by actually writing the full values to the field, using the new FIELD_PREP_WM16 macro, which grants us the benefit of better compile-time error checking. This patch was tested on RK3588 (PCIe3 x4 controller), RK3576 (PCIe2 x1 controller) and RK3568 (PCIe x2 controller), all in RC mode. Acked-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> Reviewed-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Yury Norov (NVIDIA) <yury.norov@gmail.com>
1 parent eb0bf4f commit 30e9195

1 file changed

Lines changed: 26 additions & 16 deletions

File tree

drivers/pci/controller/dwc/pcie-dw-rockchip.c

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/bitfield.h>
1212
#include <linux/clk.h>
1313
#include <linux/gpio/consumer.h>
14+
#include <linux/hw_bitfield.h>
1415
#include <linux/irqchip/chained_irq.h>
1516
#include <linux/irqdomain.h>
1617
#include <linux/mfd/syscon.h>
@@ -29,18 +30,18 @@
2930
* The upper 16 bits of PCIE_CLIENT_CONFIG are a write
3031
* mask for the lower 16 bits.
3132
*/
32-
#define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
33-
#define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val)
34-
#define HIWORD_DISABLE_BIT(val) HIWORD_UPDATE(val, ~val)
3533

3634
#define to_rockchip_pcie(x) dev_get_drvdata((x)->dev)
3735

3836
/* General Control Register */
3937
#define PCIE_CLIENT_GENERAL_CON 0x0
40-
#define PCIE_CLIENT_RC_MODE HIWORD_UPDATE_BIT(0x40)
41-
#define PCIE_CLIENT_EP_MODE HIWORD_UPDATE(0xf0, 0x0)
42-
#define PCIE_CLIENT_ENABLE_LTSSM HIWORD_UPDATE_BIT(0xc)
43-
#define PCIE_CLIENT_DISABLE_LTSSM HIWORD_UPDATE(0x0c, 0x8)
38+
#define PCIE_CLIENT_MODE_MASK GENMASK(7, 4)
39+
#define PCIE_CLIENT_MODE_EP 0x0UL
40+
#define PCIE_CLIENT_MODE_RC 0x4UL
41+
#define PCIE_CLIENT_SET_MODE(x) FIELD_PREP_WM16(PCIE_CLIENT_MODE_MASK, (x))
42+
#define PCIE_CLIENT_LD_RQ_RST_GRT FIELD_PREP_WM16(BIT(3), 1)
43+
#define PCIE_CLIENT_ENABLE_LTSSM FIELD_PREP_WM16(BIT(2), 1)
44+
#define PCIE_CLIENT_DISABLE_LTSSM FIELD_PREP_WM16(BIT(2), 0)
4445

4546
/* Interrupt Status Register Related to Legacy Interrupt */
4647
#define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8
@@ -52,6 +53,11 @@
5253

5354
/* Interrupt Mask Register Related to Legacy Interrupt */
5455
#define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c
56+
#define PCIE_INTR_MASK GENMASK(7, 0)
57+
#define PCIE_INTR_CLAMP(_x) ((BIT((_x)) & PCIE_INTR_MASK))
58+
#define PCIE_INTR_LEGACY_MASK(x) (PCIE_INTR_CLAMP((x)) | \
59+
(PCIE_INTR_CLAMP((x)) << 16))
60+
#define PCIE_INTR_LEGACY_UNMASK(x) (PCIE_INTR_CLAMP((x)) << 16)
5561

5662
/* Interrupt Mask Register Related to Miscellaneous Operation */
5763
#define PCIE_CLIENT_INTR_MASK_MISC 0x24
@@ -116,14 +122,14 @@ static void rockchip_pcie_intx_handler(struct irq_desc *desc)
116122
static void rockchip_intx_mask(struct irq_data *data)
117123
{
118124
rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data),
119-
HIWORD_UPDATE_BIT(BIT(data->hwirq)),
125+
PCIE_INTR_LEGACY_MASK(data->hwirq),
120126
PCIE_CLIENT_INTR_MASK_LEGACY);
121127
};
122128

123129
static void rockchip_intx_unmask(struct irq_data *data)
124130
{
125131
rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data),
126-
HIWORD_DISABLE_BIT(BIT(data->hwirq)),
132+
PCIE_INTR_LEGACY_UNMASK(data->hwirq),
127133
PCIE_CLIENT_INTR_MASK_LEGACY);
128134
};
129135

@@ -489,7 +495,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg)
489495
dev_dbg(dev, "hot reset or link-down reset\n");
490496
dw_pcie_ep_linkdown(&pci->ep);
491497
/* Stop delaying link training. */
492-
val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE);
498+
val = FIELD_PREP_WM16(PCIE_LTSSM_APP_DLY2_DONE, 1);
493499
rockchip_pcie_writel_apb(rockchip, val,
494500
PCIE_CLIENT_HOT_RESET_CTRL);
495501
}
@@ -528,10 +534,11 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev,
528534
}
529535

530536
/* LTSSM enable control mode */
531-
val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE);
537+
val = FIELD_PREP_WM16(PCIE_LTSSM_ENABLE_ENHANCE, 1);
532538
rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL);
533539

534-
rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_RC_MODE,
540+
rockchip_pcie_writel_apb(rockchip,
541+
PCIE_CLIENT_SET_MODE(PCIE_CLIENT_MODE_RC),
535542
PCIE_CLIENT_GENERAL_CON);
536543

537544
pp = &rockchip->pci.pp;
@@ -545,7 +552,7 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev,
545552
}
546553

547554
/* unmask DLL up/down indicator */
548-
val = HIWORD_UPDATE(PCIE_RDLH_LINK_UP_CHGED, 0);
555+
val = FIELD_PREP_WM16(PCIE_RDLH_LINK_UP_CHGED, 0);
549556
rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_INTR_MASK_MISC);
550557

551558
return ret;
@@ -577,10 +584,12 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev,
577584
* LTSSM enable control mode, and automatically delay link training on
578585
* hot reset/link-down reset.
579586
*/
580-
val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN);
587+
val = FIELD_PREP_WM16(PCIE_LTSSM_ENABLE_ENHANCE, 1) |
588+
FIELD_PREP_WM16(PCIE_LTSSM_APP_DLY2_EN, 1);
581589
rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL);
582590

583-
rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_EP_MODE,
591+
rockchip_pcie_writel_apb(rockchip,
592+
PCIE_CLIENT_SET_MODE(PCIE_CLIENT_MODE_EP),
584593
PCIE_CLIENT_GENERAL_CON);
585594

586595
rockchip->pci.ep.ops = &rockchip_pcie_ep_ops;
@@ -604,7 +613,8 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev,
604613
pci_epc_init_notify(rockchip->pci.ep.epc);
605614

606615
/* unmask DLL up/down indicator and hot reset/link-down reset */
607-
val = HIWORD_UPDATE(PCIE_RDLH_LINK_UP_CHGED | PCIE_LINK_REQ_RST_NOT_INT, 0);
616+
val = FIELD_PREP_WM16(PCIE_RDLH_LINK_UP_CHGED, 0) |
617+
FIELD_PREP_WM16(PCIE_LINK_REQ_RST_NOT_INT, 0);
608618
rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_INTR_MASK_MISC);
609619

610620
return ret;

0 commit comments

Comments
 (0)