* [PATCH v7 0/6] mfd: Add support for NXP MC33978/MC34978 MSDI
From: Oleksij Rempel @ 2026-03-27 16:34 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Lee Jones, Peter Rosin, Linus Walleij
Cc: Oleksij Rempel, kernel, linux-kernel, devicetree, linux-hwmon,
linux-gpio, David Jander
changes v7:
- drop gpiolib irq fix and make pinctrl more robust against NULL point
dereference.
This series adds support for the NXP MC33978/MC34978 Multiple Switch Detection
Interface (MSDI) via the MFD framework.
Architecture overview:
* mfd: Core driver handling 2-frame pipelined SPI, regulator sequencing, and
linear irq_domain. Harvests status bits from SPI MISO MSB.
* pinctrl: Exposes 22 physical switch inputs as standard GPIOs. Proxies IRQs to
the MFD domain.
* hwmon: Exposes thermal limits, VBATP/VDDQ voltage boundaries, and dynamic
fault alarms.
* mux: Controls the 24-to-1 AMUX routing analog signals (switch voltages,
temperature, VBATP) to an external ADC.
Initial pinctrl implementation by David Jander, reworked into this MFD
architecture.
Best regards,
Oleksij
David Jander (1):
pinctrl: add NXP MC33978/MC34978 pinctrl driver
Oleksij Rempel (5):
dt-bindings: pinctrl: add NXP MC33978/MC34978 MSDI
mfd: add NXP MC33978/MC34978 core driver
pinctrl: core: Make pin group callbacks optional for pin-only drivers
hwmon: add NXP MC33978/MC34978 driver
mux: add NXP MC33978/MC34978 AMUX driver
.../bindings/pinctrl/nxp,mc33978.yaml | 153 +++
drivers/hwmon/Kconfig | 10 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/mc33978-hwmon.c | 548 ++++++++++
drivers/mfd/Kconfig | 15 +
drivers/mfd/Makefile | 2 +
drivers/mfd/mc33978.c | 933 ++++++++++++++++++
drivers/mux/Kconfig | 14 +
drivers/mux/Makefile | 2 +
drivers/mux/mc33978-mux.c | 136 +++
drivers/pinctrl/Kconfig | 14 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/core.c | 41 +-
drivers/pinctrl/pinconf.c | 9 +-
drivers/pinctrl/pinctrl-mc33978.c | 836 ++++++++++++++++
include/linux/mfd/mc33978.h | 92 ++
16 files changed, 2800 insertions(+), 7 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pinctrl/nxp,mc33978.yaml
create mode 100644 drivers/hwmon/mc33978-hwmon.c
create mode 100644 drivers/mfd/mc33978.c
create mode 100644 drivers/mux/mc33978-mux.c
create mode 100644 drivers/pinctrl/pinctrl-mc33978.c
create mode 100644 include/linux/mfd/mc33978.h
--
2.47.3
^ permalink raw reply
* [PATCH v7 3/6] pinctrl: core: Make pin group callbacks optional for pin-only drivers
From: Oleksij Rempel @ 2026-03-27 16:34 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Lee Jones, Peter Rosin, Linus Walleij
Cc: Oleksij Rempel, kernel, linux-kernel, devicetree, linux-hwmon,
linux-gpio, David Jander
In-Reply-To: <20260327163450.3287313-1-o.rempel@pengutronix.de>
Currently, the pinctrl core strictly requires all drivers to implement
.get_groups_count and .get_group_name callbacks in their pinctrl_ops.
However, for simple pinctrl drivers that act purely as GPIO controllers
and pin-specific configuration proxies, without any concept of muxing or
pin groups, this strict requirement forces the implementation of dummy
callbacks just to satisfy pinctrl_check_ops().
Relax this requirement for pin-only drivers by making the group callbacks
optional when no muxing or group pin configuration support is provided.
Update the core and debugfs helpers to check for the existence of these
callbacks before invoking them.
Drivers that provide muxing or group pin configuration operations still
must implement group enumeration and naming callbacks, and are rejected
at registration time if they do not.
Suggested-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Linus Walleij <linusw@kernel.org>
---
changes v7:
- no changes
changes v6:
- Reject drivers in pinctrl_check_ops() that use pmxops or group confops
without providing group callbacks.
- Add <linux/pinctrl/pinconf.h> to core.c.
- Revert the unnecessary NULL check in pinconf_show_setting(), since
group settings are now strictly gated.
- Keep debugfs group listings tolerant of drivers without group callbacks.
changes v5:
- no changes
changes v4:
- add Reviewed-by: Linus Walleij ...
changes v3:
- no changes
---
drivers/pinctrl/core.c | 41 ++++++++++++++++++++++++++++++++++-----
drivers/pinctrl/pinconf.c | 9 +++++++--
2 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index b5e97689589f..19a9a370d7b9 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -30,6 +30,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include "core.h"
@@ -621,8 +622,13 @@ static int pinctrl_generic_group_name_to_selector(struct pinctrl_dev *pctldev,
const char *function)
{
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
- int ngroups = ops->get_groups_count(pctldev);
int selector = 0;
+ int ngroups;
+
+ if (!ops->get_groups_count || !ops->get_group_name)
+ return -EINVAL;
+
+ ngroups = ops->get_groups_count(pctldev);
/* See if this pctldev has this group */
while (selector < ngroups) {
@@ -737,8 +743,15 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
const char *pin_group)
{
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- unsigned int ngroups = pctlops->get_groups_count(pctldev);
unsigned int group_selector = 0;
+ unsigned int ngroups;
+
+ if (!pctlops->get_groups_count || !pctlops->get_group_name) {
+ dev_err(pctldev->dev, "does not support pin groups\n");
+ return -EINVAL;
+ }
+
+ ngroups = pctlops->get_groups_count(pctldev);
while (group_selector < ngroups) {
const char *gname = pctlops->get_group_name(pctldev,
@@ -1769,6 +1782,11 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
mutex_lock(&pctldev->mutex);
+ if (!ops->get_groups_count || !ops->get_group_name) {
+ mutex_unlock(&pctldev->mutex);
+ return 0;
+ }
+
ngroups = ops->get_groups_count(pctldev);
seq_puts(s, "registered pin groups:\n");
@@ -2049,12 +2067,25 @@ static void pinctrl_remove_device_debugfs(struct pinctrl_dev *pctldev)
static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
{
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
+ const struct pinconf_ops *confops = pctldev->desc->confops;
+ bool needs_groups = false;
- if (!ops ||
- !ops->get_groups_count ||
- !ops->get_group_name)
+ if (!ops)
return -EINVAL;
+ if (pctldev->desc->pmxops)
+ needs_groups = true;
+
+ if (confops && (confops->pin_config_group_get ||
+ confops->pin_config_group_set))
+ needs_groups = true;
+
+ if (needs_groups && (!ops->get_groups_count || !ops->get_group_name)) {
+ dev_err(pctldev->dev,
+ "driver needs group callbacks for mux or group config\n");
+ return -EINVAL;
+ }
+
return 0;
}
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index dca963633b5d..81686844dfa5 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -275,7 +275,7 @@ void pinconf_show_setting(struct seq_file *s,
case PIN_MAP_TYPE_CONFIGS_GROUP:
seq_printf(s, "group %s (%d)",
pctlops->get_group_name(pctldev,
- setting->data.configs.group_or_pin),
+ setting->data.configs.group_or_pin),
setting->data.configs.group_or_pin);
break;
default:
@@ -348,8 +348,13 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- unsigned int ngroups = pctlops->get_groups_count(pctldev);
unsigned int selector = 0;
+ unsigned int ngroups;
+
+ if (!pctlops->get_groups_count || !pctlops->get_group_name)
+ return 0;
+
+ ngroups = pctlops->get_groups_count(pctldev);
seq_puts(s, "Pin config settings per pin group\n");
seq_puts(s, "Format: group (name): configs\n");
--
2.47.3
^ permalink raw reply related
* [PATCH v1 1/1] arm64: dts: imx91-var-dart-sonata: add RGB select supply for PCA6408
From: Stefano Radaelli @ 2026-03-27 16:32 UTC (permalink / raw)
To: linux-kernel, devicetree, imx, linux-arm-kernel
Cc: pierluigi.p, Stefano Radaelli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam
From: Stefano Radaelli <stefano.r@variscite.com>
RGB_SEL controls the routing of some carrier board lines on the Sonata
board. The two PCA6408 GPIO expanders depend on that path being enabled,
so describe the selector as a fixed regulator and use it as their
vcc-supply.
Signed-off-by: Stefano Radaelli <stefano.r@variscite.com>
---
arch/arm64/boot/dts/freescale/imx91-var-dart-sonata.dts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx91-var-dart-sonata.dts b/arch/arm64/boot/dts/freescale/imx91-var-dart-sonata.dts
index afa39dab240a..3b5816884f24 100644
--- a/arch/arm64/boot/dts/freescale/imx91-var-dart-sonata.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-var-dart-sonata.dts
@@ -90,6 +90,13 @@ reg_vref_1v8: regulator-adc-vref {
regulator-max-microvolt = <1800000>;
};
+ reg_rgb_sel: regulator-rgb-sel {
+ compatible = "regulator-fixed";
+ regulator-name = "rgb-select";
+ gpio = <&pca9534 7 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
reg_usdhc2_vmmc: regulator-vmmc-usdhc2 {
compatible = "regulator-fixed";
pinctrl-names = "default";
@@ -195,6 +202,7 @@ pca6408_1: gpio@20 {
#gpio-cells = <2>;
interrupt-parent = <&gpio1>;
interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
+ vcc-supply = <®_rgb_sel>;
};
pca6408_2: gpio@21 {
@@ -204,6 +212,7 @@ pca6408_2: gpio@21 {
#gpio-cells = <2>;
interrupt-parent = <&gpio1>;
interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
+ vcc-supply = <®_rgb_sel>;
};
pca9534: gpio@22 {
--
2.47.3
^ permalink raw reply related
* Re: [PATCH v8 2/2] hwmon: temperature: add support for EMC1812
From: Marius.Cristea @ 2026-03-27 16:30 UTC (permalink / raw)
To: linux
Cc: corbet, linux-hwmon, devicetree, robh, linux-kernel, krzk+dt,
linux-doc, conor+dt
In-Reply-To: <f1e55e6e-a374-4b97-b1f3-706d627ebab5@roeck-us.net>
Hi Guenther,
Thanks for the review, please see my comments below:
...
>
>
>
>
> > +static int emc1812_init(struct emc1812_data *priv)
> > +{
> > + int ret;
> > + u8 val;
> > +
> > + /*
> > + * Set default values in registers. APDD, RECD12 and RECD34
> > are active
> > + * on 0. Set ALERT pin to be in comparator mode.
> > + * Set the device to be in Run (Active) state and converting
> > on all
> > + * channels.
> > + * Don't change conversion rate. After reset, default is 4
> > conversions/seconds.
> > + * The temperature measurement range is -64°C to +191.875°C.
> > + */
> > + val = FIELD_PREP(EMC1812_CFG_MSKAL, 1) |
> > + FIELD_PREP(EMC1812_CFG_RS, 0) |
> > + FIELD_PREP(EMC1812_CFG_ATTHM, 1) |
> > + FIELD_PREP(EMC1812_CFG_RECD12, !priv->recd12_en) |
> > + FIELD_PREP(EMC1812_CFG_RECD34, !priv->recd34_en) |
> > + FIELD_PREP(EMC1812_CFG_RANGE, 1) |
> > + FIELD_PREP(EMC1812_CFG_DA_ENA, 0) |
> > + FIELD_PREP(EMC1812_CFG_APDD, !priv->apdd_en);
> > +
>
> I assume it is on purpose that the defaults for EMC1812_CFG_RECD12
> and
> EMC1812_CFG_RECD34 deviate from the chip default (chip: enabled;
> driver:
> disabled).
>
Yes, EMC1812_CFG_ATTHM was set in order for the alerts to be clear
automaticaly when the limits goes back to normal.
The EMC1812_CFG_RANGE is set to extended range in order to be able to
measure from the -64 to 191,875 degree Celsius.
The EMC1812_CFG_MSKAL could be left at the "reset", so I will change it
to 0.
The EMC1812_CFG_RECD12 and EMC1812_CFG_RECD34 will be set based on the
device tree setting and is related to the hardware and if the system
designer wants to enable or disable the resistance error correction.
> > + ret = regmap_write(priv->regmap, EMC1812_CFG_ADDR, val);
> > + if (ret)
> > + return ret;
> > +
> > + ret = regmap_write(priv->regmap, EMC1812_THRM_HYS_ADDR,
> > 0x0A);
> > + if (ret)
> > + return ret;
> > +
> > + ret = regmap_write(priv->regmap, EMC1812_CONSEC_ALERT_ADDR,
> > 0x70);
> > + if (ret)
> > + return ret;
> > +
> > + ret = regmap_write(priv->regmap, EMC1812_FILTER_SEL_ADDR, 0);
> > + if (ret)
> > + return ret;
> > +
> > + ret = regmap_write(priv->regmap, EMC1812_HOTTEST_CFG_ADDR,
> > 0);
> > + if (ret)
> > + return ret;
> > +
> > + /* Enables the beta compensation factor auto-detection
> > function for beta1 and beta2 */
> > + ret = regmap_write(priv->regmap,
> > EMC1812_EXT1_BETA_CONFIG_ADDR,
> > + EMC1812_BETA_LOCK_VAL);
> > + if (ret)
> > + return ret;
> > +
> > + ret = regmap_write(priv->regmap,
> > EMC1812_EXT2_BETA_CONFIG_ADDR,
>
> AI review thinks that this register only exists on EMC1812. I don't
> find that detail in the datasheet, but it is odd that there are two
> registers
> with supposedly the same functionality.
>
>
All devices "have" the EMC1812_EXT2_BETA_CONFIG register (I mean if you
are writing something to it, there will be no NAK on the i2c bus, but
the value read back will be "0" for the devices that has the register
not writable).
EMC1812 having only one external channel, will not have the
EMC1812_EXT2_BETA_CONFIG writable.
Regards,
Marius
^ permalink raw reply
* RE: [PATCH net-next 5/5] dpll: zl3073x: add ref-sync pair support
From: Prathosh.Satish @ 2026-03-27 16:24 UTC (permalink / raw)
To: ivecera, netdev
Cc: arkadiusz.kubalewski, jiri, mschmidt, poros, horms,
vadim.fedorenko, linux-kernel, conor+dt, krzk+dt, robh,
devicetree, pvaanane
In-Reply-To: <20260319174826.7623-6-ivecera@redhat.com>
Reviewed-by: prathosh.satish@microchip.com
-----Original Message-----
From: Ivan Vecera <ivecera@redhat.com>
Sent: Thursday, March 19, 2026 5:48 PM
To: netdev@vger.kernel.org
Cc: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>; Jiri Pirko <jiri@resnulli.us>; Michal Schmidt <mschmidt@redhat.com>; Petr Oros <poros@redhat.com>; Prathosh Satish - M66066 <Prathosh.Satish@microchip.com>; Simon Horman <horms@kernel.org>; Vadim Fedorenko <vadim.fedorenko@linux.dev>; linux-kernel@vger.kernel.org; Conor Dooley <conor+dt@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>; Rob Herring <robh@kernel.org>; devicetree@vger.kernel.org; Pasi Vaananen <pvaanane@redhat.com>
Subject: [PATCH net-next 5/5] dpll: zl3073x: add ref-sync pair support
EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
Add support for ref-sync pair registration using the 'ref-sync-sources'
phandle property from device tree. A ref-sync pair consists of a clock reference and a low-frequency sync signal where the DPLL locks to the clock reference but phase-aligns to the sync reference.
The implementation:
- Stores fwnode handle in zl3073x_dpll_pin during pin registration
- Adds ref_sync_get/set callbacks to read and write the sync control
mode and pair registers
- Validates ref-sync frequency constraints: sync signal must be 8 kHz
or less, clock reference must be 1 kHz or more and higher than sync
- Excludes sync source from automatic reference selection by setting
its priority to NONE on connect; on disconnect the priority is left
as NONE and the user must explicitly make the pin selectable again
- Iterates ref-sync-sources phandles to register declared pairings
via dpll_pin_ref_sync_pair_add()
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/dpll.c | 207 +++++++++++++++++++++++++++++++++++-
1 file changed, 206 insertions(+), 1 deletion(-)
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c index 276f0a92db0b1..8010e2635f641 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/sprintf.h>
@@ -30,6 +31,7 @@
* @dpll: DPLL the pin is registered to
* @dpll_pin: pointer to registered dpll_pin
* @tracker: tracking object for the acquired reference
+ * @fwnode: firmware node handle
* @label: package label
* @dir: pin direction
* @id: pin id
@@ -45,6 +47,7 @@ struct zl3073x_dpll_pin {
struct zl3073x_dpll *dpll;
struct dpll_pin *dpll_pin;
dpll_tracker tracker;
+ struct fwnode_handle *fwnode;
char label[8];
enum dpll_pin_direction dir;
u8 id;
@@ -184,6 +187,109 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
return zl3073x_ref_state_set(zldev, ref_id, &ref); }
+static int
+zl3073x_dpll_input_pin_ref_sync_get(const struct dpll_pin *dpll_pin,
+ void *pin_priv,
+ const struct dpll_pin *ref_sync_pin,
+ void *ref_sync_pin_priv,
+ enum dpll_pin_state *state,
+ struct netlink_ext_ack *extack) {
+ struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
+ struct zl3073x_dpll_pin *pin = pin_priv;
+ struct zl3073x_dpll *zldpll = pin->dpll;
+ struct zl3073x_dev *zldev = zldpll->dev;
+ const struct zl3073x_ref *ref;
+ u8 ref_id, mode, pair;
+
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = zl3073x_ref_state_get(zldev, ref_id);
+ mode = zl3073x_ref_sync_mode_get(ref);
+ pair = zl3073x_ref_sync_pair_get(ref);
+
+ if (mode == ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR &&
+ pair == zl3073x_input_pin_ref_get(sync_pin->id))
+ *state = DPLL_PIN_STATE_CONNECTED;
+ else
+ *state = DPLL_PIN_STATE_DISCONNECTED;
+
+ return 0;
+}
+
+static int
+zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin,
+ void *pin_priv,
+ const struct dpll_pin *ref_sync_pin,
+ void *ref_sync_pin_priv,
+ const enum dpll_pin_state state,
+ struct netlink_ext_ack *extack) {
+ struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
+ struct zl3073x_dpll_pin *pin = pin_priv;
+ struct zl3073x_dpll *zldpll = pin->dpll;
+ struct zl3073x_dev *zldev = zldpll->dev;
+ u8 mode, ref_id, sync_ref_id;
+ struct zl3073x_chan chan;
+ struct zl3073x_ref ref;
+ int rc;
+
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ sync_ref_id = zl3073x_input_pin_ref_get(sync_pin->id);
+ ref = *zl3073x_ref_state_get(zldev, ref_id);
+
+ if (state == DPLL_PIN_STATE_CONNECTED) {
+ const struct zl3073x_ref *sync_ref;
+ u32 ref_freq, sync_freq;
+
+ sync_ref = zl3073x_ref_state_get(zldev, sync_ref_id);
+ ref_freq = zl3073x_ref_freq_get(&ref);
+ sync_freq = zl3073x_ref_freq_get(sync_ref);
+
+ /* Sync signal must be 8 kHz or less and clock reference
+ * must be 1 kHz or more and higher than the sync signal.
+ */
+ if (sync_freq > 8000) {
+ NL_SET_ERR_MSG(extack,
+ "sync frequency must be 8 kHz or less");
+ return -EINVAL;
+ }
+ if (ref_freq < 1000) {
+ NL_SET_ERR_MSG(extack,
+ "clock frequency must be 1 kHz or more");
+ return -EINVAL;
+ }
+ if (ref_freq <= sync_freq) {
+ NL_SET_ERR_MSG(extack,
+ "clock frequency must be higher than sync frequency");
+ return -EINVAL;
+ }
+
+ zl3073x_ref_sync_pair_set(&ref, sync_ref_id);
+ mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR;
+ } else {
+ mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF;
+ }
+
+ zl3073x_ref_sync_mode_set(&ref, mode);
+
+ rc = zl3073x_ref_state_set(zldev, ref_id, &ref);
+ if (rc)
+ return rc;
+
+ /* Exclude sync source from automatic reference selection by setting
+ * its priority to NONE. On disconnect the priority is left as NONE
+ * and the user must explicitly make the pin selectable again.
+ */
+ if (state == DPLL_PIN_STATE_CONNECTED) {
+ chan = *zl3073x_chan_state_get(zldev, zldpll->id);
+ zl3073x_chan_ref_prio_set(&chan, sync_ref_id,
+ ZL_DPLL_REF_PRIO_NONE);
+ return zl3073x_chan_state_set(zldev, zldpll->id, &chan);
+ }
+
+ return 0;
+}
+
static int
zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv, @@ -1100,6 +1206,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
.phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set,
.prio_get = zl3073x_dpll_input_pin_prio_get,
.prio_set = zl3073x_dpll_input_pin_prio_set,
+ .ref_sync_get = zl3073x_dpll_input_pin_ref_sync_get,
+ .ref_sync_set = zl3073x_dpll_input_pin_ref_sync_set,
.state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get,
.state_on_dpll_set = zl3073x_dpll_input_pin_state_on_dpll_set,
};
@@ -1190,8 +1298,11 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
if (IS_ERR(props))
return PTR_ERR(props);
- /* Save package label, esync capability and phase adjust granularity */
+ /* Save package label, fwnode, esync capability and phase adjust
+ * granularity.
+ */
strscpy(pin->label, props->package_label);
+ pin->fwnode = fwnode_handle_get(props->fwnode);
pin->esync_control = props->esync_control;
pin->phase_gran = props->dpll_props.phase_gran;
@@ -1236,6 +1347,8 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
dpll_pin_put(pin->dpll_pin, &pin->tracker);
pin->dpll_pin = NULL;
err_pin_get:
+ fwnode_handle_put(pin->fwnode);
+ pin->fwnode = NULL;
zl3073x_pin_props_put(props);
return rc;
@@ -1265,6 +1378,9 @@ zl3073x_dpll_pin_unregister(struct zl3073x_dpll_pin *pin)
dpll_pin_put(pin->dpll_pin, &pin->tracker);
pin->dpll_pin = NULL;
+
+ fwnode_handle_put(pin->fwnode);
+ pin->fwnode = NULL;
}
/**
@@ -1735,6 +1851,88 @@ zl3073x_dpll_free(struct zl3073x_dpll *zldpll)
kfree(zldpll);
}
+/**
+ * zl3073x_dpll_ref_sync_pair_register - register ref_sync pairs for a
+pin
+ * @pin: pointer to zl3073x_dpll_pin structure
+ *
+ * Iterates 'ref-sync-sources' phandles in the pin's firmware node and
+ * registers each declared pairing.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_dpll_ref_sync_pair_register(struct zl3073x_dpll_pin *pin) {
+ struct zl3073x_dev *zldev = pin->dpll->dev;
+ struct fwnode_handle *fwnode;
+ struct dpll_pin *sync_pin;
+ dpll_tracker tracker;
+ int n, rc;
+
+ for (n = 0; ; n++) {
+ /* Get n'th ref-sync source */
+ fwnode = fwnode_find_reference(pin->fwnode, "ref-sync-sources",
+ n);
+ if (IS_ERR(fwnode)) {
+ rc = PTR_ERR(fwnode);
+ break;
+ }
+
+ /* Find associated dpll pin */
+ sync_pin = fwnode_dpll_pin_find(fwnode, &tracker);
+ fwnode_handle_put(fwnode);
+ if (!sync_pin) {
+ dev_warn(zldev->dev, "%s: ref-sync source %d not found",
+ pin->label, n);
+ continue;
+ }
+
+ /* Register new ref-sync pair */
+ rc = dpll_pin_ref_sync_pair_add(pin->dpll_pin, sync_pin);
+ dpll_pin_put(sync_pin, &tracker);
+
+ /* -EBUSY means pairing already exists from another DPLL's
+ * registration.
+ */
+ if (rc && rc != -EBUSY) {
+ dev_err(zldev->dev,
+ "%s: failed to add ref-sync source %d: %pe",
+ pin->label, n, ERR_PTR(rc));
+ break;
+ }
+ }
+
+ return rc != -ENOENT ? rc : 0;
+}
+
+/**
+ * zl3073x_dpll_ref_sync_pairs_register - register ref_sync pairs for a
+DPLL
+ * @zldpll: pointer to zl3073x_dpll structure
+ *
+ * Iterates all registered input pins of the given DPLL and establishes
+ * ref_sync pairings declared by 'ref-sync-sources' phandles in the
+ * device tree.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_dpll_ref_sync_pairs_register(struct zl3073x_dpll *zldpll) {
+ struct zl3073x_dpll_pin *pin;
+ int rc;
+
+ list_for_each_entry(pin, &zldpll->pins, list) {
+ if (!zl3073x_dpll_is_input_pin(pin) || !pin->fwnode)
+ continue;
+
+ rc = zl3073x_dpll_ref_sync_pair_register(pin);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
/**
* zl3073x_dpll_register - register DPLL device and all its pins
* @zldpll: pointer to zl3073x_dpll structure @@ -1758,6 +1956,13 @@ zl3073x_dpll_register(struct zl3073x_dpll *zldpll)
return rc;
}
+ rc = zl3073x_dpll_ref_sync_pairs_register(zldpll);
+ if (rc) {
+ zl3073x_dpll_pins_unregister(zldpll);
+ zl3073x_dpll_device_unregister(zldpll);
+ return rc;
+ }
+
return 0;
}
--
2.52.0
^ permalink raw reply
* [PATCH 2/2] remoteproc: qcom: pas: Add Eliza ADSP support
From: Abel Vesa @ 2026-03-27 16:18 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Luca Weiss
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
Abel Vesa
In-Reply-To: <20260327-eliza-remoteproc-adsp-v1-0-1c46c5e5f809@oss.qualcomm.com>
The ADSP found on Eliza SoC is similar to the one found on SM8550.
So just add the dedicated compatible for Eliza ADSP and reuse the
SM8550 resource configuration.
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
---
drivers/remoteproc/qcom_q6v5_pas.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 46204da046fa..671e57b47a34 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -1531,6 +1531,7 @@ static const struct qcom_pas_data sm8750_mpss_resource = {
};
static const struct of_device_id qcom_pas_of_match[] = {
+ { .compatible = "qcom,eliza-adsp-pas", .data = &sm8550_adsp_resource},
{ .compatible = "qcom,milos-adsp-pas", .data = &sm8550_adsp_resource},
{ .compatible = "qcom,milos-cdsp-pas", .data = &milos_cdsp_resource},
{ .compatible = "qcom,milos-mpss-pas", .data = &sm8450_mpss_resource},
--
2.48.1
^ permalink raw reply related
* [PATCH 1/2] dt-bindings: remoteproc: qcom,milos-pas: Document Eliza ADSP
From: Abel Vesa @ 2026-03-27 16:18 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Luca Weiss
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
Abel Vesa
In-Reply-To: <20260327-eliza-remoteproc-adsp-v1-0-1c46c5e5f809@oss.qualcomm.com>
Since the devicetree bindings are exactly the same between Eliza ADSP and
Milos ADSP, reuse the existing Milos schema, just add the Eliza specific
ADSP compatible.
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
---
Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml
index c47d97004b33..e5cce0d05fc6 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml
@@ -16,6 +16,7 @@ description:
properties:
compatible:
enum:
+ - qcom,eliza-adsp-pas
- qcom,milos-adsp-pas
- qcom,milos-cdsp-pas
- qcom,milos-mpss-pas
@@ -69,6 +70,7 @@ allOf:
properties:
compatible:
enum:
+ - qcom,eliza-adsp-pas
- qcom,milos-adsp-pas
- qcom,milos-cdsp-pas
then:
@@ -89,6 +91,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,eliza-adsp-pas
- qcom,milos-adsp-pas
then:
properties:
--
2.48.1
^ permalink raw reply related
* [PATCH 0/2] remoteproc: qcom: pas: Add supoport for Eliza ADSP
From: Abel Vesa @ 2026-03-27 16:18 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Luca Weiss
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
Abel Vesa
Add support for ADSP remoteproc found on Qualcomm Eliza SoC.
The rest of the remoteprocs will come later.
Instead of adding a dedicated bindings schema, just reuse the Milos one
as bindings are exactly the same.
Then, just add the compatible and reuse the SM8550 configuration in the
driver.
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
---
Abel Vesa (2):
dt-bindings: remoteproc: qcom,milos-pas: Document Eliza ADSP
remoteproc: qcom: pas: Add Eliza ADSP support
Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml | 3 +++
drivers/remoteproc/qcom_q6v5_pas.c | 1 +
2 files changed, 4 insertions(+)
---
base-commit: e77a5a5cfe43b4c25bd44a3818e487033287517f
change-id: 20260327-eliza-remoteproc-adsp-fa7dbbc71d74
Best regards,
--
Abel Vesa <abel.vesa@oss.qualcomm.com>
^ permalink raw reply
* [PATCH v2 9/9] arm64: dts: qcom: milos: Add display (MDSS)
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Add device nodes for display: MDSS, DPU, DSI and DSI PHY.
DisplayPort is not added for now.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
arch/arm64/boot/dts/qcom/milos.dtsi | 211 +++++++++++++++++++++++++++++++++++-
1 file changed, 209 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/milos.dtsi b/arch/arm64/boot/dts/qcom/milos.dtsi
index 67f8ef4d524a..c1be2f43dbb8 100644
--- a/arch/arm64/boot/dts/qcom/milos.dtsi
+++ b/arch/arm64/boot/dts/qcom/milos.dtsi
@@ -3,6 +3,7 @@
* Copyright (c) 2025, Luca Weiss <luca.weiss@fairphone.com>
*/
+#include <dt-bindings/clock/qcom,dsi-phy-28nm.h>
#include <dt-bindings/clock/qcom,milos-camcc.h>
#include <dt-bindings/clock/qcom,milos-dispcc.h>
#include <dt-bindings/clock/qcom,milos-gcc.h>
@@ -1860,6 +1861,212 @@ camcc: clock-controller@adb0000 {
#power-domain-cells = <1>;
};
+ mdss: display-subsystem@ae00000 {
+ compatible = "qcom,milos-mdss";
+ reg = <0x0 0x0ae00000 0x0 0x1000>;
+ reg-names = "mdss";
+
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH 0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+
+ resets = <&dispcc DISP_CC_MDSS_CORE_BCR>;
+
+ interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+ <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
+ &cnoc_main SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>;
+ interconnect-names = "mdp0-mem",
+ "cpu-cfg";
+
+ power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>;
+
+ iommus = <&apps_smmu 0x1c00 0x2>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ status = "disabled";
+
+ mdss_mdp: display-controller@ae01000 {
+ compatible = "qcom,milos-dpu";
+ reg = <0x0 0x0ae01000 0x0 0x8f000>,
+ <0x0 0x0aeb0000 0x0 0x3000>;
+ reg-names = "mdp",
+ "vbif";
+
+ interrupts-extended = <&mdss 0>;
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "nrt_bus",
+ "iface",
+ "lut",
+ "core",
+ "vsync";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ operating-points-v2 = <&mdp_opp_table>;
+
+ power-domains = <&rpmhpd RPMHPD_CX>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&mdss_dsi0_in>;
+ };
+ };
+ };
+
+ mdp_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-342000000 {
+ opp-hz = /bits/ 64 <342000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-402000000 {
+ opp-hz = /bits/ 64 <402000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+
+ opp-535000000 {
+ opp-hz = /bits/ 64 <535000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ required-opps = <&rpmhpd_opp_nom_l1>;
+ };
+
+ opp-630000000 {
+ opp-hz = /bits/ 64 <630000000>;
+ required-opps = <&rpmhpd_opp_turbo>;
+ };
+ };
+ };
+
+ mdss_dsi0: dsi@ae94000 {
+ compatible = "qcom,milos-dsi-ctrl", "qcom,mdss-dsi-ctrl";
+ reg = <0x0 0x0ae94000 0x0 0x1000>;
+ reg-names = "dsi_ctrl";
+
+ interrupts-extended = <&mdss 4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>,
+ <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>;
+
+ operating-points-v2 = <&mdss_dsi_opp_table>;
+
+ power-domains = <&rpmhpd RPMHPD_CX>;
+
+ phys = <&mdss_dsi0_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mdss_dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mdss_dsi0_out: endpoint {
+ };
+ };
+ };
+
+ mdss_dsi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-187500000 {
+ opp-hz = /bits/ 64 <187500000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-358000000 {
+ opp-hz = /bits/ 64 <358000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+ };
+ };
+
+ mdss_dsi0_phy: phy@ae95000 {
+ compatible = "qcom,milos-dsi-phy-4nm";
+ reg = <0x0 0x0ae95000 0x0 0x200>,
+ <0x0 0x0ae95200 0x0 0x300>,
+ <0x0 0x0ae95500 0x0 0x400>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface",
+ "ref";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+
+ status = "disabled";
+ };
+ };
+
dispcc: clock-controller@af00000 {
compatible = "qcom,milos-dispcc";
reg = <0x0 0x0af00000 0x0 0x20000>;
@@ -1868,8 +2075,8 @@ dispcc: clock-controller@af00000 {
<&sleep_clk>,
<&gcc GCC_DISP_AHB_CLK>,
<&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>,
- <0>, /* dsi0_phy_pll_out_byteclk */
- <0>, /* dsi0_phy_pll_out_dsiclk */
+ <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>,
+ <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>,
<0>, /* dp0_phy_pll_link_clk */
<0>; /* dp0_phy_pll_vco_div_clk */
--
2.53.0
^ permalink raw reply related
* [PATCH v2 8/9] drm/msm/dpu: Add Milos support
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Add definitions for the display hardware used on the Qualcomm Milos
platform.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
.../gpu/drm/msm/disp/dpu1/catalog/dpu_10_2_milos.h | 279 +++++++++++++++++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 29 +++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 1 +
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 +
4 files changed, 310 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_2_milos.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_2_milos.h
new file mode 100644
index 000000000000..1aa8aea4e352
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_2_milos.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2026, Luca Weiss <luca.weiss@fairphone.com>
+ */
+
+#ifndef _DPU_10_2_MILOS_H
+#define _DPU_10_2_MILOS_H
+
+static const struct dpu_caps milos_dpu_caps = {
+ .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
+ .max_mixer_blendstages = 0x7,
+ .has_src_split = true,
+ .has_dim_layer = true,
+ .has_idle_pc = true,
+ .has_3d_merge = true,
+ .max_linewidth = 8192,
+ .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
+};
+
+static const struct dpu_mdp_cfg milos_mdp = {
+ .name = "top_0",
+ .base = 0, .len = 0x494,
+ .clk_ctrls = {
+ [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 },
+ },
+};
+
+static const struct dpu_ctl_cfg milos_ctl[] = {
+ {
+ .name = "ctl_0", .id = CTL_0,
+ .base = 0x15000, .len = 0x1000,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9),
+ }, {
+ .name = "ctl_1", .id = CTL_1,
+ .base = 0x16000, .len = 0x1000,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10),
+ }, {
+ .name = "ctl_2", .id = CTL_2,
+ .base = 0x17000, .len = 0x1000,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11),
+ }, {
+ .name = "ctl_3", .id = CTL_3,
+ .base = 0x18000, .len = 0x1000,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12),
+ },
+};
+
+static const struct dpu_sspp_cfg milos_sspp[] = {
+ {
+ .name = "sspp_0", .id = SSPP_VIG0,
+ .base = 0x4000, .len = 0x344,
+ .features = VIG_SDM845_MASK_SDMA,
+ .sblk = &dpu_vig_sblk_qseed3_3_3,
+ .xin_id = 0,
+ .type = SSPP_TYPE_VIG,
+ }, {
+ .name = "sspp_8", .id = SSPP_DMA0,
+ .base = 0x24000, .len = 0x344,
+ .features = DMA_SDM845_MASK_SDMA,
+ .sblk = &dpu_dma_sblk,
+ .xin_id = 1,
+ .type = SSPP_TYPE_DMA,
+ }, {
+ .name = "sspp_9", .id = SSPP_DMA1,
+ .base = 0x26000, .len = 0x344,
+ .features = DMA_SDM845_MASK_SDMA,
+ .sblk = &dpu_dma_sblk,
+ .xin_id = 5,
+ .type = SSPP_TYPE_DMA,
+ }, {
+ .name = "sspp_10", .id = SSPP_DMA2,
+ .base = 0x28000, .len = 0x344,
+ .features = DMA_SDM845_MASK_SDMA,
+ .sblk = &dpu_dma_sblk,
+ .xin_id = 9,
+ .type = SSPP_TYPE_DMA,
+ },
+};
+
+static const struct dpu_lm_cfg milos_lm[] = {
+ {
+ .name = "lm_0", .id = LM_0,
+ .base = 0x44000, .len = 0x400,
+ .features = MIXER_MSM8998_MASK,
+ .sblk = &sdm845_lm_sblk,
+ .pingpong = PINGPONG_0,
+ .dspp = DSPP_0,
+ }, {
+ .name = "lm_2", .id = LM_2,
+ .base = 0x46000, .len = 0x400,
+ .features = MIXER_MSM8998_MASK,
+ .sblk = &sdm845_lm_sblk,
+ .lm_pair = LM_3,
+ .pingpong = PINGPONG_2,
+ }, {
+ .name = "lm_3", .id = LM_3,
+ .base = 0x47000, .len = 0x400,
+ .features = MIXER_MSM8998_MASK,
+ .sblk = &sdm845_lm_sblk,
+ .lm_pair = LM_2,
+ .pingpong = PINGPONG_3,
+ },
+};
+
+static const struct dpu_dspp_cfg milos_dspp[] = {
+ {
+ .name = "dspp_0", .id = DSPP_0,
+ .base = 0x54000, .len = 0x1800,
+ .sblk = &sdm845_dspp_sblk,
+ },
+};
+
+static const struct dpu_pingpong_cfg milos_pp[] = {
+ {
+ .name = "pingpong_0", .id = PINGPONG_0,
+ .base = 0x69000, .len = 0,
+ .sblk = &sc7280_pp_sblk,
+ .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8),
+ }, {
+ .name = "pingpong_2", .id = PINGPONG_2,
+ .base = 0x6b000, .len = 0,
+ .sblk = &sc7280_pp_sblk,
+ .merge_3d = MERGE_3D_1,
+ .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10),
+ }, {
+ .name = "pingpong_3", .id = PINGPONG_3,
+ .base = 0x6c000, .len = 0,
+ .sblk = &sc7280_pp_sblk,
+ .merge_3d = MERGE_3D_1,
+ .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11),
+ }, {
+ .name = "pingpong_cwb_0", .id = PINGPONG_CWB_0,
+ .base = 0x66000, .len = 0,
+ .sblk = &sc7280_pp_sblk,
+ },
+};
+
+static const struct dpu_merge_3d_cfg milos_merge_3d[] = {
+ {
+ .name = "merge_3d_1", .id = MERGE_3D_1,
+ .base = 0x4f000, .len = 0x8,
+ },
+};
+
+/*
+ * NOTE: Each display compression engine (DCE) contains dual hard
+ * slice DSC encoders so both share same base address but with
+ * its own different sub block address.
+ */
+static const struct dpu_dsc_cfg milos_dsc[] = {
+ {
+ .name = "dce_0_0", .id = DSC_0,
+ .base = 0x80000, .len = 0x6,
+ .features = BIT(DPU_DSC_NATIVE_42x_EN),
+ .sblk = &milos_dsc_sblk_0,
+ }, {
+ .name = "dce_0_1", .id = DSC_1,
+ .base = 0x80000, .len = 0x6,
+ .features = BIT(DPU_DSC_NATIVE_42x_EN),
+ .sblk = &milos_dsc_sblk_1,
+ },
+};
+
+static const struct dpu_wb_cfg milos_wb[] = {
+ {
+ .name = "wb_2", .id = WB_2,
+ .base = 0x65000, .len = 0x2c8,
+ .features = WB_SDM845_MASK,
+ .format_list = wb2_formats_rgb_yuv,
+ .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv),
+ .xin_id = 6,
+ .maxlinewidth = 4096,
+ .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4),
+ },
+};
+
+static const struct dpu_cwb_cfg milos_cwb[] = {
+ {
+ .name = "cwb_0", .id = CWB_0,
+ .base = 0x66200, .len = 0x8,
+ },
+};
+
+static const struct dpu_intf_cfg milos_intf[] = {
+ {
+ .name = "intf_0", .id = INTF_0,
+ .base = 0x34000, .len = 0x300,
+ .type = INTF_DP,
+ .controller_id = MSM_DP_CONTROLLER_0,
+ .prog_fetch_lines_worst_case = 24,
+ .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24),
+ .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25),
+ }, {
+ .name = "intf_1", .id = INTF_1,
+ .base = 0x35000, .len = 0x300,
+ .type = INTF_DSI,
+ .controller_id = MSM_DSI_CONTROLLER_0,
+ .prog_fetch_lines_worst_case = 24,
+ .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26),
+ .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27),
+ .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF1_TEAR_INTR, 2),
+ }, {
+ .name = "intf_3", .id = INTF_3,
+ .base = 0x37000, .len = 0x300,
+ .type = INTF_DP,
+ .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */
+ .prog_fetch_lines_worst_case = 24,
+ .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30),
+ .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31),
+ },
+};
+
+static const struct dpu_perf_cfg milos_perf_data = {
+ .max_bw_low = 7100000,
+ .max_bw_high = 9800000,
+ .min_core_ib = 2500000,
+ .min_llcc_ib = 0,
+ .min_dram_ib = 1600000,
+ .min_prefill_lines = 40,
+ /* FIXME: lut tables */
+ .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0},
+ .safe_lut_tbl = {0xff00, 0xfff0, 0x0fff},
+ .qos_lut_tbl = {
+ {.nentry = ARRAY_SIZE(sc7180_qos_linear),
+ .entries = sc7180_qos_linear
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_macrotile),
+ .entries = sc7180_qos_macrotile
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_nrt),
+ .entries = sc7180_qos_nrt
+ },
+ /* TODO: macrotile-qseed is different from macrotile */
+ },
+ .cdp_cfg = {
+ {.rd_enable = 1, .wr_enable = 1},
+ {.rd_enable = 1, .wr_enable = 0}
+ },
+ .clk_inefficiency_factor = 105,
+ .bw_inefficiency_factor = 120,
+};
+
+static const struct dpu_mdss_version milos_mdss_ver = {
+ .core_major_ver = 10,
+ .core_minor_ver = 2,
+};
+
+const struct dpu_mdss_cfg dpu_milos_cfg = {
+ .mdss_ver = &milos_mdss_ver,
+ .caps = &milos_dpu_caps,
+ .mdp = &milos_mdp,
+ .cdm = &dpu_cdm_5_x,
+ .ctl_count = ARRAY_SIZE(milos_ctl),
+ .ctl = milos_ctl,
+ .sspp_count = ARRAY_SIZE(milos_sspp),
+ .sspp = milos_sspp,
+ .mixer_count = ARRAY_SIZE(milos_lm),
+ .mixer = milos_lm,
+ .dspp_count = ARRAY_SIZE(milos_dspp),
+ .dspp = milos_dspp,
+ .pingpong_count = ARRAY_SIZE(milos_pp),
+ .pingpong = milos_pp,
+ .dsc_count = ARRAY_SIZE(milos_dsc),
+ .dsc = milos_dsc,
+ .merge_3d_count = ARRAY_SIZE(milos_merge_3d),
+ .merge_3d = milos_merge_3d,
+ .wb_count = ARRAY_SIZE(milos_wb),
+ .wb = milos_wb,
+ .cwb_count = ARRAY_SIZE(milos_cwb),
+ .cwb = milos_cwb,
+ .intf_count = ARRAY_SIZE(milos_intf),
+ .intf = milos_intf,
+ .vbif = &milos_vbif,
+ .perf = &milos_perf_data,
+};
+
+#endif
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index bb4fd5fa4b22..2e10add84fd7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -454,6 +454,16 @@ static const struct dpu_dsc_sub_blks dsc_sblk_1 = {
.ctl = {.name = "ctl", .base = 0xF80, .len = 0x10},
};
+static const struct dpu_dsc_sub_blks milos_dsc_sblk_0 = {
+ .enc = {.name = "enc", .base = 0x100, .len = 0x100},
+ .ctl = {.name = "ctl", .base = 0xF00, .len = 0x80},
+};
+
+static const struct dpu_dsc_sub_blks milos_dsc_sblk_1 = {
+ .enc = {.name = "enc", .base = 0x200, .len = 0x100},
+ .ctl = {.name = "ctl", .base = 0xF80, .len = 0x80},
+};
+
static const struct dpu_dsc_sub_blks sm8750_dsc_sblk_0 = {
.enc = {.name = "enc", .base = 0x100, .len = 0x100},
.ctl = {.name = "ctl", .base = 0xF00, .len = 0x24},
@@ -513,6 +523,23 @@ static const struct dpu_vbif_dynamic_ot_cfg msm8998_ot_rdwr_cfg[] = {
},
};
+static const struct dpu_vbif_cfg milos_vbif = {
+ .len = 0x1074,
+ .features = BIT(DPU_VBIF_QOS_REMAP),
+ .xin_halt_timeout = 0x4000,
+ .qos_rp_remap_size = 0x40,
+ .qos_rt_tbl = {
+ .npriority_lvl = ARRAY_SIZE(sdm845_rt_pri_lvl),
+ .priority_lvl = sdm845_rt_pri_lvl,
+ },
+ .qos_nrt_tbl = {
+ .npriority_lvl = ARRAY_SIZE(sdm845_nrt_pri_lvl),
+ .priority_lvl = sdm845_nrt_pri_lvl,
+ },
+ .memtype_count = 16,
+ .memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+};
+
static const struct dpu_vbif_cfg msm8996_vbif = {
.len = 0x1040,
.default_ot_rd_limit = 32,
@@ -754,6 +781,8 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = {
#include "catalog/dpu_9_2_x1e80100.h"
#include "catalog/dpu_10_0_sm8650.h"
+#include "catalog/dpu_10_2_milos.h"
+
#include "catalog/dpu_12_0_sm8750.h"
#include "catalog/dpu_12_2_glymur.h"
#include "catalog/dpu_12_4_eliza.h"
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index ba04ac24d5a9..f45faf87333e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -766,6 +766,7 @@ struct dpu_mdss_cfg {
extern const struct dpu_mdss_cfg dpu_eliza_cfg;
extern const struct dpu_mdss_cfg dpu_glymur_cfg;
extern const struct dpu_mdss_cfg dpu_kaanapali_cfg;
+extern const struct dpu_mdss_cfg dpu_milos_cfg;
extern const struct dpu_mdss_cfg dpu_msm8917_cfg;
extern const struct dpu_mdss_cfg dpu_msm8937_cfg;
extern const struct dpu_mdss_cfg dpu_msm8953_cfg;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 35f7af4743d7..7c37bd51f934 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -1483,6 +1483,7 @@ static const struct of_device_id dpu_dt_match[] = {
{ .compatible = "qcom,eliza-dpu", .data = &dpu_eliza_cfg, },
{ .compatible = "qcom,glymur-dpu", .data = &dpu_glymur_cfg, },
{ .compatible = "qcom,kaanapali-dpu", .data = &dpu_kaanapali_cfg, },
+ { .compatible = "qcom,milos-dpu", .data = &dpu_milos_cfg, },
{ .compatible = "qcom,msm8917-mdp5", .data = &dpu_msm8917_cfg, },
{ .compatible = "qcom,msm8937-mdp5", .data = &dpu_msm8937_cfg, },
{ .compatible = "qcom,msm8953-mdp5", .data = &dpu_msm8953_cfg, },
--
2.53.0
^ permalink raw reply related
* [PATCH v2 7/9] drm/msm: mdss: Add Milos support
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss,
Konrad Dybcio, Dmitry Baryshkov
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Add support for MDSS on Milos.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
drivers/gpu/drm/msm/msm_mdss.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c
index 90c3fa0681a0..754ceef38717 100644
--- a/drivers/gpu/drm/msm/msm_mdss.c
+++ b/drivers/gpu/drm/msm/msm_mdss.c
@@ -550,6 +550,10 @@ static void mdss_remove(struct platform_device *pdev)
msm_mdss_destroy(mdss);
}
+static const struct msm_mdss_data data_14k = {
+ .reg_bus_bw = 14000,
+};
+
static const struct msm_mdss_data data_57k = {
.reg_bus_bw = 57000,
};
@@ -571,6 +575,7 @@ static const struct of_device_id mdss_dt_match[] = {
{ .compatible = "qcom,eliza-mdss", .data = &data_57k },
{ .compatible = "qcom,glymur-mdss", .data = &data_57k },
{ .compatible = "qcom,kaanapali-mdss", .data = &data_57k },
+ { .compatible = "qcom,milos-mdss", .data = &data_14k },
{ .compatible = "qcom,msm8998-mdss", .data = &data_76k8 },
{ .compatible = "qcom,qcm2290-mdss", .data = &data_76k8 },
{ .compatible = "qcom,qcs8300-mdss", .data = &data_74k },
--
2.53.0
^ permalink raw reply related
* [PATCH v2 6/9] drm/msm/dsi: add support for DSI-PHY on Milos
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss,
Dmitry Baryshkov
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Add DSI PHY support for the Milos platform.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 2 ++
drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 1 +
drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c | 23 +++++++++++++++++++++++
3 files changed, 26 insertions(+)
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index c59375aaae19..1fb3899b88bf 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -571,6 +571,8 @@ static const struct of_device_id dsi_phy_dt_match[] = {
.data = &dsi_phy_5nm_8350_cfgs },
{ .compatible = "qcom,sm8450-dsi-phy-5nm",
.data = &dsi_phy_5nm_8450_cfgs },
+ { .compatible = "qcom,milos-dsi-phy-4nm",
+ .data = &dsi_phy_4nm_milos_cfgs },
{ .compatible = "qcom,sm8550-dsi-phy-4nm",
.data = &dsi_phy_4nm_8550_cfgs },
{ .compatible = "qcom,sm8650-dsi-phy-4nm",
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
index c01784ca38ed..21a59d66e8dc 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
@@ -61,6 +61,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8350_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8450_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8775p_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_5nm_sar2130p_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_4nm_milos_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_3nm_8750_cfgs;
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
index 8f4b03713f25..984a66085dfb 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
@@ -1436,6 +1436,29 @@ const struct msm_dsi_phy_cfg dsi_phy_5nm_sar2130p_cfgs = {
.quirks = DSI_PHY_7NM_QUIRK_V5_2,
};
+const struct msm_dsi_phy_cfg dsi_phy_4nm_milos_cfgs = {
+ .has_phy_lane = true,
+ .regulator_data = dsi_phy_7nm_98000uA_regulators,
+ .num_regulators = ARRAY_SIZE(dsi_phy_7nm_98000uA_regulators),
+ .ops = {
+ .enable = dsi_7nm_phy_enable,
+ .disable = dsi_7nm_phy_disable,
+ .pll_init = dsi_pll_7nm_init,
+ .save_pll_state = dsi_7nm_pll_save_state,
+ .restore_pll_state = dsi_7nm_pll_restore_state,
+ .set_continuous_clock = dsi_7nm_set_continuous_clock,
+ },
+ .min_pll_rate = 600000000UL,
+#ifdef CONFIG_64BIT
+ .max_pll_rate = 5000000000UL,
+#else
+ .max_pll_rate = ULONG_MAX,
+#endif
+ .io_start = { 0xae95000 },
+ .num_dsi_phy = 1,
+ .quirks = DSI_PHY_7NM_QUIRK_V5_2,
+};
+
const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs = {
.has_phy_lane = true,
.regulator_data = dsi_phy_7nm_98400uA_regulators,
--
2.53.0
^ permalink raw reply related
* [PATCH v2 5/9] soc: qcom: ubwc: Add config for Milos
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss,
Konrad Dybcio, Dmitry Baryshkov
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Describe the Universal Bandwidth Compression (UBWC) configuration
for the Milos SoC.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
drivers/soc/qcom/ubwc_config.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c
index 3fe47d8f0f63..1551f270afce 100644
--- a/drivers/soc/qcom/ubwc_config.c
+++ b/drivers/soc/qcom/ubwc_config.c
@@ -37,6 +37,17 @@ static const struct qcom_ubwc_cfg_data kaanapali_data = {
.macrotile_mode = true,
};
+static const struct qcom_ubwc_cfg_data milos_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 14 for LP_DDR4 */
+ .highest_bank_bit = 15,
+ .macrotile_mode = true,
+};
+
static const struct qcom_ubwc_cfg_data msm8937_data = {
.ubwc_enc_version = UBWC_1_0,
.ubwc_dec_version = UBWC_1_0,
@@ -247,6 +258,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = {
{ .compatible = "qcom,kaanapali", .data = &kaanapali_data, },
{ .compatible = "qcom,glymur", .data = &glymur_data},
{ .compatible = "qcom,mahua", .data = &glymur_data },
+ { .compatible = "qcom,milos", .data = &milos_data },
{ .compatible = "qcom,msm8226", .data = &no_ubwc_data },
{ .compatible = "qcom,msm8916", .data = &no_ubwc_data },
{ .compatible = "qcom,msm8917", .data = &no_ubwc_data },
--
2.53.0
^ permalink raw reply related
* [PATCH v2 4/9] dt-bindings: display: msm: document the Milos Mobile Display Subsystem
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Document the Mobile Display Subsystem (MDSS) on the Milos SoC.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
.../bindings/display/msm/qcom,milos-mdss.yaml | 283 +++++++++++++++++++++
1 file changed, 283 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,milos-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,milos-mdss.yaml
new file mode 100644
index 000000000000..0fb66b4b2742
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/qcom,milos-mdss.yaml
@@ -0,0 +1,283 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/msm/qcom,milos-mdss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Milos Display MDSS
+
+maintainers:
+ - Luca Weiss <luca.weiss@fairphone.com>
+
+description:
+ Milos MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like
+ DPU display controller, DSI and DP interfaces etc.
+
+$ref: /schemas/display/msm/mdss-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,milos-mdss
+
+ clocks:
+ items:
+ - description: Display AHB
+ - description: Display hf AXI
+ - description: Display core
+
+ iommus:
+ maxItems: 1
+
+ interconnects:
+ items:
+ - description: Interconnect path from mdp0 port to the data bus
+ - description: Interconnect path from CPU to the reg bus
+
+ interconnect-names:
+ items:
+ - const: mdp0-mem
+ - const: cpu-cfg
+
+patternProperties:
+ "^display-controller@[0-9a-f]+$":
+ type: object
+ additionalProperties: true
+ properties:
+ compatible:
+ const: qcom,milos-dpu
+
+ "^displayport-controller@[0-9a-f]+$":
+ type: object
+ additionalProperties: true
+ properties:
+ compatible:
+ const: qcom,milos-dp
+
+ "^dsi@[0-9a-f]+$":
+ type: object
+ additionalProperties: true
+ properties:
+ compatible:
+ items:
+ - const: qcom,milos-dsi-ctrl
+ - const: qcom,mdss-dsi-ctrl
+
+ "^phy@[0-9a-f]+$":
+ type: object
+ additionalProperties: true
+ properties:
+ compatible:
+ const: qcom,milos-dsi-phy-4nm
+
+required:
+ - compatible
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/power/qcom,rpmhpd.h>
+ #include <dt-bindings/interconnect/qcom,milos-rpmh.h>
+
+ display-subsystem@ae00000 {
+ compatible = "qcom,milos-mdss";
+ reg = <0x0ae00000 0x1000>;
+ reg-names = "mdss";
+
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH 0>;
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+
+ resets = <&dispcc DISP_CC_MDSS_CORE_BCR>;
+
+ interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+ <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
+ &cnoc_main SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>;
+ interconnect-names = "mdp0-mem",
+ "cpu-cfg";
+
+ power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>;
+
+ iommus = <&apps_smmu 0x1c00 0x2>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ display-controller@ae01000 {
+ compatible = "qcom,milos-dpu";
+ reg = <0x0ae01000 0x8f000>,
+ <0x0aeb0000 0x3000>;
+ reg-names = "mdp",
+ "vbif";
+
+ interrupts-extended = <&mdss 0>;
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "nrt_bus",
+ "iface",
+ "lut",
+ "core",
+ "vsync";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ assigned-clock-rates = <19200000>;
+
+ operating-points-v2 = <&mdp_opp_table>;
+
+ power-domains = <&rpmhpd RPMHPD_CX>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ dpu_intf1_out: endpoint {
+ remote-endpoint = <&mdss_dsi0_in>;
+ };
+ };
+ };
+
+ mdp_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-342000000 {
+ opp-hz = /bits/ 64 <342000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-402000000 {
+ opp-hz = /bits/ 64 <402000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+
+ opp-535000000 {
+ opp-hz = /bits/ 64 <535000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ required-opps = <&rpmhpd_opp_nom_l1>;
+ };
+
+ opp-630000000 {
+ opp-hz = /bits/ 64 <630000000>;
+ required-opps = <&rpmhpd_opp_turbo>;
+ };
+ };
+ };
+
+ dsi@ae94000 {
+ compatible = "qcom,milos-dsi-ctrl", "qcom,mdss-dsi-ctrl";
+ reg = <0x0ae94000 0x1000>;
+ reg-names = "dsi_ctrl";
+
+ interrupts-extended = <&mdss 4>;
+
+ clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&dispcc DISP_CC_MDSS_ESC0_CLK>,
+ <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&gcc GCC_DISP_HF_AXI_CLK>;
+ clock-names = "byte",
+ "byte_intf",
+ "pixel",
+ "core",
+ "iface",
+ "bus";
+
+ assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
+ <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ assigned-clock-parents = <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>,
+ <&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>;
+
+ operating-points-v2 = <&mdss_dsi_opp_table>;
+
+ power-domains = <&rpmhpd RPMHPD_CX>;
+
+ phys = <&mdss_dsi0_phy>;
+ phy-names = "dsi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mdss_dsi0_in: endpoint {
+ remote-endpoint = <&dpu_intf1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mdss_dsi0_out: endpoint {
+ };
+ };
+ };
+
+ mdss_dsi_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-187500000 {
+ opp-hz = /bits/ 64 <187500000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_svs>;
+ };
+
+ opp-358000000 {
+ opp-hz = /bits/ 64 <358000000>;
+ required-opps = <&rpmhpd_opp_svs_l1>;
+ };
+ };
+ };
+
+ mdss_dsi0_phy: phy@ae95000 {
+ compatible = "qcom,milos-dsi-phy-4nm";
+ reg = <0x0ae95000 0x200>,
+ <0x0ae95200 0x300>,
+ <0x0ae95500 0x400>;
+ reg-names = "dsi_phy",
+ "dsi_phy_lane",
+ "dsi_pll";
+
+ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "iface",
+ "ref";
+
+ #clock-cells = <1>;
+ #phy-cells = <0>;
+ };
+ };
+...
--
2.53.0
^ permalink raw reply related
* [PATCH v2 3/9] dt-bindings: display: msm: document the Milos DPU
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Document the DPU Display Controller on the Milos Platform.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml
index dccac525d202..9da981639ddb 100644
--- a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml
+++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml
@@ -18,6 +18,7 @@ properties:
- qcom,eliza-dpu
- qcom,glymur-dpu
- qcom,kaanapali-dpu
+ - qcom,milos-dpu
- qcom,sa8775p-dpu
- qcom,sm8650-dpu
- qcom,sm8750-dpu
--
2.53.0
^ permalink raw reply related
* [PATCH v2 2/9] dt-bindings: display: msm-dsi-controller-main: document the Milos DSI Controller
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Document the DSI Controller on the Milos Platform.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
index a24fcb914418..dbc0613e427e 100644
--- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
+++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
@@ -16,6 +16,7 @@ properties:
- enum:
- qcom,apq8064-dsi-ctrl
- qcom,kaanapali-dsi-ctrl
+ - qcom,milos-dsi-ctrl
- qcom,msm8226-dsi-ctrl
- qcom,msm8916-dsi-ctrl
- qcom,msm8953-dsi-ctrl
@@ -339,6 +340,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,milos-dsi-ctrl
- qcom,msm8998-dsi-ctrl
- qcom,sa8775p-dsi-ctrl
- qcom,sar2130p-dsi-ctrl
--
2.53.0
^ permalink raw reply related
* [PATCH v2 1/9] dt-bindings: display: msm-dsi-phy-7nm: document the Milos DSI PHY
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss
In-Reply-To: <20260327-milos-mdss-v2-0-bc586683f5ca@fairphone.com>
Document the DSI PHY on the Milos Platform.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml
index b5a0c1461250..4bdec236734c 100644
--- a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml
+++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml
@@ -20,6 +20,7 @@ properties:
- qcom,dsi-phy-7nm
- qcom,dsi-phy-7nm-8150
- qcom,kaanapali-dsi-phy-3nm
+ - qcom,milos-dsi-phy-4nm
- qcom,sa8775p-dsi-phy-5nm
- qcom,sar2130p-dsi-phy-5nm
- qcom,sc7280-dsi-phy-7nm
--
2.53.0
^ permalink raw reply related
* [PATCH v2 0/9] MDSS / DPU bringup for Milos
From: Luca Weiss @ 2026-03-27 16:12 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Clark, Dmitry Baryshkov,
Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Jonathan Marek, Krishna Manikandan, Neil Armstrong,
Alexander Koskovich
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, dri-devel, freedreno, devicetree, Luca Weiss,
Konrad Dybcio, Dmitry Baryshkov
This series adds display support for the Milos SoC.
This is tested on the Fairphone (Gen. 6) using the SM7635 SoC (8bit DSC
cmd mode), and the Nothing Phone (3a) has also been reported to work by
Alexander Koskovich.
The panel driver for Fairphone (Gen. 6) and devicetree enablement will
be sent later.
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
Changes in v2:
- Address comments from RFC v1 where it wasn't confirmed working yet
- Pick up some tags
- Add dt-binding patches
- Drop fp6 dts patch, that'll come later
- Link to v1: https://lore.kernel.org/r/20251219-milos-mdss-v1-0-4537a916bdf9@fairphone.com
---
Luca Weiss (9):
dt-bindings: display: msm-dsi-phy-7nm: document the Milos DSI PHY
dt-bindings: display: msm-dsi-controller-main: document the Milos DSI Controller
dt-bindings: display: msm: document the Milos DPU
dt-bindings: display: msm: document the Milos Mobile Display Subsystem
soc: qcom: ubwc: Add config for Milos
drm/msm/dsi: add support for DSI-PHY on Milos
drm/msm: mdss: Add Milos support
drm/msm/dpu: Add Milos support
arm64: dts: qcom: milos: Add display (MDSS)
.../bindings/display/msm/dsi-controller-main.yaml | 2 +
.../bindings/display/msm/dsi-phy-7nm.yaml | 1 +
.../bindings/display/msm/qcom,milos-mdss.yaml | 283 +++++++++++++++++++++
.../bindings/display/msm/qcom,sm8650-dpu.yaml | 1 +
arch/arm64/boot/dts/qcom/milos.dtsi | 211 ++++++++++++++-
.../gpu/drm/msm/disp/dpu1/catalog/dpu_10_2_milos.h | 279 ++++++++++++++++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 29 +++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 1 +
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 +
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 2 +
drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 1 +
drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c | 23 ++
drivers/gpu/drm/msm/msm_mdss.c | 5 +
drivers/soc/qcom/ubwc_config.c | 12 +
14 files changed, 849 insertions(+), 2 deletions(-)
---
base-commit: 50f91f877c695c7ce6cabc3df6a892ab7abc6c3b
change-id: 20251219-milos-mdss-fa0763693775
Best regards,
--
Luca Weiss <luca.weiss@fairphone.com>
^ permalink raw reply
* [PATCH v2 6/6] phy: realtek: usb2: Make configs available for MACH_REALTEK_RTL
From: Rustam Adilov @ 2026-03-27 16:06 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel
Cc: Rustam Adilov
In-Reply-To: <20260327160638.15134-1-adilov@disroot.org>
Add the MACH_REALTEK_RTL to the if statement to make the config
options available for Realtek RTL SoCs as well.
Signed-off-by: Rustam Adilov <adilov@disroot.org>
---
drivers/phy/realtek/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/phy/realtek/Kconfig b/drivers/phy/realtek/Kconfig
index 75ac7e7c31ae..f9eadffacd18 100644
--- a/drivers/phy/realtek/Kconfig
+++ b/drivers/phy/realtek/Kconfig
@@ -3,7 +3,7 @@
# Phy drivers for Realtek platforms
#
-if ARCH_REALTEK || COMPILE_TEST
+if ARCH_REALTEK || MACH_REALTEK_RTL || COMPILE_TEST
config PHY_RTK_RTD_USB2PHY
tristate "Realtek RTD USB2 PHY Transceiver Driver"
--
2.53.0
^ permalink raw reply related
* [PATCH v2 5/6] phy: realtek: usb2: add support for RTL9607C USB2 PHY
From: Rustam Adilov @ 2026-03-27 16:06 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel
Cc: Rustam Adilov, Michael Zavertkin
In-Reply-To: <20260327160638.15134-1-adilov@disroot.org>
Add support for the usb2 phy of RTL9607C series based SoCs.
Add the macros and phy config struct for rtl9607.
RTL9607C requires to clear a "force host disconnect" bit in the
specific register (which is at an offset from reg_wrap_vstatus)
before proceeding with phy parameter writes.
Add the bool variable to the driver data struct and hide this whole
procedure under the if statement that checks this new variable.
Co-developed-by: Michael Zavertkin <misha.zavertkin@mail.ru>
Signed-off-by: Michael Zavertkin <misha.zavertkin@mail.ru>
Signed-off-by: Rustam Adilov <adilov@disroot.org>
---
drivers/phy/realtek/phy-rtk-usb2.c | 57 ++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
index 070cba1e0e0a..bf22d12681dc 100644
--- a/drivers/phy/realtek/phy-rtk-usb2.c
+++ b/drivers/phy/realtek/phy-rtk-usb2.c
@@ -26,6 +26,12 @@
#define PHY_VCTRL_SHIFT 8
#define PHY_REG_DATA_MASK 0xff
+#define PHY_9607_VSTS_BUSY BIT(17)
+#define PHY_9607_NEW_REG_REQ BIT(13)
+
+#define PHY_9607_FORCE_DISCONNECT_REG 0x10
+#define PHY_9607_FORCE_DISCONNECT_BIT BIT(5)
+
#define GET_LOW_NIBBLE(addr) ((addr) & 0x0f)
#define GET_HIGH_NIBBLE(addr) (((addr) & 0xf0) >> 4)
@@ -109,6 +115,7 @@ struct phy_cfg {
u32 (*read)(void __iomem *reg);
void (*write)(u32 val, void __iomem *reg);
+ bool force_host_disconnect;
};
struct phy_parameter {
@@ -614,6 +621,16 @@ static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
goto do_toggle;
}
+ if (phy_cfg->force_host_disconnect) {
+ /* disable force-host-disconnect */
+ u32 temp = readl(phy_reg->reg_wrap_vstatus + PHY_9607_FORCE_DISCONNECT_REG);
+
+ temp &= ~PHY_9607_FORCE_DISCONNECT_BIT;
+ writel(temp, phy_reg->reg_wrap_vstatus + PHY_9607_FORCE_DISCONNECT_REG);
+
+ mdelay(10);
+ }
+
/* Set page 0 */
phy_data_page = phy_cfg->page0;
rtk_phy_set_page(phy_reg, 0);
@@ -1141,6 +1158,7 @@ static const struct phy_cfg rtd1295_phy_cfg = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
};
static const struct phy_cfg rtd1395_phy_cfg = {
@@ -1170,6 +1188,7 @@ static const struct phy_cfg rtd1395_phy_cfg = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
};
static const struct phy_cfg rtd1395_phy_cfg_2port = {
@@ -1199,6 +1218,7 @@ static const struct phy_cfg rtd1395_phy_cfg_2port = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
};
static const struct phy_cfg rtd1619_phy_cfg = {
@@ -1226,6 +1246,7 @@ static const struct phy_cfg rtd1619_phy_cfg = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
};
static const struct phy_cfg rtd1319_phy_cfg = {
@@ -1257,6 +1278,7 @@ static const struct phy_cfg rtd1319_phy_cfg = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
};
static const struct phy_cfg rtd1312c_phy_cfg = {
@@ -1287,6 +1309,7 @@ static const struct phy_cfg rtd1312c_phy_cfg = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
};
static const struct phy_cfg rtd1619b_phy_cfg = {
@@ -1317,6 +1340,7 @@ static const struct phy_cfg rtd1619b_phy_cfg = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
};
static const struct phy_cfg rtd1319d_phy_cfg = {
@@ -1347,6 +1371,7 @@ static const struct phy_cfg rtd1319d_phy_cfg = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
};
static const struct phy_cfg rtd1315e_phy_cfg = {
@@ -1378,6 +1403,37 @@ static const struct phy_cfg rtd1315e_phy_cfg = {
.new_reg_req = PHY_NEW_REG_REQ,
.read = phy_read,
.write = phy_write,
+ .force_host_disconnect = false,
+};
+
+static const struct phy_cfg rtl9607_phy_cfg = {
+ .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+ .page0 = { [0] = {0xe0, 0x95},
+ [4] = {0xe4, 0x6a},
+ [12] = {0xf3, 0x31}, },
+ .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE,
+ .page1 = { [0] = {0xe0, 0x26}, },
+ .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+ .page2 = { [7] = {0xe7, 0x33}, },
+ .num_phy = 1,
+ .check_efuse = false,
+ .check_efuse_version = CHECK_EFUSE_V2,
+ .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
+ .dc_driving_mask = 0x1f,
+ .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+ .dc_disconnect_mask = 0xf,
+ .usb_dc_disconnect_at_page0 = true,
+ .do_toggle = true,
+ .do_toggle_driving = false,
+ .driving_updated_for_dev_dis = 0x8,
+ .use_default_parameter = false,
+ .is_double_sensitivity_mode = true,
+ .vstatus_offset = 0xc,
+ .vstatus_busy = PHY_9607_VSTS_BUSY,
+ .new_reg_req = PHY_9607_NEW_REG_REQ,
+ .read = phy_read_le,
+ .write = phy_write_le,
+ .force_host_disconnect = true,
};
static const struct of_device_id usbphy_rtk_dt_match[] = {
@@ -1390,6 +1446,7 @@ static const struct of_device_id usbphy_rtk_dt_match[] = {
{ .compatible = "realtek,rtd1395-usb2phy-2port", .data = &rtd1395_phy_cfg_2port },
{ .compatible = "realtek,rtd1619-usb2phy", .data = &rtd1619_phy_cfg },
{ .compatible = "realtek,rtd1619b-usb2phy", .data = &rtd1619b_phy_cfg },
+ { .compatible = "realtek,rtl9607-usb2phy", .data = &rtl9607_phy_cfg },
{},
};
MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match);
--
2.53.0
^ permalink raw reply related
* [PATCH v2 4/6] phy: realtek: usb2: introduce reset controller struct
From: Rustam Adilov @ 2026-03-27 16:06 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel
Cc: Rustam Adilov, Michael Zavertkin
In-Reply-To: <20260327160638.15134-1-adilov@disroot.org>
In RTL9607C, there is so called "IP Enable Controller" which resemble
reset controller with reset lines and is used for various things like
USB, PCIE, GMAC and such.
Introduce the reset_control struct to this driver to handle deasserting
usb2 phy reset line.
Make use of the function devm_reset_control_array_get_optional_exclusive()
function to get the reset controller and since existing RTD SoCs don't
specify the resets we can have a cleaner code.
Co-developed-by: Michael Zavertkin <misha.zavertkin@mail.ru>
Signed-off-by: Michael Zavertkin <misha.zavertkin@mail.ru>
Signed-off-by: Rustam Adilov <adilov@disroot.org>
---
drivers/phy/realtek/phy-rtk-usb2.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
index e65b8525b88b..070cba1e0e0a 100644
--- a/drivers/phy/realtek/phy-rtk-usb2.c
+++ b/drivers/phy/realtek/phy-rtk-usb2.c
@@ -17,6 +17,7 @@
#include <linux/sys_soc.h>
#include <linux/mfd/syscon.h>
#include <linux/phy/phy.h>
+#include <linux/reset.h>
#include <linux/usb.h>
/* GUSB2PHYACCn register */
@@ -130,6 +131,7 @@ struct rtk_phy {
struct phy_cfg *phy_cfg;
int num_phy;
struct phy_parameter *phy_parameter;
+ struct reset_control *phy_rst;
struct dentry *debug_dir;
};
@@ -602,6 +604,10 @@ static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
phy_reg = &phy_parameter->phy_reg;
+ reset_control_deassert(rtk_phy->phy_rst);
+
+ mdelay(5);
+
if (phy_cfg->use_default_parameter) {
dev_dbg(rtk_phy->dev, "%s phy#%d use default parameter\n",
__func__, index);
@@ -1069,6 +1075,12 @@ static int rtk_usb2phy_probe(struct platform_device *pdev)
rtk_phy->num_phy = phy_cfg->num_phy;
+ rtk_phy->phy_rst = devm_reset_control_array_get_optional_exclusive(dev);
+ if (IS_ERR(rtk_phy->phy_rst)) {
+ dev_err(dev, "usb2 phy resets are not working\n");
+ return PTR_ERR(rtk_phy->phy_rst);
+ }
+
ret = parse_phy_data(rtk_phy);
if (ret)
goto err;
--
2.53.0
^ permalink raw reply related
* [PATCH v2 3/6] dt-bindings: phy: realtek,usb2phy.yaml: extend for resets and RTL9607C support
From: Rustam Adilov @ 2026-03-27 16:06 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel
Cc: Rustam Adilov
In-Reply-To: <20260327160638.15134-1-adilov@disroot.org>
Add the "realtek,rtl9607-usb2phy" compatible for USB2 PHY on the RTL9607C
SoC series.
Add a resets property to properties to describe the usb2phy reset line.
In RTL9607C, USB2 PHY reset line is from "IP Enable controller" which is
multipurpose and handle activating various SoC peripherals.
It is unclear whether RTD SoCs have something similar to that so set
the resets to false for these devices.
RTL9607C requires the "resets" to be specified so add the corresponding
if check for the "realtek,rtl9607-usb2phy" compatible.
Signed-off-by: Rustam Adilov <adilov@disroot.org>
---
.../bindings/phy/realtek,usb2phy.yaml | 25 ++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/phy/realtek,usb2phy.yaml b/Documentation/devicetree/bindings/phy/realtek,usb2phy.yaml
index 9911ada39ee7..7b50833c8e19 100644
--- a/Documentation/devicetree/bindings/phy/realtek,usb2phy.yaml
+++ b/Documentation/devicetree/bindings/phy/realtek,usb2phy.yaml
@@ -11,7 +11,8 @@ maintainers:
- Stanley Chang <stanley_chang@realtek.com>
description: |
- Realtek USB 2.0 PHY support the digital home center (DHC) RTD series SoCs.
+ Realtek USB 2.0 PHY support the digital home center (DHC) RTD and
+ RTL9607C series SoCs.
The USB 2.0 PHY driver is designed to support the XHCI controller. The SoCs
support multiple XHCI controllers. One PHY device node maps to one XHCI
controller.
@@ -57,6 +58,12 @@ description: |
XHCI controller#1 -- usb2phy -- phy#0
XHCI controller#2 -- usb2phy -- phy#0
+ RTL9607C SoCs USB
+ The USB architecture includes OHCI and EHCI controllers.
+ Both of them map to one USB2.0 PHY.
+ OHCI controller#0 -- usb2phy -- phy#0
+ EHCI controller#0 -- usb2phy -- phy#0
+
properties:
compatible:
enum:
@@ -69,6 +76,7 @@ properties:
- realtek,rtd1395-usb2phy-2port
- realtek,rtd1619-usb2phy
- realtek,rtd1619b-usb2phy
+ - realtek,rtl9607-usb2phy
reg:
items:
@@ -130,6 +138,9 @@ properties:
minimum: -8
maximum: 8
+ resets:
+ maxItems: 1
+
required:
- compatible
- reg
@@ -157,6 +168,18 @@ allOf:
then:
properties:
realtek,driving-level-compensate: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - realtek,rtl9607-usb2phy
+ then:
+ required:
+ - resets
+ else:
+ properties:
+ resets: false
additionalProperties: false
--
2.53.0
^ permalink raw reply related
* [PATCH v2 1/6] phy: realtek: usb2: introduce vstatus/new_reg_req variables to driver data
From: Rustam Adilov @ 2026-03-27 16:06 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel
Cc: Rustam Adilov, Michael Zavertkin
In-Reply-To: <20260327160638.15134-1-adilov@disroot.org>
In RTL9607C SoC, the vstatus register is located at a certain offset from
the base and so introduce the vstatus_offset to handle it.
Busy bit of the vstatus and new_reg_req bit are also different and so
introduce these variables to the driver data as well.
Add these variables to the pre-existing phy cfg structs for RTD SoCs and
assign them the default values.
Co-developed-by: Michael Zavertkin <misha.zavertkin@mail.ru>
Signed-off-by: Michael Zavertkin <misha.zavertkin@mail.ru>
Signed-off-by: Rustam Adilov <adilov@disroot.org>
---
drivers/phy/realtek/phy-rtk-usb2.c | 59 ++++++++++++++++++++++++------
1 file changed, 48 insertions(+), 11 deletions(-)
diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
index 248550ef98ca..f5d2f0c3376a 100644
--- a/drivers/phy/realtek/phy-rtk-usb2.c
+++ b/drivers/phy/realtek/phy-rtk-usb2.c
@@ -64,6 +64,9 @@ struct phy_reg {
void __iomem *reg_wrap_vstatus;
void __iomem *reg_gusb2phyacc0;
int vstatus_index;
+ int vstatus_offset;
+ int vstatus_busy;
+ int new_reg_req;
};
struct phy_data {
@@ -96,6 +99,9 @@ struct phy_cfg {
bool do_toggle_driving;
bool use_default_parameter;
bool is_double_sensitivity_mode;
+ int vstatus_offset;
+ int vstatus_busy;
+ int new_reg_req;
};
struct phy_parameter {
@@ -162,21 +168,21 @@ static char rtk_phy_read(struct phy_reg *phy_reg, char addr)
addr -= OFFEST_PHY_READ;
/* polling until VBusy == 0 */
- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+ ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return (char)ret;
/* VCtrl = low nibble of addr, and set PHY_NEW_REG_REQ */
- val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+ val = phy_reg->new_reg_req | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
writel(val, reg_gusb2phyacc0);
- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+ ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return (char)ret;
/* VCtrl = high nibble of addr, and set PHY_NEW_REG_REQ */
- val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+ val = phy_reg->new_reg_req | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
writel(val, reg_gusb2phyacc0);
- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+ ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return (char)ret;
@@ -194,25 +200,25 @@ static int rtk_phy_write(struct phy_reg *phy_reg, char addr, char data)
int ret = 0;
/* write data to VStatusOut2 (data output to phy) */
- writel((u32)data << shift_bits, reg_wrap_vstatus);
+ writel((u32)data << shift_bits, reg_wrap_vstatus + phy_reg->vstatus_offset);
- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+ ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return ret;
/* VCtrl = low nibble of addr, set PHY_NEW_REG_REQ */
- val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+ val = phy_reg->new_reg_req | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
writel(val, reg_gusb2phyacc0);
- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+ ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return ret;
/* VCtrl = high nibble of addr, set PHY_NEW_REG_REQ */
- val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+ val = phy_reg->new_reg_req | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
writel(val, reg_gusb2phyacc0);
- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+ ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return ret;
@@ -957,6 +963,7 @@ static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy,
static int parse_phy_data(struct rtk_phy *rtk_phy)
{
+ struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
struct device *dev = rtk_phy->dev;
struct device_node *np = dev->of_node;
struct phy_parameter *phy_parameter;
@@ -974,6 +981,9 @@ static int parse_phy_data(struct rtk_phy *rtk_phy)
phy_parameter->phy_reg.reg_wrap_vstatus = of_iomap(np, 0);
phy_parameter->phy_reg.reg_gusb2phyacc0 = of_iomap(np, 1) + index;
phy_parameter->phy_reg.vstatus_index = index;
+ phy_parameter->phy_reg.vstatus_offset = phy_cfg->vstatus_offset;
+ phy_parameter->phy_reg.vstatus_busy = phy_cfg->vstatus_busy;
+ phy_parameter->phy_reg.new_reg_req = phy_cfg->new_reg_req;
if (of_property_read_bool(np, "realtek,inverse-hstx-sync-clock"))
phy_parameter->inverse_hstx_sync_clock = true;
@@ -1085,6 +1095,9 @@ static const struct phy_cfg rtd1295_phy_cfg = {
.driving_updated_for_dev_dis = 0xf,
.use_default_parameter = false,
.is_double_sensitivity_mode = false,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct phy_cfg rtd1395_phy_cfg = {
@@ -1109,6 +1122,9 @@ static const struct phy_cfg rtd1395_phy_cfg = {
.driving_updated_for_dev_dis = 0xf,
.use_default_parameter = false,
.is_double_sensitivity_mode = false,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct phy_cfg rtd1395_phy_cfg_2port = {
@@ -1133,6 +1149,9 @@ static const struct phy_cfg rtd1395_phy_cfg_2port = {
.driving_updated_for_dev_dis = 0xf,
.use_default_parameter = false,
.is_double_sensitivity_mode = false,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct phy_cfg rtd1619_phy_cfg = {
@@ -1155,6 +1174,9 @@ static const struct phy_cfg rtd1619_phy_cfg = {
.driving_updated_for_dev_dis = 0xf,
.use_default_parameter = false,
.is_double_sensitivity_mode = false,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct phy_cfg rtd1319_phy_cfg = {
@@ -1181,6 +1203,9 @@ static const struct phy_cfg rtd1319_phy_cfg = {
.driving_updated_for_dev_dis = 0xf,
.use_default_parameter = false,
.is_double_sensitivity_mode = true,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct phy_cfg rtd1312c_phy_cfg = {
@@ -1206,6 +1231,9 @@ static const struct phy_cfg rtd1312c_phy_cfg = {
.driving_updated_for_dev_dis = 0xf,
.use_default_parameter = false,
.is_double_sensitivity_mode = true,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct phy_cfg rtd1619b_phy_cfg = {
@@ -1231,6 +1259,9 @@ static const struct phy_cfg rtd1619b_phy_cfg = {
.driving_updated_for_dev_dis = 0x8,
.use_default_parameter = false,
.is_double_sensitivity_mode = true,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct phy_cfg rtd1319d_phy_cfg = {
@@ -1256,6 +1287,9 @@ static const struct phy_cfg rtd1319d_phy_cfg = {
.driving_updated_for_dev_dis = 0x8,
.use_default_parameter = false,
.is_double_sensitivity_mode = true,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct phy_cfg rtd1315e_phy_cfg = {
@@ -1282,6 +1316,9 @@ static const struct phy_cfg rtd1315e_phy_cfg = {
.driving_updated_for_dev_dis = 0x8,
.use_default_parameter = false,
.is_double_sensitivity_mode = true,
+ .vstatus_offset = 0,
+ .vstatus_busy = PHY_VSTS_BUSY,
+ .new_reg_req = PHY_NEW_REG_REQ,
};
static const struct of_device_id usbphy_rtk_dt_match[] = {
--
2.53.0
^ permalink raw reply related
* [PATCH v2 2/6] phy: realtek: usb2: introduce read and write functions to driver data
From: Rustam Adilov @ 2026-03-27 16:06 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel
Cc: Rustam Adilov, Michael Zavertkin
In-Reply-To: <20260327160638.15134-1-adilov@disroot.org>
RTL9607C is a big endian SoC but has little endian USB host controller and
thus, reads and writes to the reg_gusb2phyacc0 should go through
le32_to_cpu and cpu_to_le32 functions respectively. This doesn't apply to
vstatus register though.
To handle this situation, introduce read and write functions to the driver
data and create 2 variations of reads and write function with le32 function
in it and without.
Adjust all instances of utmi_wait_register function to now include the read
function as one of its arguments.
Assign the existing phy configuration for RTD SoCs to the default phy_read
and phy_write functions.
Co-developed-by: Michael Zavertkin <misha.zavertkin@mail.ru>
Signed-off-by: Michael Zavertkin <misha.zavertkin@mail.ru>
Signed-off-by: Rustam Adilov <adilov@disroot.org>
---
drivers/phy/realtek/phy-rtk-usb2.c | 73 ++++++++++++++++++++++++------
1 file changed, 60 insertions(+), 13 deletions(-)
diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
index f5d2f0c3376a..e65b8525b88b 100644
--- a/drivers/phy/realtek/phy-rtk-usb2.c
+++ b/drivers/phy/realtek/phy-rtk-usb2.c
@@ -67,6 +67,9 @@ struct phy_reg {
int vstatus_offset;
int vstatus_busy;
int new_reg_req;
+
+ u32 (*read)(void __iomem *reg);
+ void (*write)(u32 val, void __iomem *reg);
};
struct phy_data {
@@ -102,6 +105,9 @@ struct phy_cfg {
int vstatus_offset;
int vstatus_busy;
int new_reg_req;
+
+ u32 (*read)(void __iomem *reg);
+ void (*write)(u32 val, void __iomem *reg);
};
struct phy_parameter {
@@ -128,6 +134,26 @@ struct rtk_phy {
struct dentry *debug_dir;
};
+static inline u32 phy_read(void __iomem *reg)
+{
+ return readl(reg);
+}
+
+static inline u32 phy_read_le(void __iomem *reg)
+{
+ return le32_to_cpu(readl(reg));
+}
+
+static inline void phy_write(u32 val, void __iomem *reg)
+{
+ writel(val, reg);
+}
+
+static inline void phy_write_le(u32 val, void __iomem *reg)
+{
+ writel(cpu_to_le32(val), reg);
+}
+
/* mapping 0xE0 to 0 ... 0xE7 to 7, 0xF0 to 8 ,,, 0xF7 to 15 */
static inline int page_addr_to_array_index(u8 addr)
{
@@ -144,12 +170,13 @@ static inline u8 array_index_to_page_addr(int index)
#define PHY_IO_TIMEOUT_USEC (50000)
#define PHY_IO_DELAY_US (100)
-static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+static inline int utmi_wait_register(u32 (*read)(void __iomem *reg), void __iomem *reg, u32 mask,
+ u32 result)
{
int ret;
unsigned int val;
- ret = read_poll_timeout(readl, val, ((val & mask) == result),
+ ret = read_poll_timeout(read, val, ((val & mask) == result),
PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg);
if (ret) {
pr_err("%s can't program USB phy\n", __func__);
@@ -168,25 +195,25 @@ static char rtk_phy_read(struct phy_reg *phy_reg, char addr)
addr -= OFFEST_PHY_READ;
/* polling until VBusy == 0 */
- ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
+ ret = utmi_wait_register(phy_reg->read, reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return (char)ret;
/* VCtrl = low nibble of addr, and set PHY_NEW_REG_REQ */
val = phy_reg->new_reg_req | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
- writel(val, reg_gusb2phyacc0);
- ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
+ phy_reg->write(val, reg_gusb2phyacc0);
+ ret = utmi_wait_register(phy_reg->read, reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return (char)ret;
/* VCtrl = high nibble of addr, and set PHY_NEW_REG_REQ */
val = phy_reg->new_reg_req | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
- writel(val, reg_gusb2phyacc0);
- ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
+ phy_reg->write(val, reg_gusb2phyacc0);
+ ret = utmi_wait_register(phy_reg->read, reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return (char)ret;
- val = readl(reg_gusb2phyacc0);
+ val = phy_reg->read(reg_gusb2phyacc0);
return (char)(val & PHY_REG_DATA_MASK);
}
@@ -202,23 +229,23 @@ static int rtk_phy_write(struct phy_reg *phy_reg, char addr, char data)
/* write data to VStatusOut2 (data output to phy) */
writel((u32)data << shift_bits, reg_wrap_vstatus + phy_reg->vstatus_offset);
- ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
+ ret = utmi_wait_register(phy_reg->read, reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return ret;
/* VCtrl = low nibble of addr, set PHY_NEW_REG_REQ */
val = phy_reg->new_reg_req | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
- writel(val, reg_gusb2phyacc0);
- ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
+ phy_reg->write(val, reg_gusb2phyacc0);
+ ret = utmi_wait_register(phy_reg->read, reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return ret;
/* VCtrl = high nibble of addr, set PHY_NEW_REG_REQ */
val = phy_reg->new_reg_req | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
- writel(val, reg_gusb2phyacc0);
- ret = utmi_wait_register(reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
+ phy_reg->write(val, reg_gusb2phyacc0);
+ ret = utmi_wait_register(phy_reg->read, reg_gusb2phyacc0, phy_reg->vstatus_busy, 0);
if (ret)
return ret;
@@ -984,6 +1011,8 @@ static int parse_phy_data(struct rtk_phy *rtk_phy)
phy_parameter->phy_reg.vstatus_offset = phy_cfg->vstatus_offset;
phy_parameter->phy_reg.vstatus_busy = phy_cfg->vstatus_busy;
phy_parameter->phy_reg.new_reg_req = phy_cfg->new_reg_req;
+ phy_parameter->phy_reg.read = phy_cfg->read;
+ phy_parameter->phy_reg.write = phy_cfg->write;
if (of_property_read_bool(np, "realtek,inverse-hstx-sync-clock"))
phy_parameter->inverse_hstx_sync_clock = true;
@@ -1098,6 +1127,8 @@ static const struct phy_cfg rtd1295_phy_cfg = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct phy_cfg rtd1395_phy_cfg = {
@@ -1125,6 +1156,8 @@ static const struct phy_cfg rtd1395_phy_cfg = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct phy_cfg rtd1395_phy_cfg_2port = {
@@ -1152,6 +1185,8 @@ static const struct phy_cfg rtd1395_phy_cfg_2port = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct phy_cfg rtd1619_phy_cfg = {
@@ -1177,6 +1212,8 @@ static const struct phy_cfg rtd1619_phy_cfg = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct phy_cfg rtd1319_phy_cfg = {
@@ -1206,6 +1243,8 @@ static const struct phy_cfg rtd1319_phy_cfg = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct phy_cfg rtd1312c_phy_cfg = {
@@ -1234,6 +1273,8 @@ static const struct phy_cfg rtd1312c_phy_cfg = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct phy_cfg rtd1619b_phy_cfg = {
@@ -1262,6 +1303,8 @@ static const struct phy_cfg rtd1619b_phy_cfg = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct phy_cfg rtd1319d_phy_cfg = {
@@ -1290,6 +1333,8 @@ static const struct phy_cfg rtd1319d_phy_cfg = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct phy_cfg rtd1315e_phy_cfg = {
@@ -1319,6 +1364,8 @@ static const struct phy_cfg rtd1315e_phy_cfg = {
.vstatus_offset = 0,
.vstatus_busy = PHY_VSTS_BUSY,
.new_reg_req = PHY_NEW_REG_REQ,
+ .read = phy_read,
+ .write = phy_write,
};
static const struct of_device_id usbphy_rtk_dt_match[] = {
--
2.53.0
^ permalink raw reply related
* [PATCH v2 0/6] phy: realtek: usb2: support for RTL9607C USB2 PHY
From: Rustam Adilov @ 2026-03-27 16:06 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stanley Chang, linux-phy, devicetree, linux-kernel
Cc: Rustam Adilov
This patch series for Realtek USB2 PHY driver adds support for RTL9607C
USB2 PHY.
RTL9607C is a big endian MIPS CPU which is quite far from RTD series SoCs
supported by realtek usb2 phy driver, but the phy initilization is found
to be very indentical in most areas.
Most of the code was based on the Realtek's usb driver from the GPL tarball
in [1] and adjusted to fit into the realtek usb2 phy driver code format.
The patch series was split into smaller patches that add/change something
in the driver that are not exactly related to RTL9607C and that also
helps for easier review. That also means, patch 5 depends on all the prior
patches that come before it.
USB2 PHY on RTL9607C is primarly used for its internal OHCI/EHCI controllers.
[1] - https://github.com/jameywine/GPL-for-GP3000/blob/main/linux-5.10.x/arch/mips/rtl9607c/usb.c
---
Changelog in v2:
- Patch 5
- removed the line about OHCI/EHCI controllers from description.
- set the resets to false for RTD SoC devices and changed the
commit message to reflect that.
- Link to v1: https://lore.kernel.org/linux-phy/20260326193419.48419-1-adilov@disroot.org/
Rustam Adilov (6):
phy: realtek: usb2: introduce vstatus/new_reg_req variables to driver
data
phy: realtek: usb2: introduce read and write functions to driver data
dt-bindings: phy: realtek,usb2phy.yaml: extend for resets and RTL9607C
support
phy: realtek: usb2: introduce reset controller struct
phy: realtek: usb2: add support for RTL9607C USB2 PHY
phy: realtek: usb2: Make configs available for MACH_REALTEK_RTL
.../bindings/phy/realtek,usb2phy.yaml | 25 ++-
drivers/phy/realtek/Kconfig | 2 +-
drivers/phy/realtek/phy-rtk-usb2.c | 189 ++++++++++++++++--
3 files changed, 196 insertions(+), 20 deletions(-)
--
2.53.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox