diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml new file mode 100644 index 000000000000..1d2ab44fcd3c --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/fsl,mpc8323-qe-pario-bank.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale QUICC Engine Parallel I/O (QE PARIO) GPIO Bank + +maintainers: + - Christophe Leroy + +properties: + compatible: + oneOf: + - items: + - enum: + - fsl,mpc8360-qe-pario-bank + - fsl,mpc8569-qe-pario-bank + - const: fsl,mpc8323-qe-pario-bank + - const: fsl,mpc8323-qe-pario-bank + + reg: + maxItems: 1 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + "#address-cells": + const: 0 + + "#interrupt-cells": + const: 2 + + interrupt-map: + description: | + Specifies the mapping of GPIO lines to the parent interrupt controller, as the + GPIO controller does not do interrupt handling itself. + +required: + - compatible + - reg + - gpio-controller + - "#gpio-cells" + +additionalProperties: false + +examples: + - | + #include + + gpio-controller@1400 { + compatible = "fsl,mpc8360-qe-pario-bank", "fsl,mpc8323-qe-pario-bank"; + reg = <0x1400 0x18>; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio-controller@1418 { + compatible = "fsl,mpc8323-qe-pario-bank"; + reg = <0x1418 0x18>; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-map = < + 7 IRQ_TYPE_EDGE_FALLING &pic 4 IRQ_TYPE_EDGE_FALLING + 7 IRQ_TYPE_EDGE_BOTH &pic 4 IRQ_TYPE_EDGE_BOTH + 7 0 &pic 4 IRQ_TYPE_NONE + + 9 IRQ_TYPE_EDGE_FALLING &pic 5 IRQ_TYPE_EDGE_FALLING + 9 IRQ_TYPE_EDGE_BOTH &pic 5 IRQ_TYPE_EDGE_BOTH + 9 0 &pic 5 IRQ_TYPE_NONE + + 25 IRQ_TYPE_EDGE_FALLING &pic 6 IRQ_TYPE_EDGE_FALLING + 25 IRQ_TYPE_EDGE_BOTH &pic 6 IRQ_TYPE_EDGE_BOTH + 25 0 &pic 6 IRQ_TYPE_NONE + + 27 IRQ_TYPE_EDGE_FALLING &pic 7 IRQ_TYPE_EDGE_FALLING + 27 IRQ_TYPE_EDGE_BOTH &pic 7 IRQ_TYPE_EDGE_BOTH + 27 0 &pic 7 IRQ_TYPE_NONE + >; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml b/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml index 2b8e7b9c6d7a..2b7c6b4f0389 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml @@ -23,7 +23,7 @@ properties: const: 0 '#interrupt-cells': - const: 1 + const: 2 interrupts: maxItems: 1 @@ -45,7 +45,7 @@ examples: reg = <0xc00 0x18>; interrupt-controller; #address-cells = <0>; - #interrupt-cells = <1>; + #interrupt-cells = <2>; interrupts = <74 0x8>; interrupt-parent = <&ipic>; }; diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt index 09b1b05fa677..782699c14567 100644 --- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt @@ -24,28 +24,4 @@ par_io@1400 { Note that "par_io" nodes are obsolete, and should not be used for the new device trees. Instead, each Par I/O bank should be represented -via its own gpio-controller node: - -Required properties: -- #gpio-cells : should be "2". -- compatible : should be "fsl,-qe-pario-bank", - "fsl,mpc8323-qe-pario-bank". -- reg : offset to the register set and its length. -- gpio-controller : node to identify gpio controllers. - -Example: - qe_pio_a: gpio-controller@1400 { - #gpio-cells = <2>; - compatible = "fsl,mpc8360-qe-pario-bank", - "fsl,mpc8323-qe-pario-bank"; - reg = <0x1400 0x18>; - gpio-controller; - }; - - qe_pio_e: gpio-controller@1460 { - #gpio-cells = <2>; - compatible = "fsl,mpc8360-qe-pario-bank", - "fsl,mpc8323-qe-pario-bank"; - reg = <0x1460 0x18>; - gpio-controller; - }; +via its own gpio-controller node. diff --git a/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml b/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml index 3fb0534ea597..fc14fd0bf84b 100644 --- a/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml +++ b/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml @@ -36,7 +36,20 @@ properties: - const: simple-mfd reg: - maxItems: 1 + minItems: 1 + items: + - description: + Customer-visible DCFG register map from CCSR address space + (Configuration, Control and Status Registers) + - description: + Customer-hidden DCFG register map from DCSR address space + (Debug Control and Status Registers) + + reg-names: + minItems: 1 + items: + - const: dcfg_ccsr + - const: dcfg_dcsr little-endian: true big-endian: true diff --git a/MAINTAINERS b/MAINTAINERS index ae360813184c..9091653c0620 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7814,7 +7814,7 @@ F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.yaml F: drivers/media/i2c/dw9807-vcm.c DPAA2 DATAPATH I/O (DPIO) DRIVER -M: Roy Pledge +M: Ioana Ciornei L: linux-kernel@vger.kernel.org S: Maintained F: drivers/soc/fsl/dpio diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index c4e61843d9d9..2f797ac6f1b3 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -228,14 +228,6 @@ config TAU_AVERAGE If in doubt, say N here. -config QE_GPIO - bool "QE GPIO support" - depends on QUICC_ENGINE - select GPIOLIB - help - Say Y here if you're going to use hardware that connects to the - QE GPIOs. - config CPM2 bool "Enable support for the CPM2 (Communications Processor Module)" depends on (FSL_SOC_BOOKE && PPC32) || PPC_82xx diff --git a/drivers/bus/fsl-mc/dprc-driver.c b/drivers/bus/fsl-mc/dprc-driver.c index a85706826fa0..a81188cb06f2 100644 --- a/drivers/bus/fsl-mc/dprc-driver.c +++ b/drivers/bus/fsl-mc/dprc-driver.c @@ -521,12 +521,8 @@ static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev) IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(&mc_dev->dev), &mc_dev->dev); - if (error < 0) { - dev_err(&mc_dev->dev, - "devm_request_threaded_irq() failed: %d\n", - error); + if (error < 0) return error; - } return 0; } diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 64d75eed0d34..8c203cd47534 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -908,7 +908,7 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev, int state, err; mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); - strcpy(endpoint1.type, mc_dev->obj_desc.type); + strscpy(endpoint1.type, mc_dev->obj_desc.type); endpoint1.id = mc_dev->obj_desc.id; endpoint1.if_id = if_id; @@ -925,7 +925,7 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev, return ERR_PTR(err); } - strcpy(endpoint_desc.type, endpoint2.type); + strscpy(endpoint_desc.type, endpoint2.type); endpoint_desc.id = endpoint2.id; endpoint = fsl_mc_device_lookup(&endpoint_desc, mc_bus_dev); if (endpoint) diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index 5bf3864fbe64..d4e189fffbf8 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -58,6 +58,7 @@ config PHY_FSL_LYNX_10G tristate "Freescale Layerscape Lynx 10G SerDes PHY support" depends on OF depends on ARCH_LAYERSCAPE || COMPILE_TEST + select FSL_GUTS select GENERIC_PHY select PHY_FSL_LYNX_CORE help diff --git a/drivers/phy/freescale/phy-fsl-lynx-10g.c b/drivers/phy/freescale/phy-fsl-lynx-10g.c index 38def160ef1a..60c85d08c33e 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-10g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-10g.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "phy-fsl-lynx-core.h" @@ -1167,14 +1168,7 @@ static bool lynx_10g_lane_mode_needs_rcw_override(struct lynx_lane *lane, /* Major protocol changes, which involve changing the PCS connection to * the GMII MAC with the one to the XGMII MAC, require an RCW override - * procedure to reconfigure an internal mux, as documented here: - * https://lore.kernel.org/linux-phy/20230810102631.bvozjer3t67r67iy@skbuf/ - * This is SoC-specific, and not yet implemented in drivers/soc/fsl/guts.c. - * - * So the supported set of protocols depends on the initial lane mode. - * - * Minor protocol changes (SGMII <-> 1000Base-X <-> 2500Base-X or - * 10GBase-R <-> USXGMII) are supported. + * procedure to reconfigure an internal mux. */ if ((lynx_lane_mode_uses_gmii_mac(curr) && lynx_lane_mode_uses_xgmii_mac(new)) || @@ -1189,6 +1183,7 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode, union phy_configure_opts *opts) { struct lynx_lane *lane = phy_get_drvdata(phy); + struct lynx_priv *priv = lane->priv; enum lynx_lane_mode lane_mode; int err; @@ -1197,7 +1192,8 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode, return err; if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) - return -EINVAL; + return fsl_guts_lane_validate(priv->info->index, lane->id, + lane_mode); return 0; } @@ -1205,6 +1201,7 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode, static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct lynx_lane *lane = phy_get_drvdata(phy); + struct lynx_priv *priv = lane->priv; bool powered_up = lane->powered_up; enum lynx_lane_mode lane_mode; int err; @@ -1225,6 +1222,13 @@ static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode) if (powered_up) lynx_10g_lane_halt(phy); + if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) { + err = fsl_guts_lane_set_mode(priv->info->index, lane->id, + lane_mode); + if (err) + goto out; + } + err = lynx_10g_lane_disable_pcvt(lane, lane->mode); if (err) goto out; @@ -1314,6 +1318,7 @@ static struct platform_driver lynx_10g_driver = { }; module_platform_driver(lynx_10g_driver); +MODULE_IMPORT_NS("FSL_GUTS"); MODULE_IMPORT_NS("PHY_FSL_LYNX"); MODULE_AUTHOR("Ioana Ciornei "); MODULE_AUTHOR("Vladimir Oltean "); diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 9e3fddd8f5a9..d5198ffc4455 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -102,12 +102,8 @@ static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu) 0, dev_name(&dpio_dev->dev), &dpio_dev->dev); - if (error < 0) { - dev_err(&dpio_dev->dev, - "devm_request_irq() failed: %d\n", - error); + if (error < 0) return error; - } /* set the affinity hint */ if (irq_set_affinity_hint(irq->virq, cpumask_of(cpu))) diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c index 9bee7baec2b9..28361c63e26c 100644 --- a/drivers/soc/fsl/guts.c +++ b/drivers/soc/fsl/guts.c @@ -5,7 +5,10 @@ * Copyright (C) 2016 Freescale Semiconductor, Inc. */ +#include +#include #include +#include #include #include #include @@ -14,15 +17,110 @@ #include #include +#define DCFG_CCSR 0 +#define DCFG_DCSR 1 + +#define RCW_TIMEOUT_US 1 + +#define LS1046A_RCWSR5_SRDS_PRTCL_S1(lane) \ + GENMASK(19 + 4 * (lane), 16 + 4 * (lane)) +#define LS1046A_SRDS_PRTCL_XFI 1 +#define LS1046A_SRDS_PRTCL_100BASEX_SGMII 3 + +#define LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn(lane) \ + GENMASK(19 + 4 * (3 - (lane)), 16 + 4 * (3 - (lane))) +#define LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn(lane) \ + GENMASK(3 + 4 * (3 - (lane)), 4 * (3 - (lane))) +#define LS1088A_SRDS_PRTCL_XFI 1 +#define LS1088A_SRDS_PRTCL_100BASEX_SGMII 3 + +#define LS2088A_RCWSR29_SRDS_PRTCL_S1 GENMASK(23, 16) +#define LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1 BIT(14) +#define LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(lane) BIT(6 + (7 - (lane))) +#define LS2088A_RCWSR30_SRDS_CLK_SEL_MSK GENMASK(13, 6) +#define LS2088A_SRDS_CLK_SEL_XGMII 1 +#define LS2088A_SRDS_CLK_SEL_GMII 0 + struct fsl_soc_die_attr { char *die; u32 svr; u32 mask; }; +struct fsl_soc_serdes_rcw_override { + int offset; + int mask; + int val; +}; + struct fsl_soc_data { const char *sfp_compat; u32 uid_offset; + int num_serdes_blocks; + int num_serdes_lanes; + int (*serdes_init_rcwcr)(int index); + int (*serdes_get_rcw_override)(int index, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override); +}; + +enum qoriq_die { + DIE_T4240, + DIE_T1040, + DIE_T2080, + DIE_T1024, + DIE_LS1043A, + DIE_LS2080A, + DIE_LS1088A, + DIE_LS1012A, + DIE_LS1046A, + DIE_LS2088A, + DIE_LS1021A, + DIE_LX2160A, + DIE_LS1028A, + DIE_MAX, +}; + +struct rcw_full_srds_proto { + int srds_proto_val; + unsigned long xgmii_lanes; +}; + +static const struct rcw_full_srds_proto ls2088a_rcw_full_srds1_protos[] = { + { 0x05, 0 }, + { 0x07, 0 }, + { 0x09, 0 }, + { 0x0a, 0 }, + { 0x0c, 0 }, + { 0x0e, 0 }, + { 0x10, 0 }, + { 0x12, 0 }, + { 0x14, 0 }, + { 0x16, 0 }, + { 0x18, 0 }, + { 0x1a, 0 }, + { 0x1c, 0 }, + { 0x1e, 0 }, + { 0x20, 0 }, + { 0x22, 0 }, + { 0x24, 0 }, + { 0x26, GENMASK(7, 6) }, + { 0x28, GENMASK(7, 4) }, + { 0x2a, GENMASK(7, 0) }, + /* 0x2b: unimplemented because of XAUI1 (lanes E-H) */ + /* 0x2d: unimplemented because of XAUI1 (lanes E-H) */ + /* 0x2e: unimplemented because of XAUI1 (lanes E-H) */ + /* 0x30: unimplemented because of XAUI1 (lanes E-H) */ + /* 0x32: unimplemented because of XAUI1 (lanes E-H) and XAUI2 (A-D) */ + /* 0x33: unimplemented because of QSGMII (lanes E-H) */ + /* 0x35: unimplemented because of QSGMII (lanes A-C) */ + /* 0x37: unimplemented because of QSGMII (lanes E-F) */ + { 0x39, 0 }, + { 0x3b, GENMASK(6, 4) | GENMASK(2, 0) }, + { 0x4b, GENMASK(7, 4) }, + { 0x4c, GENMASK(3, 0) }, + { 0x4d, 0 }, + { 0x58, 0 }, }; /* SoC die attribute definition for QorIQ platform */ @@ -32,21 +130,25 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = { */ /* Die: T4240, SoC: T4240/T4160/T4080 */ + [DIE_T4240] = { .die = "T4240", .svr = 0x82400000, .mask = 0xfff00000, }, /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */ + [DIE_T1040] = { .die = "T1040", .svr = 0x85200000, .mask = 0xfff00000, }, /* Die: T2080, SoC: T2080/T2081 */ + [DIE_T2080] = { .die = "T2080", .svr = 0x85300000, .mask = 0xfff00000, }, /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */ + [DIE_T1024] = { .die = "T1024", .svr = 0x85400000, .mask = 0xfff00000, @@ -57,46 +159,55 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = { */ /* Die: LS1043A, SoC: LS1043A/LS1023A */ + [DIE_LS1043A] = { .die = "LS1043A", .svr = 0x87920000, .mask = 0xffff0000, }, /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */ + [DIE_LS2080A] = { .die = "LS2080A", .svr = 0x87010000, .mask = 0xff3f0000, }, /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */ + [DIE_LS1088A] = { .die = "LS1088A", .svr = 0x87030000, .mask = 0xff3f0000, }, /* Die: LS1012A, SoC: LS1012A */ + [DIE_LS1012A] = { .die = "LS1012A", .svr = 0x87040000, .mask = 0xffff0000, }, /* Die: LS1046A, SoC: LS1046A/LS1026A */ + [DIE_LS1046A] = { .die = "LS1046A", .svr = 0x87070000, .mask = 0xffff0000, }, /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */ + [DIE_LS2088A] = { .die = "LS2088A", .svr = 0x87090000, .mask = 0xff3f0000, }, /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */ + [DIE_LS1021A] = { .die = "LS1021A", .svr = 0x87000000, .mask = 0xfff70000, }, /* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */ + [DIE_LX2160A] = { .die = "LX2160A", .svr = 0x87360000, .mask = 0xff3f0000, }, /* Die: LS1028A, SoC: LS1028A */ + [DIE_LS1028A] = { .die = "LS1028A", .svr = 0x870b0000, .mask = 0xff3f0000, @@ -104,17 +215,160 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = { { }, }; +static struct fsl_soc_guts { + struct ccsr_guts __iomem *dcfg_ccsr; + struct ccsr_guts __iomem *dcfg_dcsr; + const struct fsl_soc_data *data; + bool little_endian; + u32 svr; + spinlock_t rcwcr_lock; /* serializes concurrent writes to the RCWCR */ +} soc; + +static unsigned int fsl_guts_read(const void __iomem *reg) +{ + if (soc.little_endian) + return ioread32(reg); + + return ioread32be(reg); +} + +static void fsl_guts_write(void __iomem *reg, u32 val) +{ + if (soc.little_endian) + iowrite32(val, reg); + else + iowrite32be(val, reg); +} + +/* Some fields of the Reset Configuration Word (RCW) can be overridden at + * runtime by writing to the RCWCRn registers contained within the DCSR space + * of the Device Configuration (DCFG) block. The layout of the RCWCRn registers + * is identical with the read-only RCWSRn from the CCSR space. + */ +static int fsl_guts_rcw_rmw(int offset, u32 val, u32 mask) +{ + u32 rcwcr, rcwsr = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[offset]); + + rcwcr = rcwsr & ~mask; + rcwcr |= val; + fsl_guts_write(&soc.dcfg_dcsr->rcwcr[offset], rcwcr); + + pr_debug("RCW override: RCWSR%d 0x%x -> RCWCR%d 0x%x\n", + offset + 1, rcwsr, offset + 1, rcwcr); + + /* Updates to RCWCR should be visible back in RCWSR immediately */ + return read_poll_timeout_atomic(fsl_guts_read, rcwsr, rcwsr == rcwcr, + 0, RCW_TIMEOUT_US, false, + &soc.dcfg_ccsr->rcwsr[offset]); +} + +static bool fsl_soc_die_match_one(u32 svr, const struct fsl_soc_die_attr *match) +{ + return match->svr == (svr & match->mask); +} + static const struct fsl_soc_die_attr *fsl_soc_die_match( u32 svr, const struct fsl_soc_die_attr *matches) { while (matches->svr) { - if (matches->svr == (svr & matches->mask)) + if (fsl_soc_die_match_one(svr, matches)) return matches; matches++; } return NULL; } +static int +fsl_guts_serdes_get_rcw_override(int serdes_idx, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override) +{ + const struct fsl_soc_data *soc_data = soc.data; + + if (!soc_data) + return -ENODEV; + + /* serdes_idx is one-based */ + if (serdes_idx > soc_data->num_serdes_blocks || serdes_idx <= 0) + return -ERANGE; + + if (lane >= soc_data->num_serdes_lanes || lane < 0) + return -ERANGE; + + if (!soc_data->serdes_get_rcw_override) { + pr_debug("RCW override not implemented for SoC\n"); + return -EINVAL; + } + + if (!soc.dcfg_dcsr) { + pr_debug("Device tree does not define DCFG_DCSR region necessary for RCW override\n"); + return -EINVAL; + } + + return soc_data->serdes_get_rcw_override(serdes_idx, lane, lane_mode, + override); +} + +/** + * fsl_guts_lane_validate() - Validate that SerDes protocol is implemented and + * supported on current SoC + * @serdes_idx: one-based SerDes block index + * @lane: zero-based lane index within SerDes + * @lane_mode: requested SerDes protocol + * + * Should be called before actually requesting the RCW override procedure to be + * applied using %fsl_guts_lane_set_mode() + * + * Return: 0 if RCW override to protocol is possible, negative error otherwise + */ +int fsl_guts_lane_validate(int serdes_idx, int lane, enum lynx_lane_mode lane_mode) +{ + struct fsl_soc_serdes_rcw_override override; + + return fsl_guts_serdes_get_rcw_override(serdes_idx, lane, lane_mode, + &override); +} +EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_validate, "FSL_GUTS"); + +/** + * fsl_guts_lane_set_mode() - apply RCW override procedure for SerDes lane + * @serdes_idx: one-based SerDes block index + * @lane: zero-based lane index within SerDes + * @lane_mode: requested SerDes protocol + * + * Return: 0 on success, negative error otherwise + */ +int fsl_guts_lane_set_mode(int serdes_idx, int lane, enum lynx_lane_mode lane_mode) +{ + struct fsl_soc_serdes_rcw_override override; + int err; + + err = fsl_guts_serdes_get_rcw_override(serdes_idx, lane, lane_mode, + &override); + if (err) + return err; + + spin_lock(&soc.rcwcr_lock); + + if (soc.data->serdes_init_rcwcr) { + err = soc.data->serdes_init_rcwcr(serdes_idx); + if (err) + goto out_unlock; + } + + err = fsl_guts_rcw_rmw(override.offset, + override.val << __ffs(override.mask), + override.mask); + if (err) + pr_err("RCW override failed: %pe\n", ERR_PTR(err)); + +out_unlock: + spin_unlock(&soc.rcwcr_lock); + + return err; +} +EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_set_mode, "FSL_GUTS"); + static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset) { struct device_node *np; @@ -141,9 +395,188 @@ static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset) return uid; } +static int ls1046a_serdes_get_rcw_override(int index, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override) +{ + /* The RCW override procedure has to write to different registers + * depending on the SerDes block index. + */ + switch (index) { + case 1: + override->offset = 4; + override->mask = LS1046A_RCWSR5_SRDS_PRTCL_S1(lane); + break; + default: + return -EINVAL; + } + + if (lynx_lane_mode_uses_xgmii_mac(lane_mode)) + override->val = LS1046A_SRDS_PRTCL_XFI; + else if (lynx_lane_mode_uses_gmii_mac(lane_mode)) + override->val = LS1046A_SRDS_PRTCL_100BASEX_SGMII; + else + return -EINVAL; + + return 0; +} + +static int ls1088a_serdes_get_rcw_override(int index, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override) +{ + /* The RCW override procedure has to write to different registers + * depending on the SerDes block index. + */ + switch (index) { + case 1: + override->offset = 28; + override->mask = LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn(lane); + break; + case 2: + override->offset = 29; + override->mask = LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn(lane); + break; + default: + return -EINVAL; + } + + if (lynx_lane_mode_uses_xgmii_mac(lane_mode)) + override->val = LS1088A_SRDS_PRTCL_XFI; + else if (lynx_lane_mode_uses_gmii_mac(lane_mode)) + override->val = LS1088A_SRDS_PRTCL_100BASEX_SGMII; + else + return -EINVAL; + + return 0; +} + +static const struct rcw_full_srds_proto *ls2088a_get_full_serdes1_proto(void) +{ + u32 rcwsr29 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[28]); + u32 srds_prtcl_s1 = FIELD_GET(LS2088A_RCWSR29_SRDS_PRTCL_S1, rcwsr29); + + for (int i = 0; i < ARRAY_SIZE(ls2088a_rcw_full_srds1_protos); i++) { + const struct rcw_full_srds_proto *proto; + + proto = &ls2088a_rcw_full_srds1_protos[i]; + if (proto->srds_proto_val == srds_prtcl_s1) + return proto; + } + + return NULL; +} + +static int ls2088a_serdes_get_rcw_override(int index, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override) +{ + switch (index) { + case 1: + override->offset = 29; + override->mask = LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(lane); + break; + default: + return -EINVAL; + } + + /* RCW override only supported if we know how to handle the initial + * RCWSR29[SRDS_PRTCL_S1] value and turn it into an override. + */ + if (!ls2088a_get_full_serdes1_proto()) { + u32 rcwsr30 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[29]); + + /* If a SerDes-level override is already in place (probably + * left there by a previous boot stage), use it. + */ + if (!(rcwsr30 & LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1)) + return -EINVAL; + } + + if (lynx_lane_mode_uses_xgmii_mac(lane_mode)) + override->val = LS2088A_SRDS_CLK_SEL_XGMII; + else if (lynx_lane_mode_uses_gmii_mac(lane_mode)) + override->val = LS2088A_SRDS_CLK_SEL_GMII; + else + return -EINVAL; + + return 0; +} + +static int ls2088a_serdes_init_rcwcr(int serdes_idx) +{ + const struct rcw_full_srds_proto *srds_prtcl_s1; + const struct fsl_soc_data *soc_data = soc.data; + u32 rcwsr30; + int i, err; + + /* SerDes 2 supports only SGMII for networking. There should be + * no need for RCW override + */ + if (serdes_idx != 1) + return -EINVAL; + + /* SRDS_CLK_EN_SEL_XGMII_S1: SerDes Clock Enable Select XGMII Serdes 1: + * Enables to select GMII/XGMII clock according to + * SRDS_CLK_SEL_XGMII_Ln_S1. + * If the GMII/XGMII select override has already been set, use it. + * Otherwise, derive an initial override for all lanes based on the + * full SerDes protocol table. + */ + rcwsr30 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[29]); + if (rcwsr30 & LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1) { + pr_debug("RCWSR30 = 0x%x, using this.\n", rcwsr30); + return 0; + } + + srds_prtcl_s1 = ls2088a_get_full_serdes1_proto(); + + rcwsr30 = LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1; + + /* We need to configure the initial state of all lanes for + * the SerDes block #1 + */ + for_each_set_bit(i, &srds_prtcl_s1->xgmii_lanes, soc_data->num_serdes_lanes) + rcwsr30 |= LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(i); + + pr_debug("Setting initial RCWSR30 = 0x%x based on SRDS_PRTCL_S1 = 0x%x\n", + rcwsr30, srds_prtcl_s1->srds_proto_val); + + err = fsl_guts_rcw_rmw(29, rcwsr30, + LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1 | + LS2088A_RCWSR30_SRDS_CLK_SEL_MSK); + if (err) { + pr_err("Setting up initial RCWCR failed: %pe\n", ERR_PTR(err)); + return err; + } + + return 0; +} + +static const struct fsl_soc_data ls1088a_data = { + .serdes_get_rcw_override = ls1088a_serdes_get_rcw_override, + .num_serdes_blocks = 2, + .num_serdes_lanes = 4, +}; + +static const struct fsl_soc_data ls1046a_data = { + .serdes_get_rcw_override = ls1046a_serdes_get_rcw_override, + .num_serdes_blocks = 2, + .num_serdes_lanes = 4, +}; + +static const struct fsl_soc_data ls2088a_data = { + .serdes_get_rcw_override = ls2088a_serdes_get_rcw_override, + .serdes_init_rcwcr = ls2088a_serdes_init_rcwcr, + .num_serdes_blocks = 2, + .num_serdes_lanes = 8, +}; + static const struct fsl_soc_data ls1028a_data = { .sfp_compat = "fsl,ls1028a-sfp", .uid_offset = 0x21c, + .num_serdes_blocks = 1, + .num_serdes_lanes = 4, }; /* @@ -169,10 +602,10 @@ static const struct of_device_id fsl_guts_of_match[] = { { .compatible = "fsl,mpc8572-guts", }, { .compatible = "fsl,ls1021a-dcfg", }, { .compatible = "fsl,ls1043a-dcfg", }, - { .compatible = "fsl,ls2080a-dcfg", }, - { .compatible = "fsl,ls1088a-dcfg", }, + { .compatible = "fsl,ls2080a-dcfg", .data = &ls2088a_data}, + { .compatible = "fsl,ls1088a-dcfg", .data = &ls1088a_data}, { .compatible = "fsl,ls1012a-dcfg", }, - { .compatible = "fsl,ls1046a-dcfg", }, + { .compatible = "fsl,ls1046a-dcfg", .data = &ls1046a_data}, { .compatible = "fsl,lx2160a-dcfg", }, { .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data}, {} @@ -180,68 +613,73 @@ static const struct of_device_id fsl_guts_of_match[] = { static int __init fsl_guts_init(void) { - struct soc_device_attribute *soc_dev_attr; + struct soc_device_attribute *soc_dev_attr = NULL; static struct soc_device *soc_dev; const struct fsl_soc_die_attr *soc_die; - const struct fsl_soc_data *soc_data; const struct of_device_id *match; - struct ccsr_guts __iomem *regs; struct device_node *np; - bool little_endian; u64 soc_uid = 0; - u32 svr; int ret; + spin_lock_init(&soc.rcwcr_lock); + np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match); if (!np) return 0; - soc_data = match->data; + soc.data = match->data; - regs = of_iomap(np, 0); - if (!regs) { + soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR); + if (!soc.dcfg_ccsr) { of_node_put(np); - return -ENOMEM; + ret = -ENOMEM; + goto err_clear_soc_data; } + /* DCFG_DCSR is optional */ + soc.dcfg_dcsr = of_iomap(np, DCFG_DCSR); - little_endian = of_property_read_bool(np, "little-endian"); - if (little_endian) - svr = ioread32(®s->svr); - else - svr = ioread32be(®s->svr); - iounmap(regs); + soc.little_endian = of_property_read_bool(np, "little-endian"); + soc.svr = fsl_guts_read(&soc.dcfg_ccsr->svr); of_node_put(np); /* Register soc device */ soc_dev_attr = kzalloc_obj(*soc_dev_attr); - if (!soc_dev_attr) - return -ENOMEM; + if (!soc_dev_attr) { + ret = -ENOMEM; + goto err_unmap_dcfg_ccsr_dcsr; + } ret = soc_attr_read_machine(soc_dev_attr); if (ret) of_machine_read_compatible(&soc_dev_attr->machine, 0); - soc_die = fsl_soc_die_match(svr, fsl_soc_die); + soc_die = fsl_soc_die_match(soc.svr, fsl_soc_die); if (soc_die) { soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s", soc_die->die); } else { soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ"); } - if (!soc_dev_attr->family) - goto err_nomem; + if (!soc_dev_attr->family) { + ret = -ENOMEM; + goto err_free_soc_dev_attr; + } - soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr); - if (!soc_dev_attr->soc_id) - goto err_nomem; + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", soc.svr); + if (!soc_dev_attr->soc_id) { + ret = -ENOMEM; + goto err_free_family; + } soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", - (svr >> 4) & 0xf, svr & 0xf); - if (!soc_dev_attr->revision) - goto err_nomem; + (soc.svr >> 4) & 0xf, soc.svr & 0xf); + if (!soc_dev_attr->revision) { + ret = -ENOMEM; + goto err_free_soc_id; + } - if (soc_data) - soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat, - soc_data->uid_offset); + if (soc.data) + soc_uid = fsl_guts_get_soc_uid(soc.data->sfp_compat, + soc.data->uid_offset); if (soc_uid) soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); @@ -249,7 +687,7 @@ static int __init fsl_guts_init(void) soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { ret = PTR_ERR(soc_dev); - goto err; + goto err_free_serial_number; } pr_info("Machine: %s\n", soc_dev_attr->machine); @@ -259,14 +697,24 @@ static int __init fsl_guts_init(void) return 0; -err_nomem: - ret = -ENOMEM; -err: - kfree(soc_dev_attr->family); - kfree(soc_dev_attr->soc_id); - kfree(soc_dev_attr->revision); +err_free_serial_number: kfree(soc_dev_attr->serial_number); + kfree(soc_dev_attr->revision); +err_free_soc_id: + kfree(soc_dev_attr->soc_id); +err_free_family: + kfree(soc_dev_attr->family); +err_free_soc_dev_attr: kfree(soc_dev_attr); +err_unmap_dcfg_ccsr_dcsr: + if (soc.dcfg_dcsr) { + iounmap(soc.dcfg_dcsr); + soc.dcfg_dcsr = NULL; + } + iounmap(soc.dcfg_ccsr); + soc.dcfg_ccsr = NULL; +err_clear_soc_data: + soc.data = NULL; return ret; } diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index eb03f42ab978..87cd1662e168 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -67,3 +67,12 @@ config QE_USB default y if USB_FSL_QE help QE USB Controller support + +config QE_GPIO + bool "QE GPIO support" + depends on QUICC_ENGINE + select GENERIC_IRQ_CHIP + select GPIOLIB + help + Say Y here if you're going to use hardware that connects to the + QE GPIOs. diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index 66828f2a3577..5cd59cfbf22f 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,7 @@ #define PIN_MASK(gpio) (1UL << (QE_PIO_PINS - 1 - (gpio))) struct qe_gpio_chip { + struct device_node *np; struct gpio_chip gc; void __iomem *regs; spinlock_t lock; @@ -135,6 +137,53 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } +static int qe_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); + struct qe_pio_regs __iomem *regs = qe_gc->regs; + unsigned long flags; + u32 val, mask; + + spin_lock_irqsave(&qe_gc->lock, flags); + + if (gpio < QE_PIO_PINS / 2) + val = ioread32be(®s->cpdir1); + else + val = ioread32be(®s->cpdir2); + + spin_unlock_irqrestore(&qe_gc->lock, flags); + + mask = (u32)QE_PIO_DIR_OUT << (QE_PIO_PINS - 2 - (gpio % (QE_PIO_PINS / 2)) * 2); + + if (val & mask) + return GPIO_LINE_DIRECTION_OUT; + else + return GPIO_LINE_DIRECTION_IN; +} + +static int qe_gpio_to_irq(struct gpio_chip *gc, unsigned int gpio) +{ + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); + struct of_phandle_args oirq; + struct irq_domain *domain; + int ret; + + oirq.np = qe_gc->np; + oirq.args_count = 2; + oirq.args[0] = gpio; + oirq.args[1] = 0; + + ret = of_irq_parse_raw(NULL, &oirq); + if (ret) + return ret; + + domain = irq_find_host(oirq.np); + if (!domain) + return -EPROBE_DEFER; + + return irq_create_of_mapping(&oirq); +} + struct qe_pin { /* * The qe_gpio_chip name is unfortunate, we should change that to @@ -299,7 +348,7 @@ static int qe_gpio_probe(struct platform_device *ofdev) qe_gc = devm_kzalloc(dev, sizeof(*qe_gc), GFP_KERNEL); if (!qe_gc) return -ENOMEM; - + qe_gc->np = np; spin_lock_init(&qe_gc->lock); gc = &qe_gc->gc; @@ -308,9 +357,11 @@ static int qe_gpio_probe(struct platform_device *ofdev) gc->ngpio = QE_PIO_PINS; gc->direction_input = qe_gpio_dir_in; gc->direction_output = qe_gpio_dir_out; + gc->get_direction = qe_gpio_get_direction; gc->get = qe_gpio_get; gc->set = qe_gpio_set; gc->set_multiple = qe_gpio_set_multiple; + gc->to_irq = qe_gpio_to_irq; gc->parent = dev; gc->owner = THIS_MODULE; diff --git a/drivers/soc/fsl/qe/qe_io.c b/drivers/soc/fsl/qe/qe_io.c index a5e2d0e5ab51..150913fce981 100644 --- a/drivers/soc/fsl/qe/qe_io.c +++ b/drivers/soc/fsl/qe/qe_io.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -184,3 +185,17 @@ int par_io_of_config(struct device_node *np) return 0; } EXPORT_SYMBOL(par_io_of_config); + +static int __init par_io_populate(void) +{ + struct device_node *np = of_find_node_by_type(NULL, "par_io"); + + if (!np) + return 0; + + of_platform_default_populate(np, NULL, NULL); + of_node_put(np); + + return 0; +} +arch_initcall(par_io_populate); diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c index 9b0bba64e91e..7375f92f528b 100644 --- a/drivers/soc/fsl/qe/qe_ports_ic.c +++ b/drivers/soc/fsl/qe/qe_ports_ic.c @@ -5,7 +5,9 @@ * Copyright (c) 2025 Christophe Leroy CS GROUP France (christophe.leroy@csgroup.eu) */ +#include #include +#include #include #include @@ -16,116 +18,158 @@ struct qepic_data { void __iomem *reg; - struct irq_domain *host; - int irq; + int parent_irq; }; static void qepic_mask(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; - clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d))); + guard(raw_spinlock)(&gc->lock); + + val = ioread32be(gc->reg_base + CEPIMR); + iowrite32be(val & ~d->mask, gc->reg_base + CEPIMR); } static void qepic_unmask(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; - setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d))); + guard(raw_spinlock)(&gc->lock); + + val = ioread32be(gc->reg_base + CEPIMR); + iowrite32be(val | d->mask, gc->reg_base + CEPIMR); } static void qepic_end(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d))); + iowrite32be(d->mask, gc->reg_base + CEPIER); +} + +static void qepic_calc_mask(struct irq_data *d) +{ + d->mask = 1 << (31 - irqd_to_hwirq(d)); } static int qepic_set_type(struct irq_data *d, unsigned int flow_type) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); - unsigned int vec = (unsigned int)irqd_to_hwirq(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; + guard(raw_spinlock)(&gc->lock); + + val = ioread32be(gc->reg_base + CEPICR); switch (flow_type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_FALLING: - setbits32(data->reg + CEPICR, 1 << (31 - vec)); + iowrite32be(val | d->mask, gc->reg_base + CEPICR); return 0; case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_NONE: - clrbits32(data->reg + CEPICR, 1 << (31 - vec)); + iowrite32be(val & ~d->mask, gc->reg_base + CEPICR); return 0; } return -EINVAL; } -static struct irq_chip qepic = { - .name = "QEPIC", - .irq_mask = qepic_mask, - .irq_unmask = qepic_unmask, - .irq_eoi = qepic_end, - .irq_set_type = qepic_set_type, -}; - -static int qepic_get_irq(struct irq_desc *desc) -{ - struct qepic_data *data = irq_desc_get_handler_data(desc); - u32 event = in_be32(data->reg + CEPIER); - - if (!event) - return -1; - - return irq_find_mapping(data->host, 32 - ffs(event)); -} - static void qepic_cascade(struct irq_desc *desc) { - generic_handle_irq(qepic_get_irq(desc)); + struct irq_domain *domain = irq_desc_get_handler_data(desc); + struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned long event, bit; + + chained_irq_enter(chip, desc); + + event = ioread32be(gc->reg_base + CEPIER); + if (!event) { + handle_bad_irq(desc); + goto out; + } + + for_each_set_bit(bit, &event, 32) + generic_handle_domain_irq(domain, 31 - bit); + +out: + chained_irq_exit(chip, desc); } -static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) +static int qepic_chip_init(struct irq_chip_generic *gc) { - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq); + struct qepic_data *data = gc->domain->host_data; + struct irq_chip_type *ct = gc->chip_types; + + gc->reg_base = data->reg; + + ct->chip.irq_mask = qepic_mask; + ct->chip.irq_unmask = qepic_unmask; + ct->chip.irq_eoi = qepic_end; + ct->chip.irq_set_type = qepic_set_type; + ct->chip.irq_calc_mask = qepic_calc_mask; + return 0; } -static const struct irq_domain_ops qepic_host_ops = { - .map = qepic_host_map, -}; - -static void qepic_remove(void *res) +static int qepic_domain_init(struct irq_domain *d) { - struct qepic_data *data = res; + struct qepic_data *data = d->host_data; - irq_set_chained_handler_and_data(data->irq, NULL, NULL); - irq_domain_remove(data->host); + irq_set_chained_handler_and_data(data->parent_irq, qepic_cascade, d); + + return 0; +} + +static void qepic_domain_exit(struct irq_domain *d) +{ + struct qepic_data *data = d->host_data; + + irq_set_chained_handler_and_data(data->parent_irq, NULL, NULL); } static int qepic_probe(struct platform_device *pdev) { + struct irq_domain_chip_generic_info dgc_info = { + .name = "QEPIC", + .handler = handle_fasteoi_irq, + .irqs_per_chip = 32, + .num_ct = 1, + .init = qepic_chip_init, + }; + struct irq_domain_info d_info = { + .fwnode = of_fwnode_handle(pdev->dev.of_node), + .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC, + .size = 32, + .hwirq_max = 32, + .ops = &irq_generic_chip_ops, + .dgc_info = &dgc_info, + .init = qepic_domain_init, + .exit = qepic_domain_exit, + }; struct device *dev = &pdev->dev; + struct irq_domain *domain; struct qepic_data *data; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + d_info.host_data = data; data->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(data->reg)) return PTR_ERR(data->reg); - data->irq = platform_get_irq(pdev, 0); - if (data->irq < 0) - return data->irq; + data->parent_irq = platform_get_irq(pdev, 0); + if (data->parent_irq < 0) + return data->parent_irq; - data->host = irq_domain_create_linear(dev_fwnode(dev), 32, &qepic_host_ops, data); - if (!data->host) - return -ENODEV; - - irq_set_chained_handler_and_data(data->irq, qepic_cascade, data); - - return devm_add_action_or_reset(dev, qepic_remove, data); + domain = devm_irq_domain_instantiate(dev, &d_info); + if (IS_ERR(domain)) + return PTR_ERR(domain); + return 0; } static const struct of_device_id qepic_match[] = { diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b3b1ec696bf5..10cff12a3f31 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -611,6 +611,7 @@ config USB_UHCI_ASPEED config USB_FHCI_HCD tristate "Freescale QE USB Host Controller support" depends on QE_GPIO && QUICC_ENGINE + depends on PPC select FSL_GTM select QE_USB help diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h index fdb55ca47a4f..8d5ffb985fee 100644 --- a/include/linux/fsl/guts.h +++ b/include/linux/fsl/guts.h @@ -13,6 +13,7 @@ #include #include +#include /* * Global Utility Registers. @@ -91,9 +92,15 @@ struct ccsr_guts { u32 iovselsr; /* 0x.00c0 - I/O voltage select status register Called 'elbcvselcr' on 86xx SOCs */ u8 res0c4[0x100 - 0xc4]; - u32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers - There are 16 registers */ - u8 res140[0x224 - 0x140]; + /* 0x.0100 - read-only Reset Configuration Word Status registers in + * CCSR, or write-only Reset Configuration Word Control registers in + * DCSR. In both cases there are 32 registers. + */ + union { + u32 rcwsr[32]; + u32 rcwcr[32]; + }; + u8 res180[0x224 - 0x180]; u32 iodelay1; /* 0x.0224 - IO delay control register 1 */ u32 iodelay2; /* 0x.0228 - IO delay control register 2 */ u8 res22c[0x604 - 0x22c]; @@ -131,6 +138,11 @@ struct ccsr_guts { u32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */ } __attribute__ ((packed)); +int fsl_guts_lane_validate(int serdes_idx, int lane, + enum lynx_lane_mode lane_mode); +int fsl_guts_lane_set_mode(int serdes_idx, int lane, + enum lynx_lane_mode lane_mode); + /* Alternate function signal multiplex control */ #define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x)) diff --git a/include/soc/fsl/dpaa2-fd.h b/include/soc/fsl/dpaa2-fd.h index bae490cac0aa..0ca0766b2b0d 100644 --- a/include/soc/fsl/dpaa2-fd.h +++ b/include/soc/fsl/dpaa2-fd.h @@ -25,14 +25,15 @@ /** * struct dpaa2_fd - Struct describing FDs - * @words: for easier/faster copying the whole FD structure - * @addr: address in the FD - * @len: length in the FD - * @bpid: buffer pool ID - * @format_offset: format, offset, and short-length fields - * @frc: frame context - * @ctrl: control bits...including dd, sc, va, err, etc - * @flc: flow context address + * @words: for easier/faster copying the whole FD structure + * @simple: struct for the FD fields + * @simple.addr: address in the FD + * @simple.len: length in the FD + * @simple.bpid: buffer pool ID + * @simple.format_offset: format, offset, and short-length fields + * @simple.frc: frame context + * @simple.ctrl: control bits...including dd, sc, va, err, etc + * @simple.flc: flow context address * * This structure represents the basic Frame Descriptor used in the system. */ @@ -497,7 +498,7 @@ static inline void dpaa2_fl_set_addr(struct dpaa2_fl_entry *fle, * dpaa2_fl_get_frc() - Get the frame context in the FLE * @fle: the given frame list entry * - * Return the frame context field in the frame lsit entry. + * Return the frame context field in the frame list entry. */ static inline u32 dpaa2_fl_get_frc(const struct dpaa2_fl_entry *fle) { diff --git a/include/soc/fsl/dpaa2-io.h b/include/soc/fsl/dpaa2-io.h index 4bf62de2e00e..2a748fafa5b7 100644 --- a/include/soc/fsl/dpaa2-io.h +++ b/include/soc/fsl/dpaa2-io.h @@ -22,7 +22,7 @@ struct device; * DOC: DPIO Service * * The DPIO service provides APIs for users to interact with the datapath - * by enqueueing and dequeing frame descriptors. + * by enqueueing and dequeueing frame descriptors. * * The following set of APIs can be used to enqueue and dequeue frames * as well as producing notification callbacks when data is available @@ -33,7 +33,7 @@ struct device; /** * struct dpaa2_io_desc - The DPIO descriptor - * @receives_notifications: Use notificaton mode. Non-zero if the DPIO + * @receives_notifications: Use notification mode. Non-zero if the DPIO * has a channel. * @has_8prio: Set to non-zero for channel with 8 priority WQs. Ignored * unless receives_notification is TRUE.