All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v22 0/2] drm/bridge: PS8640 MIPI-to-eDP bridge
@ 2019-12-20  8:17 ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Collabora Kernel ML, matthias.bgg, drinkcat, hsinyi,
	linux-arm-kernel, devicetree, Jonas Karlman, Andrzej Hajda,
	Ulrich Hecht, Philipp Zabel, dri-devel, Neil Armstrong,
	Rob Herring, linux-mediatek, David Airlie, Mark Rutland,
	Jitao Shi, Laurent Pinchart, Jernej Skrabec, Daniel Vetter

Hi all,

This is another version of the driver. Note that the driver changed
significally and is a more simply because now is using the panel_bridge
helpers. Apart from this, I addressed the comments from Maxime, Laurent
and Ezequiel.

This bridge is required to have the embedded display working on an Acer
Chromebook R13 ("Elm"). Hopefully we are a bit more close to have this
driver merged. If more changes are required, please let me know and I
will work on it.

Note: Along these around 20 revisions of this driver I was unable to
reconstruct the full changelog history, so I'm skipping this. Sorry
about that, I promise I'll maintain the changelog for future revisions.

Thanks,
 Enric

Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.
- Remove sysfs attributes because are not really used (Enric Balletbo)
- Use enum for address page offsets (Ezequiel Garcia)
- Remove enable tracking (Enric Balletbo)
- Use panel_bridge API (Laurent Pinchart)
- Do not use kernel-doc format for non kernel-doc formatted commands (Enric Balletbo)
- Remove verbose message for PAGE1_VSTART command (Ezequiel Garcia)
- Use time_is_after_jiffies idiom (Ezequiel Garcia)
- Remove unused macros (Ezequiel Garcia)
- Fix weird alignment in dsi->mode_flags (Laurent Pinchart)
- Use drm_of_find_panel_or_bridge helper (Laurent Pinchart)
- Remove mode-sel-gpios as is not used (Laurent Pinchart)
- Remove error messages to get gpios as the core will already report it (Enric Balletbo)
- Remove redundant message getting the regulators (Laurent Pinchart)
- Rename sleep-gpios to powerdown-gpios (Laurent Pinchart)
- Use ARRAY_SIZE(ps_bridge->page) instead of MAX_DEV when possible (Laurent Pinchart)
- Fix race with userspace accessing the sysfs attributes (Laurent Pinchart)
- Remove id_table as is only used on DR platforms (Laurent Pinchart)
- Convert to new i2c device probe() (Laurent Pinchart)
- Use i2c_smbus_read/write helpers instead of open coding it (Laurent Pinchart)
- Remove unnused global variables (Laurent Pinchart)
- Remove unnused fields in ps8640 struct (Laurent Pinchart)
- Remove commented-out headers (Laurent Pinchart)

Changes in v21:
 - Use devm_i2c_new_dummy_device and fix build issue using deprecated i2c_new_dummy
 - Fix build issue due missing drm_bridge.h
 - Do not remove in ps8640_remove device managed resources

Changes in v19:
 - fixed return value of ps8640_probe() when no panel is found

Changes in v18:
 - followed DRM API changes
 - use DEVICE_ATTR_RO()
 - remove firmware update code
 - add SPDX identifier

Changes in v17:
 - remove some unused head files.
 - add macros for ps8640 pages.
 - remove ddc_i2c client
 - add mipi_dsi_device_register_full
 - remove the manufacturer from the name and i2c_device_id

Changes in v16:
 - Disable ps8640 DSI MCS Function.
 - Rename gpios name more clearly.
 - Tune the ps8640 power on sequence.

Changes in v15:
 - Drop drm_connector_(un)register calls from parade ps8640.
   The main DRM driver mtk_drm_drv now calls
   drm_connector_register_all() after drm_dev_register() in the
   mtk_drm_bind() function. That function should iterate over all
   connectors and call drm_connector_register() for each of them.
   So, remove drm_connector_(un)register calls from parade ps8640.

Changes in v14:
 - update copyright info.
 - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
 - fix some coding style.
 - use sizeof as array counter.
 - use drm_get_edid when read edid.
 - add mutex when firmware updating.

Changes in v13:
 - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
 - fix PAGE2_SW_REST tyro.
 - move the buf[3] init to entrance of the function.

Changes in v12:
 - fix hw_chip_id build warning

Changes in v11:
 - Remove depends on I2C, add DRM depends
 - Reuse ps8640_write_bytes() in ps8640_write_byte()
 - Use timer check for polling like the routines in <linux/iopoll.h>
 - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
 - Check the ps8640 hardware id in ps8640_validate_firmware
 - Remove fw_version check
 - Move ps8640_validate_firmware before ps8640_enter_bl
 - Add ddc_i2c unregister when probe fail and ps8640_remove

Jitao Shi (2):
  Documentation: bridge: Add documentation for ps8640 DT properties
  drm/bridge: Add I2C based driver for ps8640 bridge

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++
 drivers/gpu/drm/bridge/Kconfig                |  11 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/parade-ps8640.c        | 354 ++++++++++++++++++
 4 files changed, 478 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml
 create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c

-- 
2.20.1


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v22 0/2] drm/bridge: PS8640 MIPI-to-eDP bridge
@ 2019-12-20  8:17 ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, devicetree, Jernej Skrabec, drinkcat, Jitao Shi,
	Daniel Vetter, Jonas Karlman, David Airlie, Neil Armstrong,
	dri-devel, Andrzej Hajda, Ulrich Hecht, Rob Herring,
	linux-mediatek, Laurent Pinchart, Philipp Zabel, hsinyi,
	matthias.bgg, Collabora Kernel ML, linux-arm-kernel

Hi all,

This is another version of the driver. Note that the driver changed
significally and is a more simply because now is using the panel_bridge
helpers. Apart from this, I addressed the comments from Maxime, Laurent
and Ezequiel.

This bridge is required to have the embedded display working on an Acer
Chromebook R13 ("Elm"). Hopefully we are a bit more close to have this
driver merged. If more changes are required, please let me know and I
will work on it.

Note: Along these around 20 revisions of this driver I was unable to
reconstruct the full changelog history, so I'm skipping this. Sorry
about that, I promise I'll maintain the changelog for future revisions.

Thanks,
 Enric

Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.
- Remove sysfs attributes because are not really used (Enric Balletbo)
- Use enum for address page offsets (Ezequiel Garcia)
- Remove enable tracking (Enric Balletbo)
- Use panel_bridge API (Laurent Pinchart)
- Do not use kernel-doc format for non kernel-doc formatted commands (Enric Balletbo)
- Remove verbose message for PAGE1_VSTART command (Ezequiel Garcia)
- Use time_is_after_jiffies idiom (Ezequiel Garcia)
- Remove unused macros (Ezequiel Garcia)
- Fix weird alignment in dsi->mode_flags (Laurent Pinchart)
- Use drm_of_find_panel_or_bridge helper (Laurent Pinchart)
- Remove mode-sel-gpios as is not used (Laurent Pinchart)
- Remove error messages to get gpios as the core will already report it (Enric Balletbo)
- Remove redundant message getting the regulators (Laurent Pinchart)
- Rename sleep-gpios to powerdown-gpios (Laurent Pinchart)
- Use ARRAY_SIZE(ps_bridge->page) instead of MAX_DEV when possible (Laurent Pinchart)
- Fix race with userspace accessing the sysfs attributes (Laurent Pinchart)
- Remove id_table as is only used on DR platforms (Laurent Pinchart)
- Convert to new i2c device probe() (Laurent Pinchart)
- Use i2c_smbus_read/write helpers instead of open coding it (Laurent Pinchart)
- Remove unnused global variables (Laurent Pinchart)
- Remove unnused fields in ps8640 struct (Laurent Pinchart)
- Remove commented-out headers (Laurent Pinchart)

Changes in v21:
 - Use devm_i2c_new_dummy_device and fix build issue using deprecated i2c_new_dummy
 - Fix build issue due missing drm_bridge.h
 - Do not remove in ps8640_remove device managed resources

Changes in v19:
 - fixed return value of ps8640_probe() when no panel is found

Changes in v18:
 - followed DRM API changes
 - use DEVICE_ATTR_RO()
 - remove firmware update code
 - add SPDX identifier

Changes in v17:
 - remove some unused head files.
 - add macros for ps8640 pages.
 - remove ddc_i2c client
 - add mipi_dsi_device_register_full
 - remove the manufacturer from the name and i2c_device_id

Changes in v16:
 - Disable ps8640 DSI MCS Function.
 - Rename gpios name more clearly.
 - Tune the ps8640 power on sequence.

Changes in v15:
 - Drop drm_connector_(un)register calls from parade ps8640.
   The main DRM driver mtk_drm_drv now calls
   drm_connector_register_all() after drm_dev_register() in the
   mtk_drm_bind() function. That function should iterate over all
   connectors and call drm_connector_register() for each of them.
   So, remove drm_connector_(un)register calls from parade ps8640.

Changes in v14:
 - update copyright info.
 - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
 - fix some coding style.
 - use sizeof as array counter.
 - use drm_get_edid when read edid.
 - add mutex when firmware updating.

Changes in v13:
 - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
 - fix PAGE2_SW_REST tyro.
 - move the buf[3] init to entrance of the function.

Changes in v12:
 - fix hw_chip_id build warning

Changes in v11:
 - Remove depends on I2C, add DRM depends
 - Reuse ps8640_write_bytes() in ps8640_write_byte()
 - Use timer check for polling like the routines in <linux/iopoll.h>
 - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
 - Check the ps8640 hardware id in ps8640_validate_firmware
 - Remove fw_version check
 - Move ps8640_validate_firmware before ps8640_enter_bl
 - Add ddc_i2c unregister when probe fail and ps8640_remove

Jitao Shi (2):
  Documentation: bridge: Add documentation for ps8640 DT properties
  drm/bridge: Add I2C based driver for ps8640 bridge

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++
 drivers/gpu/drm/bridge/Kconfig                |  11 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/parade-ps8640.c        | 354 ++++++++++++++++++
 4 files changed, 478 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml
 create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c

-- 
2.20.1


_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v22 0/2] drm/bridge: PS8640 MIPI-to-eDP bridge
@ 2019-12-20  8:17 ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, devicetree, Jernej Skrabec, drinkcat, Jitao Shi,
	Daniel Vetter, Jonas Karlman, David Airlie, Neil Armstrong,
	dri-devel, Andrzej Hajda, Ulrich Hecht, Rob Herring,
	linux-mediatek, Laurent Pinchart, Philipp Zabel, hsinyi,
	matthias.bgg, Collabora Kernel ML, linux-arm-kernel

Hi all,

This is another version of the driver. Note that the driver changed
significally and is a more simply because now is using the panel_bridge
helpers. Apart from this, I addressed the comments from Maxime, Laurent
and Ezequiel.

This bridge is required to have the embedded display working on an Acer
Chromebook R13 ("Elm"). Hopefully we are a bit more close to have this
driver merged. If more changes are required, please let me know and I
will work on it.

Note: Along these around 20 revisions of this driver I was unable to
reconstruct the full changelog history, so I'm skipping this. Sorry
about that, I promise I'll maintain the changelog for future revisions.

Thanks,
 Enric

Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.
- Remove sysfs attributes because are not really used (Enric Balletbo)
- Use enum for address page offsets (Ezequiel Garcia)
- Remove enable tracking (Enric Balletbo)
- Use panel_bridge API (Laurent Pinchart)
- Do not use kernel-doc format for non kernel-doc formatted commands (Enric Balletbo)
- Remove verbose message for PAGE1_VSTART command (Ezequiel Garcia)
- Use time_is_after_jiffies idiom (Ezequiel Garcia)
- Remove unused macros (Ezequiel Garcia)
- Fix weird alignment in dsi->mode_flags (Laurent Pinchart)
- Use drm_of_find_panel_or_bridge helper (Laurent Pinchart)
- Remove mode-sel-gpios as is not used (Laurent Pinchart)
- Remove error messages to get gpios as the core will already report it (Enric Balletbo)
- Remove redundant message getting the regulators (Laurent Pinchart)
- Rename sleep-gpios to powerdown-gpios (Laurent Pinchart)
- Use ARRAY_SIZE(ps_bridge->page) instead of MAX_DEV when possible (Laurent Pinchart)
- Fix race with userspace accessing the sysfs attributes (Laurent Pinchart)
- Remove id_table as is only used on DR platforms (Laurent Pinchart)
- Convert to new i2c device probe() (Laurent Pinchart)
- Use i2c_smbus_read/write helpers instead of open coding it (Laurent Pinchart)
- Remove unnused global variables (Laurent Pinchart)
- Remove unnused fields in ps8640 struct (Laurent Pinchart)
- Remove commented-out headers (Laurent Pinchart)

Changes in v21:
 - Use devm_i2c_new_dummy_device and fix build issue using deprecated i2c_new_dummy
 - Fix build issue due missing drm_bridge.h
 - Do not remove in ps8640_remove device managed resources

Changes in v19:
 - fixed return value of ps8640_probe() when no panel is found

Changes in v18:
 - followed DRM API changes
 - use DEVICE_ATTR_RO()
 - remove firmware update code
 - add SPDX identifier

Changes in v17:
 - remove some unused head files.
 - add macros for ps8640 pages.
 - remove ddc_i2c client
 - add mipi_dsi_device_register_full
 - remove the manufacturer from the name and i2c_device_id

Changes in v16:
 - Disable ps8640 DSI MCS Function.
 - Rename gpios name more clearly.
 - Tune the ps8640 power on sequence.

Changes in v15:
 - Drop drm_connector_(un)register calls from parade ps8640.
   The main DRM driver mtk_drm_drv now calls
   drm_connector_register_all() after drm_dev_register() in the
   mtk_drm_bind() function. That function should iterate over all
   connectors and call drm_connector_register() for each of them.
   So, remove drm_connector_(un)register calls from parade ps8640.

Changes in v14:
 - update copyright info.
 - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
 - fix some coding style.
 - use sizeof as array counter.
 - use drm_get_edid when read edid.
 - add mutex when firmware updating.

Changes in v13:
 - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
 - fix PAGE2_SW_REST tyro.
 - move the buf[3] init to entrance of the function.

Changes in v12:
 - fix hw_chip_id build warning

Changes in v11:
 - Remove depends on I2C, add DRM depends
 - Reuse ps8640_write_bytes() in ps8640_write_byte()
 - Use timer check for polling like the routines in <linux/iopoll.h>
 - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
 - Check the ps8640 hardware id in ps8640_validate_firmware
 - Remove fw_version check
 - Move ps8640_validate_firmware before ps8640_enter_bl
 - Add ddc_i2c unregister when probe fail and ps8640_remove

Jitao Shi (2):
  Documentation: bridge: Add documentation for ps8640 DT properties
  drm/bridge: Add I2C based driver for ps8640 bridge

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++
 drivers/gpu/drm/bridge/Kconfig                |  11 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/parade-ps8640.c        | 354 ++++++++++++++++++
 4 files changed, 478 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml
 create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c

-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v22 0/2] drm/bridge: PS8640 MIPI-to-eDP bridge
@ 2019-12-20  8:17 ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, devicetree, Jernej Skrabec, drinkcat, Jitao Shi,
	Jonas Karlman, David Airlie, Neil Armstrong, dri-devel,
	Ulrich Hecht, Rob Herring, linux-mediatek, Laurent Pinchart,
	hsinyi, matthias.bgg, Collabora Kernel ML, linux-arm-kernel

Hi all,

This is another version of the driver. Note that the driver changed
significally and is a more simply because now is using the panel_bridge
helpers. Apart from this, I addressed the comments from Maxime, Laurent
and Ezequiel.

This bridge is required to have the embedded display working on an Acer
Chromebook R13 ("Elm"). Hopefully we are a bit more close to have this
driver merged. If more changes are required, please let me know and I
will work on it.

Note: Along these around 20 revisions of this driver I was unable to
reconstruct the full changelog history, so I'm skipping this. Sorry
about that, I promise I'll maintain the changelog for future revisions.

Thanks,
 Enric

Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.
- Remove sysfs attributes because are not really used (Enric Balletbo)
- Use enum for address page offsets (Ezequiel Garcia)
- Remove enable tracking (Enric Balletbo)
- Use panel_bridge API (Laurent Pinchart)
- Do not use kernel-doc format for non kernel-doc formatted commands (Enric Balletbo)
- Remove verbose message for PAGE1_VSTART command (Ezequiel Garcia)
- Use time_is_after_jiffies idiom (Ezequiel Garcia)
- Remove unused macros (Ezequiel Garcia)
- Fix weird alignment in dsi->mode_flags (Laurent Pinchart)
- Use drm_of_find_panel_or_bridge helper (Laurent Pinchart)
- Remove mode-sel-gpios as is not used (Laurent Pinchart)
- Remove error messages to get gpios as the core will already report it (Enric Balletbo)
- Remove redundant message getting the regulators (Laurent Pinchart)
- Rename sleep-gpios to powerdown-gpios (Laurent Pinchart)
- Use ARRAY_SIZE(ps_bridge->page) instead of MAX_DEV when possible (Laurent Pinchart)
- Fix race with userspace accessing the sysfs attributes (Laurent Pinchart)
- Remove id_table as is only used on DR platforms (Laurent Pinchart)
- Convert to new i2c device probe() (Laurent Pinchart)
- Use i2c_smbus_read/write helpers instead of open coding it (Laurent Pinchart)
- Remove unnused global variables (Laurent Pinchart)
- Remove unnused fields in ps8640 struct (Laurent Pinchart)
- Remove commented-out headers (Laurent Pinchart)

Changes in v21:
 - Use devm_i2c_new_dummy_device and fix build issue using deprecated i2c_new_dummy
 - Fix build issue due missing drm_bridge.h
 - Do not remove in ps8640_remove device managed resources

Changes in v19:
 - fixed return value of ps8640_probe() when no panel is found

Changes in v18:
 - followed DRM API changes
 - use DEVICE_ATTR_RO()
 - remove firmware update code
 - add SPDX identifier

Changes in v17:
 - remove some unused head files.
 - add macros for ps8640 pages.
 - remove ddc_i2c client
 - add mipi_dsi_device_register_full
 - remove the manufacturer from the name and i2c_device_id

Changes in v16:
 - Disable ps8640 DSI MCS Function.
 - Rename gpios name more clearly.
 - Tune the ps8640 power on sequence.

Changes in v15:
 - Drop drm_connector_(un)register calls from parade ps8640.
   The main DRM driver mtk_drm_drv now calls
   drm_connector_register_all() after drm_dev_register() in the
   mtk_drm_bind() function. That function should iterate over all
   connectors and call drm_connector_register() for each of them.
   So, remove drm_connector_(un)register calls from parade ps8640.

Changes in v14:
 - update copyright info.
 - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
 - fix some coding style.
 - use sizeof as array counter.
 - use drm_get_edid when read edid.
 - add mutex when firmware updating.

Changes in v13:
 - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
 - fix PAGE2_SW_REST tyro.
 - move the buf[3] init to entrance of the function.

Changes in v12:
 - fix hw_chip_id build warning

Changes in v11:
 - Remove depends on I2C, add DRM depends
 - Reuse ps8640_write_bytes() in ps8640_write_byte()
 - Use timer check for polling like the routines in <linux/iopoll.h>
 - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
 - Check the ps8640 hardware id in ps8640_validate_firmware
 - Remove fw_version check
 - Move ps8640_validate_firmware before ps8640_enter_bl
 - Add ddc_i2c unregister when probe fail and ps8640_remove

Jitao Shi (2):
  Documentation: bridge: Add documentation for ps8640 DT properties
  drm/bridge: Add I2C based driver for ps8640 bridge

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++
 drivers/gpu/drm/bridge/Kconfig                |  11 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/parade-ps8640.c        | 354 ++++++++++++++++++
 4 files changed, 478 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml
 create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c

-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
  2019-12-20  8:17 ` Enric Balletbo i Serra
  (?)
  (?)
@ 2019-12-20  8:17   ` Enric Balletbo i Serra
  -1 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Collabora Kernel ML, matthias.bgg, drinkcat, hsinyi, Jitao Shi,
	Rob Herring, Philipp Zabel, Ulrich Hecht, linux-arm-kernel,
	devicetree, dri-devel, Rob Herring, linux-mediatek, David Airlie,
	Mark Rutland, Daniel Vetter

From: Jitao Shi <jitao.shi@mediatek.com>

Add documentation for DT properties supported by
ps8640 DSI-eDP converter.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
I maintained the ack from Rob Herring and the review from Philipp
because in essence the only thing I did is migrate to YAML format and
check that no errors are reported via dtbs_check. Just let me know if
you're not agree.

Apart from this note that I removed the mode-sel property because is not
used and I renamed sleep-gpios to powerdown-gpios.

Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.

Changes in v21: None
Changes in v19: None
Changes in v18: None
Changes in v17: None
Changes in v16: None
Changes in v15: None
Changes in v14: None
Changes in v13: None
Changes in v12: None
Changes in v11: None

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644
index 000000000000..5dff93641bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-20  8:17   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, Rob Herring, drinkcat, Jitao Shi, Daniel Vetter,
	Ulrich Hecht, David Airlie, dri-devel, devicetree, Rob Herring,
	linux-mediatek, Philipp Zabel, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

From: Jitao Shi <jitao.shi@mediatek.com>

Add documentation for DT properties supported by
ps8640 DSI-eDP converter.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
I maintained the ack from Rob Herring and the review from Philipp
because in essence the only thing I did is migrate to YAML format and
check that no errors are reported via dtbs_check. Just let me know if
you're not agree.

Apart from this note that I removed the mode-sel property because is not
used and I renamed sleep-gpios to powerdown-gpios.

Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.

Changes in v21: None
Changes in v19: None
Changes in v18: None
Changes in v17: None
Changes in v16: None
Changes in v15: None
Changes in v14: None
Changes in v13: None
Changes in v12: None
Changes in v11: None

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644
index 000000000000..5dff93641bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
-- 
2.20.1


_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-20  8:17   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, Rob Herring, drinkcat, Jitao Shi, Daniel Vetter,
	Ulrich Hecht, David Airlie, dri-devel, devicetree, Rob Herring,
	linux-mediatek, Philipp Zabel, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

From: Jitao Shi <jitao.shi@mediatek.com>

Add documentation for DT properties supported by
ps8640 DSI-eDP converter.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
I maintained the ack from Rob Herring and the review from Philipp
because in essence the only thing I did is migrate to YAML format and
check that no errors are reported via dtbs_check. Just let me know if
you're not agree.

Apart from this note that I removed the mode-sel property because is not
used and I renamed sleep-gpios to powerdown-gpios.

Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.

Changes in v21: None
Changes in v19: None
Changes in v18: None
Changes in v17: None
Changes in v16: None
Changes in v15: None
Changes in v14: None
Changes in v13: None
Changes in v12: None
Changes in v11: None

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644
index 000000000000..5dff93641bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-20  8:17   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, drinkcat, Jitao Shi, Ulrich Hecht, David Airlie,
	dri-devel, devicetree, Rob Herring, linux-mediatek, hsinyi,
	matthias.bgg, Collabora Kernel ML, linux-arm-kernel

From: Jitao Shi <jitao.shi@mediatek.com>

Add documentation for DT properties supported by
ps8640 DSI-eDP converter.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
I maintained the ack from Rob Herring and the review from Philipp
because in essence the only thing I did is migrate to YAML format and
check that no errors are reported via dtbs_check. Just let me know if
you're not agree.

Apart from this note that I removed the mode-sel property because is not
used and I renamed sleep-gpios to powerdown-gpios.

Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.

Changes in v21: None
Changes in v19: None
Changes in v18: None
Changes in v17: None
Changes in v16: None
Changes in v15: None
Changes in v14: None
Changes in v13: None
Changes in v12: None
Changes in v11: None

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644
index 000000000000..5dff93641bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
  2019-12-20  8:17 ` Enric Balletbo i Serra
  (?)
  (?)
@ 2019-12-20  8:17   ` Enric Balletbo i Serra
  -1 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Collabora Kernel ML, matthias.bgg, drinkcat, hsinyi, Jitao Shi,
	Daniel Kurtz, Ulrich Hecht, linux-arm-kernel, Andrzej Hajda,
	Jonas Karlman, dri-devel, Neil Armstrong, linux-mediatek,
	David Airlie, Jernej Skrabec, Laurent Pinchart, Daniel Vetter

From: Jitao Shi <jitao.shi@mediatek.com>

This patch adds drm_bridge driver for parade DSI to eDP bridge chip.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
[uli: followed API changes, removed FW update feature]
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
One of the reviews from Laurent was to use 'i2c_new_ancillary_device'. I
didn't change this for two reasons.
1) It doesn't have a devm version, so the remove path is more simple
using the devm_i2c_new_dummy_device family.
2) IIUC the ancillary function is useful when you want to retrieve the
address from the firmware or DT, that's not really the case here, as we
have a base address and fixed offset to the base address which I think
is not configurable.

Let me know if you still think that I should use the ancillary call.

Changes in v22:
- Remove sysfs attributes because are not really used (Enric Balletbo)
- Use enum for address page offsets (Ezequiel Garcia)
- Remove enable tracking (Enric Balletbo)
- Use panel_bridge API (Laurent Pinchart)
- Do not use kernel-doc format for non kernel-doc formatted commands (Enric Balletbo)
- Remove verbose message for PAGE1_VSTART command (Ezequiel Garcia)
- Use time_is_after_jiffies idiom (Ezequiel Garcia)
- Remove unused macros (Ezequiel Garcia)
- Fix weird alignment in dsi->mode_flags (Laurent Pinchart)
- Use drm_of_find_panel_or_bridge helper (Laurent Pinchart)
- Remove mode-sel-gpios as is not used (Laurent Pinchart)
- Remove error messages to get gpios as the core will already report it (Enric Balletbo)
- Remove redundant message getting the regulators (Laurent Pinchart)
- Rename sleep-gpios to powerdown-gpios (Laurent Pinchart)
- Use ARRAY_SIZE(ps_bridge->page) instead of MAX_DEV when possible (Laurent Pinchart)
- Fix race with userspace accessing the sysfs attributes (Laurent Pinchart)
- Remove id_table as is only used on DR platforms (Laurent Pinchart)
- Convert to new i2c device probe() (Laurent Pinchart)
- Use i2c_smbus_read/write helpers instead of open coding it (Laurent Pinchart)
- Remove unnused global variables (Laurent Pinchart)
- Remove unnused fields in ps8640 struct (Laurent Pinchart)
- Remove commented-out headers (Laurent Pinchart)

Changes in v21:
 - Use devm_i2c_new_dummy_device and fix build issue using deprecated i2c_new_dummy
 - Fix build issue due missing drm_bridge.h
 - Do not remove in ps8640_remove device managed resources

Changes in v19:
 - fixed return value of ps8640_probe() when no panel is found

Changes in v18:
 - followed DRM API changes
 - use DEVICE_ATTR_RO()
 - remove firmware update code
 - add SPDX identifier

Changes in v17:
 - remove some unused head files.
 - add macros for ps8640 pages.
 - remove ddc_i2c client
 - add mipi_dsi_device_register_full
 - remove the manufacturer from the name and i2c_device_id

Changes in v16:
 - Disable ps8640 DSI MCS Function.
 - Rename gpios name more clearly.
 - Tune the ps8640 power on sequence.

Changes in v15:
 - Drop drm_connector_(un)register calls from parade ps8640.
   The main DRM driver mtk_drm_drv now calls
   drm_connector_register_all() after drm_dev_register() in the
   mtk_drm_bind() function. That function should iterate over all
   connectors and call drm_connector_register() for each of them.
   So, remove drm_connector_(un)register calls from parade ps8640.

Changes in v14:
 - update copyright info.
 - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
 - fix some coding style.
 - use sizeof as array counter.
 - use drm_get_edid when read edid.
 - add mutex when firmware updating.

Changes in v13:
 - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
 - fix PAGE2_SW_REST tyro.
 - move the buf[3] init to entrance of the function.

Changes in v12:
 - fix hw_chip_id build warning

Changes in v11:
 - Remove depends on I2C, add DRM depends
 - Reuse ps8640_write_bytes() in ps8640_write_byte()
 - Use timer check for polling like the routines in <linux/iopoll.h>
 - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
 - Check the ps8640 hardware id in ps8640_validate_firmware
 - Remove fw_version check
 - Move ps8640_validate_firmware before ps8640_enter_bl
 - Add ddc_i2c unregister when probe fail and ps8640_remove

 drivers/gpu/drm/bridge/Kconfig         |  11 +
 drivers/gpu/drm/bridge/Makefile        |   1 +
 drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++
 3 files changed, 366 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 4734f6993858..3e0a63011723 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -101,6 +101,17 @@ config DRM_PARADE_PS8622
 	---help---
 	  Parade eDP-LVDS bridge chip driver.
 
+config DRM_PARADE_PS8640
+	tristate "Parade PS8640 MIPI DSI to eDP Converter"
+	depends on OF
+	select DRM_KMS_HELPER
+	select DRM_MIPI_DSI
+	select DRM_PANEL
+	help
+	  Choose this option if you have PS8640 for display
+	  The PS8640 is a high-performance and low-power
+	  MIPI DSI to eDP converter
+
 config DRM_SIL_SII8620
 	tristate "Silicon Image SII8620 HDMI/MHL bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 1c0c92667ac4..91490c595b38 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
+obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
 obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
 obj-$(CONFIG_DRM_SII902X) += sii902x.o
 obj-$(CONFIG_DRM_SII9234) += sii9234.o
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
new file mode 100644
index 000000000000..aa0045037f44
--- /dev/null
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#define PAGE2_GPIO_H		0xa7
+#define PS_GPIO9		BIT(1)
+#define PAGE2_I2C_BYPASS	0xea
+#define I2C_BYPASS_EN		0xd0
+#define PAGE2_MCS_EN		0xf3
+#define MCS_EN			BIT(0)
+#define PAGE3_SET_ADD		0xfe
+#define VDO_CTL_ADD		0x13
+#define VDO_DIS			0x18
+#define VDO_EN			0x1c
+
+/*
+ * PS8640 uses multiple addresses:
+ * page[0]: for DP control
+ * page[1]: for VIDEO Bridge
+ * page[2]: for control top
+ * page[3]: for DSI Link Control1
+ * page[4]: for MIPI Phy
+ * page[5]: for VPLL
+ * page[6]: for DSI Link Control2
+ * page[7]: for SPI ROM mapping
+ */
+enum page_addr_offset {
+	PAGE0_DP_CNTL = 0,
+	PAGE1_VDO_BDG,
+	PAGE2_TOP_CNTL,
+	PAGE3_DSI_CNTL1,
+	PAGE4_MIPI_PHY,
+	PAGE5_VPLL,
+	PAGE6_DSI_CNTL2,
+	PAGE7_SPI_CNTL,
+	MAX_DEVS
+};
+
+struct ps8640 {
+	struct drm_bridge bridge;
+	struct drm_bridge *panel_bridge;
+	struct mipi_dsi_device *dsi;
+	struct i2c_client *page[MAX_DEVS];
+	struct regulator_bulk_data supplies[2];
+	struct gpio_desc *gpio_reset;
+	struct gpio_desc *gpio_powerdown;
+};
+
+static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
+{
+	return container_of(e, struct ps8640, bridge);
+}
+
+static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
+{
+	struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+	u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+					     sizeof(vdo_ctrl_buf),
+					     vdo_ctrl_buf);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
+{
+	struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+	u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+					     sizeof(vdo_ctrl_buf),
+					     vdo_ctrl_buf);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void ps8640_pre_enable(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
+	unsigned long timeout;
+	int ret, status;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
+				    ps_bridge->supplies);
+	if (ret < 0) {
+		DRM_ERROR("cannot enable regulators %d\n", ret);
+		return;
+	}
+
+	gpiod_set_value(ps_bridge->gpio_powerdown, 1);
+	gpiod_set_value(ps_bridge->gpio_reset, 0);
+	usleep_range(2000, 2500);
+	gpiod_set_value(ps_bridge->gpio_reset, 1);
+
+	/*
+	 * Wait for the ps8640 embedded MCU to be ready
+	 * First wait 200ms and then check the MCU ready flag every 20ms
+	 */
+	msleep(200);
+
+	timeout = jiffies + msecs_to_jiffies(200) + 1;
+
+	while (time_is_after_jiffies(timeout)) {
+		status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
+		if (status < 0) {
+			DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
+			goto err_regulators_disable;
+		}
+		if ((status & PS_GPIO9) == PS_GPIO9)
+			break;
+
+		msleep(20);
+	}
+
+	msleep(50);
+
+	/*
+	 * The Manufacturer Command Set (MCS) is a device dependent interface
+	 * intended for factory programming of the display module default
+	 * parameters. Once the display module is configured, the MCS shall be
+	 * disabled by the manufacturer. Once disabled, all MCS commands are
+	 * ignored by the display interface.
+	 */
+	status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
+	if (status < 0) {
+		DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
+		goto err_regulators_disable;
+	}
+
+	ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
+					status & ~MCS_EN);
+	if (ret < 0) {
+		DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
+		goto err_regulators_disable;
+	}
+
+	ret = ps8640_bridge_unmute(ps_bridge);
+	if (ret)
+		DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
+
+	/* Switch access edp panel's edid through i2c */
+	ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
+					I2C_BYPASS_EN);
+	if (ret < 0) {
+		DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
+		goto err_regulators_disable;
+	}
+
+	return;
+
+err_regulators_disable:
+	regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+			       ps_bridge->supplies);
+}
+
+static void ps8640_post_disable(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	int ret;
+
+	ret = ps8640_bridge_mute(ps_bridge);
+	if (ret < 0)
+		DRM_ERROR("failed to unmutevideo: %d\n", ret);
+
+	gpiod_set_value(ps_bridge->gpio_reset, 0);
+	gpiod_set_value(ps_bridge->gpio_powerdown, 0);
+	ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+				     ps_bridge->supplies);
+	if (ret < 0)
+		DRM_ERROR("cannot disable regulators %d\n", ret);
+}
+
+int ps8640_bridge_attach(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	struct device *dev = &ps_bridge->page[0]->dev;
+	struct device_node *in_ep, *dsi_node;
+	struct mipi_dsi_device *dsi;
+	struct mipi_dsi_host *host;
+	int ret;
+	const struct mipi_dsi_device_info info = { .type = "ps8640",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+	/* port@0 is ps8640 dsi input port */
+	in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
+	if (!in_ep)
+		return -ENODEV;
+
+	dsi_node = of_graph_get_remote_port_parent(in_ep);
+	of_node_put(in_ep);
+	if (!dsi_node)
+		return -ENODEV;
+
+	host = of_find_mipi_dsi_host_by_node(dsi_node);
+	of_node_put(dsi_node);
+	if (!host)
+		return -ENODEV;
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		dev_err(dev, "failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		return ret;
+	}
+
+	ps_bridge->dsi = dsi;
+
+	dsi->host = host;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+			  MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->lanes = 4;
+	ret = mipi_dsi_attach(dsi);
+	if (ret)
+		goto err_dsi_attach;
+
+	/* Attach the panel-bridge to the dsi bridge */
+	return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
+				 &ps_bridge->bridge);
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+	return ret;
+}
+
+static const struct drm_bridge_funcs ps8640_bridge_funcs = {
+	.attach = ps8640_bridge_attach,
+	.post_disable = ps8640_post_disable,
+	.pre_enable = ps8640_pre_enable,
+};
+
+static int ps8640_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
+	struct ps8640 *ps_bridge;
+	struct drm_panel *panel;
+	int ret;
+	u32 i;
+
+	ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
+	if (!ps_bridge)
+		return -ENOMEM;
+
+	/* port@1 is ps8640 output port */
+	ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
+	if (ret < 0)
+		return ret;
+	if (!panel)
+		return -ENODEV;
+
+	panel->connector_type = DRM_MODE_CONNECTOR_eDP;
+
+	ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+	if (IS_ERR(ps_bridge->panel_bridge))
+		return PTR_ERR(ps_bridge->panel_bridge);
+
+	ps_bridge->supplies[0].supply = "vdd33";
+	ps_bridge->supplies[1].supply = "vdd12";
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
+				      ps_bridge->supplies);
+	if (ret)
+		return ret;
+
+	ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
+						   GPIOD_OUT_LOW);
+	if (IS_ERR(ps_bridge->gpio_powerdown))
+		return PTR_ERR(ps_bridge->gpio_powerdown);
+
+	/*
+	 * Request the reset pin low to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
+					       GPIOD_OUT_LOW);
+	if (IS_ERR(ps_bridge->gpio_reset))
+		return PTR_ERR(ps_bridge->gpio_reset);
+
+	ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
+	ps_bridge->bridge.of_node = dev->of_node;
+
+	ps_bridge->page[PAGE0_DP_CNTL] = client;
+
+	for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
+		ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
+							     client->adapter,
+							     client->addr + i);
+		if (IS_ERR(ps_bridge->page[i])) {
+			dev_err(dev, "failed i2c dummy device, address%02x\n",
+				client->addr + i);
+			return PTR_ERR(ps_bridge->page[i]);
+		}
+	}
+
+	i2c_set_clientdata(client, ps_bridge);
+
+	drm_bridge_add(&ps_bridge->bridge);
+
+	return 0;
+}
+
+static int ps8640_remove(struct i2c_client *client)
+{
+	struct ps8640 *ps_bridge = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&ps_bridge->bridge);
+
+	return 0;
+}
+
+static const struct of_device_id ps8640_match[] = {
+	{ .compatible = "parade,ps8640" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ps8640_match);
+
+static struct i2c_driver ps8640_driver = {
+	.probe_new = ps8640_probe,
+	.remove = ps8640_remove,
+	.driver = {
+		.name = "ps8640",
+		.of_match_table = ps8640_match,
+	},
+};
+module_i2c_driver(ps8640_driver);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
+MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
+MODULE_LICENSE("GPL v2");
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:17   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ulrich Hecht, Jernej Skrabec, drinkcat, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, Andrzej Hajda, linux-mediatek,
	dri-devel, Daniel Vetter, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel, Laurent Pinchart

From: Jitao Shi <jitao.shi@mediatek.com>

This patch adds drm_bridge driver for parade DSI to eDP bridge chip.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
[uli: followed API changes, removed FW update feature]
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
One of the reviews from Laurent was to use 'i2c_new_ancillary_device'. I
didn't change this for two reasons.
1) It doesn't have a devm version, so the remove path is more simple
using the devm_i2c_new_dummy_device family.
2) IIUC the ancillary function is useful when you want to retrieve the
address from the firmware or DT, that's not really the case here, as we
have a base address and fixed offset to the base address which I think
is not configurable.

Let me know if you still think that I should use the ancillary call.

Changes in v22:
- Remove sysfs attributes because are not really used (Enric Balletbo)
- Use enum for address page offsets (Ezequiel Garcia)
- Remove enable tracking (Enric Balletbo)
- Use panel_bridge API (Laurent Pinchart)
- Do not use kernel-doc format for non kernel-doc formatted commands (Enric Balletbo)
- Remove verbose message for PAGE1_VSTART command (Ezequiel Garcia)
- Use time_is_after_jiffies idiom (Ezequiel Garcia)
- Remove unused macros (Ezequiel Garcia)
- Fix weird alignment in dsi->mode_flags (Laurent Pinchart)
- Use drm_of_find_panel_or_bridge helper (Laurent Pinchart)
- Remove mode-sel-gpios as is not used (Laurent Pinchart)
- Remove error messages to get gpios as the core will already report it (Enric Balletbo)
- Remove redundant message getting the regulators (Laurent Pinchart)
- Rename sleep-gpios to powerdown-gpios (Laurent Pinchart)
- Use ARRAY_SIZE(ps_bridge->page) instead of MAX_DEV when possible (Laurent Pinchart)
- Fix race with userspace accessing the sysfs attributes (Laurent Pinchart)
- Remove id_table as is only used on DR platforms (Laurent Pinchart)
- Convert to new i2c device probe() (Laurent Pinchart)
- Use i2c_smbus_read/write helpers instead of open coding it (Laurent Pinchart)
- Remove unnused global variables (Laurent Pinchart)
- Remove unnused fields in ps8640 struct (Laurent Pinchart)
- Remove commented-out headers (Laurent Pinchart)

Changes in v21:
 - Use devm_i2c_new_dummy_device and fix build issue using deprecated i2c_new_dummy
 - Fix build issue due missing drm_bridge.h
 - Do not remove in ps8640_remove device managed resources

Changes in v19:
 - fixed return value of ps8640_probe() when no panel is found

Changes in v18:
 - followed DRM API changes
 - use DEVICE_ATTR_RO()
 - remove firmware update code
 - add SPDX identifier

Changes in v17:
 - remove some unused head files.
 - add macros for ps8640 pages.
 - remove ddc_i2c client
 - add mipi_dsi_device_register_full
 - remove the manufacturer from the name and i2c_device_id

Changes in v16:
 - Disable ps8640 DSI MCS Function.
 - Rename gpios name more clearly.
 - Tune the ps8640 power on sequence.

Changes in v15:
 - Drop drm_connector_(un)register calls from parade ps8640.
   The main DRM driver mtk_drm_drv now calls
   drm_connector_register_all() after drm_dev_register() in the
   mtk_drm_bind() function. That function should iterate over all
   connectors and call drm_connector_register() for each of them.
   So, remove drm_connector_(un)register calls from parade ps8640.

Changes in v14:
 - update copyright info.
 - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
 - fix some coding style.
 - use sizeof as array counter.
 - use drm_get_edid when read edid.
 - add mutex when firmware updating.

Changes in v13:
 - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
 - fix PAGE2_SW_REST tyro.
 - move the buf[3] init to entrance of the function.

Changes in v12:
 - fix hw_chip_id build warning

Changes in v11:
 - Remove depends on I2C, add DRM depends
 - Reuse ps8640_write_bytes() in ps8640_write_byte()
 - Use timer check for polling like the routines in <linux/iopoll.h>
 - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
 - Check the ps8640 hardware id in ps8640_validate_firmware
 - Remove fw_version check
 - Move ps8640_validate_firmware before ps8640_enter_bl
 - Add ddc_i2c unregister when probe fail and ps8640_remove

 drivers/gpu/drm/bridge/Kconfig         |  11 +
 drivers/gpu/drm/bridge/Makefile        |   1 +
 drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++
 3 files changed, 366 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 4734f6993858..3e0a63011723 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -101,6 +101,17 @@ config DRM_PARADE_PS8622
 	---help---
 	  Parade eDP-LVDS bridge chip driver.
 
+config DRM_PARADE_PS8640
+	tristate "Parade PS8640 MIPI DSI to eDP Converter"
+	depends on OF
+	select DRM_KMS_HELPER
+	select DRM_MIPI_DSI
+	select DRM_PANEL
+	help
+	  Choose this option if you have PS8640 for display
+	  The PS8640 is a high-performance and low-power
+	  MIPI DSI to eDP converter
+
 config DRM_SIL_SII8620
 	tristate "Silicon Image SII8620 HDMI/MHL bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 1c0c92667ac4..91490c595b38 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
+obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
 obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
 obj-$(CONFIG_DRM_SII902X) += sii902x.o
 obj-$(CONFIG_DRM_SII9234) += sii9234.o
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
new file mode 100644
index 000000000000..aa0045037f44
--- /dev/null
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#define PAGE2_GPIO_H		0xa7
+#define PS_GPIO9		BIT(1)
+#define PAGE2_I2C_BYPASS	0xea
+#define I2C_BYPASS_EN		0xd0
+#define PAGE2_MCS_EN		0xf3
+#define MCS_EN			BIT(0)
+#define PAGE3_SET_ADD		0xfe
+#define VDO_CTL_ADD		0x13
+#define VDO_DIS			0x18
+#define VDO_EN			0x1c
+
+/*
+ * PS8640 uses multiple addresses:
+ * page[0]: for DP control
+ * page[1]: for VIDEO Bridge
+ * page[2]: for control top
+ * page[3]: for DSI Link Control1
+ * page[4]: for MIPI Phy
+ * page[5]: for VPLL
+ * page[6]: for DSI Link Control2
+ * page[7]: for SPI ROM mapping
+ */
+enum page_addr_offset {
+	PAGE0_DP_CNTL = 0,
+	PAGE1_VDO_BDG,
+	PAGE2_TOP_CNTL,
+	PAGE3_DSI_CNTL1,
+	PAGE4_MIPI_PHY,
+	PAGE5_VPLL,
+	PAGE6_DSI_CNTL2,
+	PAGE7_SPI_CNTL,
+	MAX_DEVS
+};
+
+struct ps8640 {
+	struct drm_bridge bridge;
+	struct drm_bridge *panel_bridge;
+	struct mipi_dsi_device *dsi;
+	struct i2c_client *page[MAX_DEVS];
+	struct regulator_bulk_data supplies[2];
+	struct gpio_desc *gpio_reset;
+	struct gpio_desc *gpio_powerdown;
+};
+
+static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
+{
+	return container_of(e, struct ps8640, bridge);
+}
+
+static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
+{
+	struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+	u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+					     sizeof(vdo_ctrl_buf),
+					     vdo_ctrl_buf);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
+{
+	struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+	u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+					     sizeof(vdo_ctrl_buf),
+					     vdo_ctrl_buf);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void ps8640_pre_enable(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
+	unsigned long timeout;
+	int ret, status;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
+				    ps_bridge->supplies);
+	if (ret < 0) {
+		DRM_ERROR("cannot enable regulators %d\n", ret);
+		return;
+	}
+
+	gpiod_set_value(ps_bridge->gpio_powerdown, 1);
+	gpiod_set_value(ps_bridge->gpio_reset, 0);
+	usleep_range(2000, 2500);
+	gpiod_set_value(ps_bridge->gpio_reset, 1);
+
+	/*
+	 * Wait for the ps8640 embedded MCU to be ready
+	 * First wait 200ms and then check the MCU ready flag every 20ms
+	 */
+	msleep(200);
+
+	timeout = jiffies + msecs_to_jiffies(200) + 1;
+
+	while (time_is_after_jiffies(timeout)) {
+		status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
+		if (status < 0) {
+			DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
+			goto err_regulators_disable;
+		}
+		if ((status & PS_GPIO9) == PS_GPIO9)
+			break;
+
+		msleep(20);
+	}
+
+	msleep(50);
+
+	/*
+	 * The Manufacturer Command Set (MCS) is a device dependent interface
+	 * intended for factory programming of the display module default
+	 * parameters. Once the display module is configured, the MCS shall be
+	 * disabled by the manufacturer. Once disabled, all MCS commands are
+	 * ignored by the display interface.
+	 */
+	status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
+	if (status < 0) {
+		DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
+		goto err_regulators_disable;
+	}
+
+	ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
+					status & ~MCS_EN);
+	if (ret < 0) {
+		DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
+		goto err_regulators_disable;
+	}
+
+	ret = ps8640_bridge_unmute(ps_bridge);
+	if (ret)
+		DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
+
+	/* Switch access edp panel's edid through i2c */
+	ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
+					I2C_BYPASS_EN);
+	if (ret < 0) {
+		DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
+		goto err_regulators_disable;
+	}
+
+	return;
+
+err_regulators_disable:
+	regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+			       ps_bridge->supplies);
+}
+
+static void ps8640_post_disable(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	int ret;
+
+	ret = ps8640_bridge_mute(ps_bridge);
+	if (ret < 0)
+		DRM_ERROR("failed to unmutevideo: %d\n", ret);
+
+	gpiod_set_value(ps_bridge->gpio_reset, 0);
+	gpiod_set_value(ps_bridge->gpio_powerdown, 0);
+	ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+				     ps_bridge->supplies);
+	if (ret < 0)
+		DRM_ERROR("cannot disable regulators %d\n", ret);
+}
+
+int ps8640_bridge_attach(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	struct device *dev = &ps_bridge->page[0]->dev;
+	struct device_node *in_ep, *dsi_node;
+	struct mipi_dsi_device *dsi;
+	struct mipi_dsi_host *host;
+	int ret;
+	const struct mipi_dsi_device_info info = { .type = "ps8640",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+	/* port@0 is ps8640 dsi input port */
+	in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
+	if (!in_ep)
+		return -ENODEV;
+
+	dsi_node = of_graph_get_remote_port_parent(in_ep);
+	of_node_put(in_ep);
+	if (!dsi_node)
+		return -ENODEV;
+
+	host = of_find_mipi_dsi_host_by_node(dsi_node);
+	of_node_put(dsi_node);
+	if (!host)
+		return -ENODEV;
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		dev_err(dev, "failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		return ret;
+	}
+
+	ps_bridge->dsi = dsi;
+
+	dsi->host = host;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+			  MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->lanes = 4;
+	ret = mipi_dsi_attach(dsi);
+	if (ret)
+		goto err_dsi_attach;
+
+	/* Attach the panel-bridge to the dsi bridge */
+	return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
+				 &ps_bridge->bridge);
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+	return ret;
+}
+
+static const struct drm_bridge_funcs ps8640_bridge_funcs = {
+	.attach = ps8640_bridge_attach,
+	.post_disable = ps8640_post_disable,
+	.pre_enable = ps8640_pre_enable,
+};
+
+static int ps8640_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
+	struct ps8640 *ps_bridge;
+	struct drm_panel *panel;
+	int ret;
+	u32 i;
+
+	ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
+	if (!ps_bridge)
+		return -ENOMEM;
+
+	/* port@1 is ps8640 output port */
+	ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
+	if (ret < 0)
+		return ret;
+	if (!panel)
+		return -ENODEV;
+
+	panel->connector_type = DRM_MODE_CONNECTOR_eDP;
+
+	ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+	if (IS_ERR(ps_bridge->panel_bridge))
+		return PTR_ERR(ps_bridge->panel_bridge);
+
+	ps_bridge->supplies[0].supply = "vdd33";
+	ps_bridge->supplies[1].supply = "vdd12";
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
+				      ps_bridge->supplies);
+	if (ret)
+		return ret;
+
+	ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
+						   GPIOD_OUT_LOW);
+	if (IS_ERR(ps_bridge->gpio_powerdown))
+		return PTR_ERR(ps_bridge->gpio_powerdown);
+
+	/*
+	 * Request the reset pin low to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
+					       GPIOD_OUT_LOW);
+	if (IS_ERR(ps_bridge->gpio_reset))
+		return PTR_ERR(ps_bridge->gpio_reset);
+
+	ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
+	ps_bridge->bridge.of_node = dev->of_node;
+
+	ps_bridge->page[PAGE0_DP_CNTL] = client;
+
+	for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
+		ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
+							     client->adapter,
+							     client->addr + i);
+		if (IS_ERR(ps_bridge->page[i])) {
+			dev_err(dev, "failed i2c dummy device, address%02x\n",
+				client->addr + i);
+			return PTR_ERR(ps_bridge->page[i]);
+		}
+	}
+
+	i2c_set_clientdata(client, ps_bridge);
+
+	drm_bridge_add(&ps_bridge->bridge);
+
+	return 0;
+}
+
+static int ps8640_remove(struct i2c_client *client)
+{
+	struct ps8640 *ps_bridge = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&ps_bridge->bridge);
+
+	return 0;
+}
+
+static const struct of_device_id ps8640_match[] = {
+	{ .compatible = "parade,ps8640" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ps8640_match);
+
+static struct i2c_driver ps8640_driver = {
+	.probe_new = ps8640_probe,
+	.remove = ps8640_remove,
+	.driver = {
+		.name = "ps8640",
+		.of_match_table = ps8640_match,
+	},
+};
+module_i2c_driver(ps8640_driver);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
+MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
+MODULE_LICENSE("GPL v2");
-- 
2.20.1


_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:17   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ulrich Hecht, Jernej Skrabec, drinkcat, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, Daniel Kurtz, Andrzej Hajda,
	linux-mediatek, dri-devel, Daniel Vetter, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel, Laurent Pinchart

From: Jitao Shi <jitao.shi@mediatek.com>

This patch adds drm_bridge driver for parade DSI to eDP bridge chip.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
[uli: followed API changes, removed FW update feature]
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
One of the reviews from Laurent was to use 'i2c_new_ancillary_device'. I
didn't change this for two reasons.
1) It doesn't have a devm version, so the remove path is more simple
using the devm_i2c_new_dummy_device family.
2) IIUC the ancillary function is useful when you want to retrieve the
address from the firmware or DT, that's not really the case here, as we
have a base address and fixed offset to the base address which I think
is not configurable.

Let me know if you still think that I should use the ancillary call.

Changes in v22:
- Remove sysfs attributes because are not really used (Enric Balletbo)
- Use enum for address page offsets (Ezequiel Garcia)
- Remove enable tracking (Enric Balletbo)
- Use panel_bridge API (Laurent Pinchart)
- Do not use kernel-doc format for non kernel-doc formatted commands (Enric Balletbo)
- Remove verbose message for PAGE1_VSTART command (Ezequiel Garcia)
- Use time_is_after_jiffies idiom (Ezequiel Garcia)
- Remove unused macros (Ezequiel Garcia)
- Fix weird alignment in dsi->mode_flags (Laurent Pinchart)
- Use drm_of_find_panel_or_bridge helper (Laurent Pinchart)
- Remove mode-sel-gpios as is not used (Laurent Pinchart)
- Remove error messages to get gpios as the core will already report it (Enric Balletbo)
- Remove redundant message getting the regulators (Laurent Pinchart)
- Rename sleep-gpios to powerdown-gpios (Laurent Pinchart)
- Use ARRAY_SIZE(ps_bridge->page) instead of MAX_DEV when possible (Laurent Pinchart)
- Fix race with userspace accessing the sysfs attributes (Laurent Pinchart)
- Remove id_table as is only used on DR platforms (Laurent Pinchart)
- Convert to new i2c device probe() (Laurent Pinchart)
- Use i2c_smbus_read/write helpers instead of open coding it (Laurent Pinchart)
- Remove unnused global variables (Laurent Pinchart)
- Remove unnused fields in ps8640 struct (Laurent Pinchart)
- Remove commented-out headers (Laurent Pinchart)

Changes in v21:
 - Use devm_i2c_new_dummy_device and fix build issue using deprecated i2c_new_dummy
 - Fix build issue due missing drm_bridge.h
 - Do not remove in ps8640_remove device managed resources

Changes in v19:
 - fixed return value of ps8640_probe() when no panel is found

Changes in v18:
 - followed DRM API changes
 - use DEVICE_ATTR_RO()
 - remove firmware update code
 - add SPDX identifier

Changes in v17:
 - remove some unused head files.
 - add macros for ps8640 pages.
 - remove ddc_i2c client
 - add mipi_dsi_device_register_full
 - remove the manufacturer from the name and i2c_device_id

Changes in v16:
 - Disable ps8640 DSI MCS Function.
 - Rename gpios name more clearly.
 - Tune the ps8640 power on sequence.

Changes in v15:
 - Drop drm_connector_(un)register calls from parade ps8640.
   The main DRM driver mtk_drm_drv now calls
   drm_connector_register_all() after drm_dev_register() in the
   mtk_drm_bind() function. That function should iterate over all
   connectors and call drm_connector_register() for each of them.
   So, remove drm_connector_(un)register calls from parade ps8640.

Changes in v14:
 - update copyright info.
 - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
 - fix some coding style.
 - use sizeof as array counter.
 - use drm_get_edid when read edid.
 - add mutex when firmware updating.

Changes in v13:
 - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
 - fix PAGE2_SW_REST tyro.
 - move the buf[3] init to entrance of the function.

Changes in v12:
 - fix hw_chip_id build warning

Changes in v11:
 - Remove depends on I2C, add DRM depends
 - Reuse ps8640_write_bytes() in ps8640_write_byte()
 - Use timer check for polling like the routines in <linux/iopoll.h>
 - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
 - Check the ps8640 hardware id in ps8640_validate_firmware
 - Remove fw_version check
 - Move ps8640_validate_firmware before ps8640_enter_bl
 - Add ddc_i2c unregister when probe fail and ps8640_remove

 drivers/gpu/drm/bridge/Kconfig         |  11 +
 drivers/gpu/drm/bridge/Makefile        |   1 +
 drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++
 3 files changed, 366 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 4734f6993858..3e0a63011723 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -101,6 +101,17 @@ config DRM_PARADE_PS8622
 	---help---
 	  Parade eDP-LVDS bridge chip driver.
 
+config DRM_PARADE_PS8640
+	tristate "Parade PS8640 MIPI DSI to eDP Converter"
+	depends on OF
+	select DRM_KMS_HELPER
+	select DRM_MIPI_DSI
+	select DRM_PANEL
+	help
+	  Choose this option if you have PS8640 for display
+	  The PS8640 is a high-performance and low-power
+	  MIPI DSI to eDP converter
+
 config DRM_SIL_SII8620
 	tristate "Silicon Image SII8620 HDMI/MHL bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 1c0c92667ac4..91490c595b38 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
+obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
 obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
 obj-$(CONFIG_DRM_SII902X) += sii902x.o
 obj-$(CONFIG_DRM_SII9234) += sii9234.o
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
new file mode 100644
index 000000000000..aa0045037f44
--- /dev/null
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#define PAGE2_GPIO_H		0xa7
+#define PS_GPIO9		BIT(1)
+#define PAGE2_I2C_BYPASS	0xea
+#define I2C_BYPASS_EN		0xd0
+#define PAGE2_MCS_EN		0xf3
+#define MCS_EN			BIT(0)
+#define PAGE3_SET_ADD		0xfe
+#define VDO_CTL_ADD		0x13
+#define VDO_DIS			0x18
+#define VDO_EN			0x1c
+
+/*
+ * PS8640 uses multiple addresses:
+ * page[0]: for DP control
+ * page[1]: for VIDEO Bridge
+ * page[2]: for control top
+ * page[3]: for DSI Link Control1
+ * page[4]: for MIPI Phy
+ * page[5]: for VPLL
+ * page[6]: for DSI Link Control2
+ * page[7]: for SPI ROM mapping
+ */
+enum page_addr_offset {
+	PAGE0_DP_CNTL = 0,
+	PAGE1_VDO_BDG,
+	PAGE2_TOP_CNTL,
+	PAGE3_DSI_CNTL1,
+	PAGE4_MIPI_PHY,
+	PAGE5_VPLL,
+	PAGE6_DSI_CNTL2,
+	PAGE7_SPI_CNTL,
+	MAX_DEVS
+};
+
+struct ps8640 {
+	struct drm_bridge bridge;
+	struct drm_bridge *panel_bridge;
+	struct mipi_dsi_device *dsi;
+	struct i2c_client *page[MAX_DEVS];
+	struct regulator_bulk_data supplies[2];
+	struct gpio_desc *gpio_reset;
+	struct gpio_desc *gpio_powerdown;
+};
+
+static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
+{
+	return container_of(e, struct ps8640, bridge);
+}
+
+static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
+{
+	struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+	u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+					     sizeof(vdo_ctrl_buf),
+					     vdo_ctrl_buf);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
+{
+	struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+	u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+					     sizeof(vdo_ctrl_buf),
+					     vdo_ctrl_buf);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void ps8640_pre_enable(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
+	unsigned long timeout;
+	int ret, status;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
+				    ps_bridge->supplies);
+	if (ret < 0) {
+		DRM_ERROR("cannot enable regulators %d\n", ret);
+		return;
+	}
+
+	gpiod_set_value(ps_bridge->gpio_powerdown, 1);
+	gpiod_set_value(ps_bridge->gpio_reset, 0);
+	usleep_range(2000, 2500);
+	gpiod_set_value(ps_bridge->gpio_reset, 1);
+
+	/*
+	 * Wait for the ps8640 embedded MCU to be ready
+	 * First wait 200ms and then check the MCU ready flag every 20ms
+	 */
+	msleep(200);
+
+	timeout = jiffies + msecs_to_jiffies(200) + 1;
+
+	while (time_is_after_jiffies(timeout)) {
+		status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
+		if (status < 0) {
+			DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
+			goto err_regulators_disable;
+		}
+		if ((status & PS_GPIO9) == PS_GPIO9)
+			break;
+
+		msleep(20);
+	}
+
+	msleep(50);
+
+	/*
+	 * The Manufacturer Command Set (MCS) is a device dependent interface
+	 * intended for factory programming of the display module default
+	 * parameters. Once the display module is configured, the MCS shall be
+	 * disabled by the manufacturer. Once disabled, all MCS commands are
+	 * ignored by the display interface.
+	 */
+	status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
+	if (status < 0) {
+		DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
+		goto err_regulators_disable;
+	}
+
+	ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
+					status & ~MCS_EN);
+	if (ret < 0) {
+		DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
+		goto err_regulators_disable;
+	}
+
+	ret = ps8640_bridge_unmute(ps_bridge);
+	if (ret)
+		DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
+
+	/* Switch access edp panel's edid through i2c */
+	ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
+					I2C_BYPASS_EN);
+	if (ret < 0) {
+		DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
+		goto err_regulators_disable;
+	}
+
+	return;
+
+err_regulators_disable:
+	regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+			       ps_bridge->supplies);
+}
+
+static void ps8640_post_disable(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	int ret;
+
+	ret = ps8640_bridge_mute(ps_bridge);
+	if (ret < 0)
+		DRM_ERROR("failed to unmutevideo: %d\n", ret);
+
+	gpiod_set_value(ps_bridge->gpio_reset, 0);
+	gpiod_set_value(ps_bridge->gpio_powerdown, 0);
+	ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+				     ps_bridge->supplies);
+	if (ret < 0)
+		DRM_ERROR("cannot disable regulators %d\n", ret);
+}
+
+int ps8640_bridge_attach(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	struct device *dev = &ps_bridge->page[0]->dev;
+	struct device_node *in_ep, *dsi_node;
+	struct mipi_dsi_device *dsi;
+	struct mipi_dsi_host *host;
+	int ret;
+	const struct mipi_dsi_device_info info = { .type = "ps8640",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+	/* port@0 is ps8640 dsi input port */
+	in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
+	if (!in_ep)
+		return -ENODEV;
+
+	dsi_node = of_graph_get_remote_port_parent(in_ep);
+	of_node_put(in_ep);
+	if (!dsi_node)
+		return -ENODEV;
+
+	host = of_find_mipi_dsi_host_by_node(dsi_node);
+	of_node_put(dsi_node);
+	if (!host)
+		return -ENODEV;
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		dev_err(dev, "failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		return ret;
+	}
+
+	ps_bridge->dsi = dsi;
+
+	dsi->host = host;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+			  MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->lanes = 4;
+	ret = mipi_dsi_attach(dsi);
+	if (ret)
+		goto err_dsi_attach;
+
+	/* Attach the panel-bridge to the dsi bridge */
+	return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
+				 &ps_bridge->bridge);
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+	return ret;
+}
+
+static const struct drm_bridge_funcs ps8640_bridge_funcs = {
+	.attach = ps8640_bridge_attach,
+	.post_disable = ps8640_post_disable,
+	.pre_enable = ps8640_pre_enable,
+};
+
+static int ps8640_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
+	struct ps8640 *ps_bridge;
+	struct drm_panel *panel;
+	int ret;
+	u32 i;
+
+	ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
+	if (!ps_bridge)
+		return -ENOMEM;
+
+	/* port@1 is ps8640 output port */
+	ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
+	if (ret < 0)
+		return ret;
+	if (!panel)
+		return -ENODEV;
+
+	panel->connector_type = DRM_MODE_CONNECTOR_eDP;
+
+	ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+	if (IS_ERR(ps_bridge->panel_bridge))
+		return PTR_ERR(ps_bridge->panel_bridge);
+
+	ps_bridge->supplies[0].supply = "vdd33";
+	ps_bridge->supplies[1].supply = "vdd12";
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
+				      ps_bridge->supplies);
+	if (ret)
+		return ret;
+
+	ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
+						   GPIOD_OUT_LOW);
+	if (IS_ERR(ps_bridge->gpio_powerdown))
+		return PTR_ERR(ps_bridge->gpio_powerdown);
+
+	/*
+	 * Request the reset pin low to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
+					       GPIOD_OUT_LOW);
+	if (IS_ERR(ps_bridge->gpio_reset))
+		return PTR_ERR(ps_bridge->gpio_reset);
+
+	ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
+	ps_bridge->bridge.of_node = dev->of_node;
+
+	ps_bridge->page[PAGE0_DP_CNTL] = client;
+
+	for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
+		ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
+							     client->adapter,
+							     client->addr + i);
+		if (IS_ERR(ps_bridge->page[i])) {
+			dev_err(dev, "failed i2c dummy device, address%02x\n",
+				client->addr + i);
+			return PTR_ERR(ps_bridge->page[i]);
+		}
+	}
+
+	i2c_set_clientdata(client, ps_bridge);
+
+	drm_bridge_add(&ps_bridge->bridge);
+
+	return 0;
+}
+
+static int ps8640_remove(struct i2c_client *client)
+{
+	struct ps8640 *ps_bridge = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&ps_bridge->bridge);
+
+	return 0;
+}
+
+static const struct of_device_id ps8640_match[] = {
+	{ .compatible = "parade,ps8640" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ps8640_match);
+
+static struct i2c_driver ps8640_driver = {
+	.probe_new = ps8640_probe,
+	.remove = ps8640_remove,
+	.driver = {
+		.name = "ps8640",
+		.of_match_table = ps8640_match,
+	},
+};
+module_i2c_driver(ps8640_driver);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
+MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
+MODULE_LICENSE("GPL v2");
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:17   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-20  8:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ulrich Hecht, Jernej Skrabec, drinkcat, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, linux-mediatek, dri-devel, hsinyi,
	matthias.bgg, Collabora Kernel ML, linux-arm-kernel,
	Laurent Pinchart

From: Jitao Shi <jitao.shi@mediatek.com>

This patch adds drm_bridge driver for parade DSI to eDP bridge chip.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
[uli: followed API changes, removed FW update feature]
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
One of the reviews from Laurent was to use 'i2c_new_ancillary_device'. I
didn't change this for two reasons.
1) It doesn't have a devm version, so the remove path is more simple
using the devm_i2c_new_dummy_device family.
2) IIUC the ancillary function is useful when you want to retrieve the
address from the firmware or DT, that's not really the case here, as we
have a base address and fixed offset to the base address which I think
is not configurable.

Let me know if you still think that I should use the ancillary call.

Changes in v22:
- Remove sysfs attributes because are not really used (Enric Balletbo)
- Use enum for address page offsets (Ezequiel Garcia)
- Remove enable tracking (Enric Balletbo)
- Use panel_bridge API (Laurent Pinchart)
- Do not use kernel-doc format for non kernel-doc formatted commands (Enric Balletbo)
- Remove verbose message for PAGE1_VSTART command (Ezequiel Garcia)
- Use time_is_after_jiffies idiom (Ezequiel Garcia)
- Remove unused macros (Ezequiel Garcia)
- Fix weird alignment in dsi->mode_flags (Laurent Pinchart)
- Use drm_of_find_panel_or_bridge helper (Laurent Pinchart)
- Remove mode-sel-gpios as is not used (Laurent Pinchart)
- Remove error messages to get gpios as the core will already report it (Enric Balletbo)
- Remove redundant message getting the regulators (Laurent Pinchart)
- Rename sleep-gpios to powerdown-gpios (Laurent Pinchart)
- Use ARRAY_SIZE(ps_bridge->page) instead of MAX_DEV when possible (Laurent Pinchart)
- Fix race with userspace accessing the sysfs attributes (Laurent Pinchart)
- Remove id_table as is only used on DR platforms (Laurent Pinchart)
- Convert to new i2c device probe() (Laurent Pinchart)
- Use i2c_smbus_read/write helpers instead of open coding it (Laurent Pinchart)
- Remove unnused global variables (Laurent Pinchart)
- Remove unnused fields in ps8640 struct (Laurent Pinchart)
- Remove commented-out headers (Laurent Pinchart)

Changes in v21:
 - Use devm_i2c_new_dummy_device and fix build issue using deprecated i2c_new_dummy
 - Fix build issue due missing drm_bridge.h
 - Do not remove in ps8640_remove device managed resources

Changes in v19:
 - fixed return value of ps8640_probe() when no panel is found

Changes in v18:
 - followed DRM API changes
 - use DEVICE_ATTR_RO()
 - remove firmware update code
 - add SPDX identifier

Changes in v17:
 - remove some unused head files.
 - add macros for ps8640 pages.
 - remove ddc_i2c client
 - add mipi_dsi_device_register_full
 - remove the manufacturer from the name and i2c_device_id

Changes in v16:
 - Disable ps8640 DSI MCS Function.
 - Rename gpios name more clearly.
 - Tune the ps8640 power on sequence.

Changes in v15:
 - Drop drm_connector_(un)register calls from parade ps8640.
   The main DRM driver mtk_drm_drv now calls
   drm_connector_register_all() after drm_dev_register() in the
   mtk_drm_bind() function. That function should iterate over all
   connectors and call drm_connector_register() for each of them.
   So, remove drm_connector_(un)register calls from parade ps8640.

Changes in v14:
 - update copyright info.
 - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
 - fix some coding style.
 - use sizeof as array counter.
 - use drm_get_edid when read edid.
 - add mutex when firmware updating.

Changes in v13:
 - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
 - fix PAGE2_SW_REST tyro.
 - move the buf[3] init to entrance of the function.

Changes in v12:
 - fix hw_chip_id build warning

Changes in v11:
 - Remove depends on I2C, add DRM depends
 - Reuse ps8640_write_bytes() in ps8640_write_byte()
 - Use timer check for polling like the routines in <linux/iopoll.h>
 - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
 - Check the ps8640 hardware id in ps8640_validate_firmware
 - Remove fw_version check
 - Move ps8640_validate_firmware before ps8640_enter_bl
 - Add ddc_i2c unregister when probe fail and ps8640_remove

 drivers/gpu/drm/bridge/Kconfig         |  11 +
 drivers/gpu/drm/bridge/Makefile        |   1 +
 drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++
 3 files changed, 366 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 4734f6993858..3e0a63011723 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -101,6 +101,17 @@ config DRM_PARADE_PS8622
 	---help---
 	  Parade eDP-LVDS bridge chip driver.
 
+config DRM_PARADE_PS8640
+	tristate "Parade PS8640 MIPI DSI to eDP Converter"
+	depends on OF
+	select DRM_KMS_HELPER
+	select DRM_MIPI_DSI
+	select DRM_PANEL
+	help
+	  Choose this option if you have PS8640 for display
+	  The PS8640 is a high-performance and low-power
+	  MIPI DSI to eDP converter
+
 config DRM_SIL_SII8620
 	tristate "Silicon Image SII8620 HDMI/MHL bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 1c0c92667ac4..91490c595b38 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
+obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
 obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
 obj-$(CONFIG_DRM_SII902X) += sii902x.o
 obj-$(CONFIG_DRM_SII9234) += sii9234.o
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
new file mode 100644
index 000000000000..aa0045037f44
--- /dev/null
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#define PAGE2_GPIO_H		0xa7
+#define PS_GPIO9		BIT(1)
+#define PAGE2_I2C_BYPASS	0xea
+#define I2C_BYPASS_EN		0xd0
+#define PAGE2_MCS_EN		0xf3
+#define MCS_EN			BIT(0)
+#define PAGE3_SET_ADD		0xfe
+#define VDO_CTL_ADD		0x13
+#define VDO_DIS			0x18
+#define VDO_EN			0x1c
+
+/*
+ * PS8640 uses multiple addresses:
+ * page[0]: for DP control
+ * page[1]: for VIDEO Bridge
+ * page[2]: for control top
+ * page[3]: for DSI Link Control1
+ * page[4]: for MIPI Phy
+ * page[5]: for VPLL
+ * page[6]: for DSI Link Control2
+ * page[7]: for SPI ROM mapping
+ */
+enum page_addr_offset {
+	PAGE0_DP_CNTL = 0,
+	PAGE1_VDO_BDG,
+	PAGE2_TOP_CNTL,
+	PAGE3_DSI_CNTL1,
+	PAGE4_MIPI_PHY,
+	PAGE5_VPLL,
+	PAGE6_DSI_CNTL2,
+	PAGE7_SPI_CNTL,
+	MAX_DEVS
+};
+
+struct ps8640 {
+	struct drm_bridge bridge;
+	struct drm_bridge *panel_bridge;
+	struct mipi_dsi_device *dsi;
+	struct i2c_client *page[MAX_DEVS];
+	struct regulator_bulk_data supplies[2];
+	struct gpio_desc *gpio_reset;
+	struct gpio_desc *gpio_powerdown;
+};
+
+static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
+{
+	return container_of(e, struct ps8640, bridge);
+}
+
+static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
+{
+	struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+	u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+					     sizeof(vdo_ctrl_buf),
+					     vdo_ctrl_buf);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
+{
+	struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+	u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+					     sizeof(vdo_ctrl_buf),
+					     vdo_ctrl_buf);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void ps8640_pre_enable(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
+	unsigned long timeout;
+	int ret, status;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
+				    ps_bridge->supplies);
+	if (ret < 0) {
+		DRM_ERROR("cannot enable regulators %d\n", ret);
+		return;
+	}
+
+	gpiod_set_value(ps_bridge->gpio_powerdown, 1);
+	gpiod_set_value(ps_bridge->gpio_reset, 0);
+	usleep_range(2000, 2500);
+	gpiod_set_value(ps_bridge->gpio_reset, 1);
+
+	/*
+	 * Wait for the ps8640 embedded MCU to be ready
+	 * First wait 200ms and then check the MCU ready flag every 20ms
+	 */
+	msleep(200);
+
+	timeout = jiffies + msecs_to_jiffies(200) + 1;
+
+	while (time_is_after_jiffies(timeout)) {
+		status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
+		if (status < 0) {
+			DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
+			goto err_regulators_disable;
+		}
+		if ((status & PS_GPIO9) == PS_GPIO9)
+			break;
+
+		msleep(20);
+	}
+
+	msleep(50);
+
+	/*
+	 * The Manufacturer Command Set (MCS) is a device dependent interface
+	 * intended for factory programming of the display module default
+	 * parameters. Once the display module is configured, the MCS shall be
+	 * disabled by the manufacturer. Once disabled, all MCS commands are
+	 * ignored by the display interface.
+	 */
+	status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
+	if (status < 0) {
+		DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
+		goto err_regulators_disable;
+	}
+
+	ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
+					status & ~MCS_EN);
+	if (ret < 0) {
+		DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
+		goto err_regulators_disable;
+	}
+
+	ret = ps8640_bridge_unmute(ps_bridge);
+	if (ret)
+		DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
+
+	/* Switch access edp panel's edid through i2c */
+	ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
+					I2C_BYPASS_EN);
+	if (ret < 0) {
+		DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
+		goto err_regulators_disable;
+	}
+
+	return;
+
+err_regulators_disable:
+	regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+			       ps_bridge->supplies);
+}
+
+static void ps8640_post_disable(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	int ret;
+
+	ret = ps8640_bridge_mute(ps_bridge);
+	if (ret < 0)
+		DRM_ERROR("failed to unmutevideo: %d\n", ret);
+
+	gpiod_set_value(ps_bridge->gpio_reset, 0);
+	gpiod_set_value(ps_bridge->gpio_powerdown, 0);
+	ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+				     ps_bridge->supplies);
+	if (ret < 0)
+		DRM_ERROR("cannot disable regulators %d\n", ret);
+}
+
+int ps8640_bridge_attach(struct drm_bridge *bridge)
+{
+	struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+	struct device *dev = &ps_bridge->page[0]->dev;
+	struct device_node *in_ep, *dsi_node;
+	struct mipi_dsi_device *dsi;
+	struct mipi_dsi_host *host;
+	int ret;
+	const struct mipi_dsi_device_info info = { .type = "ps8640",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+	/* port@0 is ps8640 dsi input port */
+	in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
+	if (!in_ep)
+		return -ENODEV;
+
+	dsi_node = of_graph_get_remote_port_parent(in_ep);
+	of_node_put(in_ep);
+	if (!dsi_node)
+		return -ENODEV;
+
+	host = of_find_mipi_dsi_host_by_node(dsi_node);
+	of_node_put(dsi_node);
+	if (!host)
+		return -ENODEV;
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		dev_err(dev, "failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		return ret;
+	}
+
+	ps_bridge->dsi = dsi;
+
+	dsi->host = host;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+			  MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->lanes = 4;
+	ret = mipi_dsi_attach(dsi);
+	if (ret)
+		goto err_dsi_attach;
+
+	/* Attach the panel-bridge to the dsi bridge */
+	return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
+				 &ps_bridge->bridge);
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+	return ret;
+}
+
+static const struct drm_bridge_funcs ps8640_bridge_funcs = {
+	.attach = ps8640_bridge_attach,
+	.post_disable = ps8640_post_disable,
+	.pre_enable = ps8640_pre_enable,
+};
+
+static int ps8640_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
+	struct ps8640 *ps_bridge;
+	struct drm_panel *panel;
+	int ret;
+	u32 i;
+
+	ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
+	if (!ps_bridge)
+		return -ENOMEM;
+
+	/* port@1 is ps8640 output port */
+	ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
+	if (ret < 0)
+		return ret;
+	if (!panel)
+		return -ENODEV;
+
+	panel->connector_type = DRM_MODE_CONNECTOR_eDP;
+
+	ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+	if (IS_ERR(ps_bridge->panel_bridge))
+		return PTR_ERR(ps_bridge->panel_bridge);
+
+	ps_bridge->supplies[0].supply = "vdd33";
+	ps_bridge->supplies[1].supply = "vdd12";
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
+				      ps_bridge->supplies);
+	if (ret)
+		return ret;
+
+	ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
+						   GPIOD_OUT_LOW);
+	if (IS_ERR(ps_bridge->gpio_powerdown))
+		return PTR_ERR(ps_bridge->gpio_powerdown);
+
+	/*
+	 * Request the reset pin low to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
+					       GPIOD_OUT_LOW);
+	if (IS_ERR(ps_bridge->gpio_reset))
+		return PTR_ERR(ps_bridge->gpio_reset);
+
+	ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
+	ps_bridge->bridge.of_node = dev->of_node;
+
+	ps_bridge->page[PAGE0_DP_CNTL] = client;
+
+	for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
+		ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
+							     client->adapter,
+							     client->addr + i);
+		if (IS_ERR(ps_bridge->page[i])) {
+			dev_err(dev, "failed i2c dummy device, address%02x\n",
+				client->addr + i);
+			return PTR_ERR(ps_bridge->page[i]);
+		}
+	}
+
+	i2c_set_clientdata(client, ps_bridge);
+
+	drm_bridge_add(&ps_bridge->bridge);
+
+	return 0;
+}
+
+static int ps8640_remove(struct i2c_client *client)
+{
+	struct ps8640 *ps_bridge = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&ps_bridge->bridge);
+
+	return 0;
+}
+
+static const struct of_device_id ps8640_match[] = {
+	{ .compatible = "parade,ps8640" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ps8640_match);
+
+static struct i2c_driver ps8640_driver = {
+	.probe_new = ps8640_probe,
+	.remove = ps8640_remove,
+	.driver = {
+		.name = "ps8640",
+		.of_match_table = ps8640_match,
+	},
+};
+module_i2c_driver(ps8640_driver);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
+MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
+MODULE_LICENSE("GPL v2");
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
  2019-12-20  8:17   ` Enric Balletbo i Serra
  (?)
  (?)
@ 2019-12-20  8:44     ` Nicolas Boichat
  -1 siblings, 0 replies; 44+ messages in thread
From: Nicolas Boichat @ 2019-12-20  8:44 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: lkml, Collabora Kernel ML, Matthias Brugger, Hsin-Yi Wang,
	Jitao Shi, Daniel Kurtz, Ulrich Hecht, linux-arm Mailing List,
	Andrzej Hajda, Jonas Karlman, dri-devel, Neil Armstrong,
	moderated list:ARM/Mediatek SoC support, David Airlie,
	Jernej Skrabec, Laurent Pinchart, Daniel Vetter

On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> From: Jitao Shi <jitao.shi@mediatek.com>
>
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [uli: followed API changes, removed FW update feature]
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
> [snip]
>
>  drivers/gpu/drm/bridge/Kconfig         |  11 +
>  drivers/gpu/drm/bridge/Makefile        |   1 +
>  drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++

Half the size! Sounds great.

Mostly nits below.

>  3 files changed, 366 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>
> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
> new file mode 100644
> index 000000000000..aa0045037f44
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> @@ -0,0 +1,354 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of_graph.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +
> +#define PAGE2_GPIO_H           0xa7
> +#define PS_GPIO9               BIT(1)
> +#define PAGE2_I2C_BYPASS       0xea
> +#define I2C_BYPASS_EN          0xd0
> +#define PAGE2_MCS_EN           0xf3
> +#define MCS_EN                 BIT(0)
> +#define PAGE3_SET_ADD          0xfe
> +#define VDO_CTL_ADD            0x13
> +#define VDO_DIS                        0x18
> +#define VDO_EN                 0x1c
> +
> +/*
> + * PS8640 uses multiple addresses:
> + * page[0]: for DP control
> + * page[1]: for VIDEO Bridge
> + * page[2]: for control top
> + * page[3]: for DSI Link Control1
> + * page[4]: for MIPI Phy
> + * page[5]: for VPLL
> + * page[6]: for DSI Link Control2
> + * page[7]: for SPI ROM mapping
> + */
> +enum page_addr_offset {
> +       PAGE0_DP_CNTL = 0,
> +       PAGE1_VDO_BDG,
> +       PAGE2_TOP_CNTL,
> +       PAGE3_DSI_CNTL1,
> +       PAGE4_MIPI_PHY,
> +       PAGE5_VPLL,
> +       PAGE6_DSI_CNTL2,
> +       PAGE7_SPI_CNTL,
> +       MAX_DEVS
> +};
> +
> +struct ps8640 {
> +       struct drm_bridge bridge;
> +       struct drm_bridge *panel_bridge;
> +       struct mipi_dsi_device *dsi;
> +       struct i2c_client *page[MAX_DEVS];
> +       struct regulator_bulk_data supplies[2];
> +       struct gpio_desc *gpio_reset;
> +       struct gpio_desc *gpio_powerdown;
> +};
> +
> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
> +{
> +       return container_of(e, struct ps8640, bridge);
> +}
> +
> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
> +{
> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };

nit: const?

> +       int ret;
> +
> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
> +                                            sizeof(vdo_ctrl_buf),
> +                                            vdo_ctrl_buf);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
> +{
> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };

ditto

> +       int ret;
> +
> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
> +                                            sizeof(vdo_ctrl_buf),
> +                                            vdo_ctrl_buf);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}

Since the 2 functions are almost the same, you could shrink the driver
a bit further by merging them into one with a boolean parameter? (then
maybe give up on the const u8 comment).

> +
> +static void ps8640_pre_enable(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> +       unsigned long timeout;
> +       int ret, status;
> +
> +       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
> +                                   ps_bridge->supplies);
> +       if (ret < 0) {
> +               DRM_ERROR("cannot enable regulators %d\n", ret);
> +               return;
> +       }
> +
> +       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
> +       usleep_range(2000, 2500);
> +       gpiod_set_value(ps_bridge->gpio_reset, 1);
> +
> +       /*
> +        * Wait for the ps8640 embedded MCU to be ready
> +        * First wait 200ms and then check the MCU ready flag every 20ms
> +        */
> +       msleep(200);
> +
> +       timeout = jiffies + msecs_to_jiffies(200) + 1;
> +
> +       while (time_is_after_jiffies(timeout)) {
> +               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
> +               if (status < 0) {
> +                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
> +                       goto err_regulators_disable;
> +               }
> +               if ((status & PS_GPIO9) == PS_GPIO9)
> +                       break;
> +
> +               msleep(20);
> +       }
> +
> +       msleep(50);
> +
> +       /*
> +        * The Manufacturer Command Set (MCS) is a device dependent interface
> +        * intended for factory programming of the display module default
> +        * parameters. Once the display module is configured, the MCS shall be
> +        * disabled by the manufacturer. Once disabled, all MCS commands are
> +        * ignored by the display interface.
> +        */
> +       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
> +       if (status < 0) {
> +               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
> +               goto err_regulators_disable;
> +       }
> +
> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
> +                                       status & ~MCS_EN);
> +       if (ret < 0) {
> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
> +               goto err_regulators_disable;
> +       }
> +
> +       ret = ps8640_bridge_unmute(ps_bridge);
> +       if (ret)
> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);

failed to unmute? Or failed to enable?

> +
> +       /* Switch access edp panel's edid through i2c */
> +       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
> +                                       I2C_BYPASS_EN);
> +       if (ret < 0) {
> +               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
> +               goto err_regulators_disable;
> +       }
> +
> +       return;
> +
> +err_regulators_disable:
> +       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> +                              ps_bridge->supplies);
> +}
> +
> +static void ps8640_post_disable(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       int ret;
> +
> +       ret = ps8640_bridge_mute(ps_bridge);
> +       if (ret < 0)
> +               DRM_ERROR("failed to unmutevideo: %d\n", ret);

ditto

> +
> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
> +       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
> +       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> +                                    ps_bridge->supplies);
> +       if (ret < 0)
> +               DRM_ERROR("cannot disable regulators %d\n", ret);
> +}
> +
> +int ps8640_bridge_attach(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       struct device *dev = &ps_bridge->page[0]->dev;
> +       struct device_node *in_ep, *dsi_node;
> +       struct mipi_dsi_device *dsi;
> +       struct mipi_dsi_host *host;
> +       int ret;
> +       const struct mipi_dsi_device_info info = { .type = "ps8640",
> +                                                  .channel = 0,
> +                                                  .node = NULL,
> +                                                };
> +       /* port@0 is ps8640 dsi input port */
> +       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
> +       if (!in_ep)
> +               return -ENODEV;
> +
> +       dsi_node = of_graph_get_remote_port_parent(in_ep);
> +       of_node_put(in_ep);
> +       if (!dsi_node)
> +               return -ENODEV;
> +
> +       host = of_find_mipi_dsi_host_by_node(dsi_node);
> +       of_node_put(dsi_node);
> +       if (!host)
> +               return -ENODEV;
> +
> +       dsi = mipi_dsi_device_register_full(host, &info);
> +       if (IS_ERR(dsi)) {
> +               dev_err(dev, "failed to create dsi device\n");
> +               ret = PTR_ERR(dsi);
> +               return ret;
> +       }
> +
> +       ps_bridge->dsi = dsi;
> +
> +       dsi->host = host;
> +       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
> +                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +       dsi->format = MIPI_DSI_FMT_RGB888;
> +       dsi->lanes = 4;
> +       ret = mipi_dsi_attach(dsi);
> +       if (ret)
> +               goto err_dsi_attach;
> +
> +       /* Attach the panel-bridge to the dsi bridge */
> +       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
> +                                &ps_bridge->bridge);
> +
> +err_dsi_attach:
> +       mipi_dsi_device_unregister(dsi);
> +       return ret;
> +}
> +
> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
> +       .attach = ps8640_bridge_attach,
> +       .post_disable = ps8640_post_disable,
> +       .pre_enable = ps8640_pre_enable,
> +};
> +
> +static int ps8640_probe(struct i2c_client *client)
> +{
> +       struct device *dev = &client->dev;
> +       struct device_node *np = dev->of_node;
> +       struct ps8640 *ps_bridge;
> +       struct drm_panel *panel;
> +       int ret;
> +       u32 i;
> +
> +       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
> +       if (!ps_bridge)
> +               return -ENOMEM;
> +
> +       /* port@1 is ps8640 output port */
> +       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
> +       if (ret < 0)
> +               return ret;
> +       if (!panel)
> +               return -ENODEV;
> +
> +       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
> +
> +       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
> +       if (IS_ERR(ps_bridge->panel_bridge))
> +               return PTR_ERR(ps_bridge->panel_bridge);
> +
> +       ps_bridge->supplies[0].supply = "vdd33";
> +       ps_bridge->supplies[1].supply = "vdd12";
> +       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
> +                                     ps_bridge->supplies);
> +       if (ret)
> +               return ret;
> +
> +       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
> +                                                  GPIOD_OUT_LOW);
> +       if (IS_ERR(ps_bridge->gpio_powerdown))
> +               return PTR_ERR(ps_bridge->gpio_powerdown);
> +
> +       /*
> +        * Request the reset pin low to avoid the bridge being
> +        * initialized prematurely
> +        */
> +       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
> +                                              GPIOD_OUT_LOW);
> +       if (IS_ERR(ps_bridge->gpio_reset))
> +               return PTR_ERR(ps_bridge->gpio_reset);
> +
> +       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
> +       ps_bridge->bridge.of_node = dev->of_node;
> +
> +       ps_bridge->page[PAGE0_DP_CNTL] = client;
> +
> +       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
> +               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
> +                                                            client->adapter,
> +                                                            client->addr + i);
> +               if (IS_ERR(ps_bridge->page[i])) {
> +                       dev_err(dev, "failed i2c dummy device, address%02x\n",

Space after address?

> +                               client->addr + i);
> +                       return PTR_ERR(ps_bridge->page[i]);
> +               }
> +       }
> +
> +       i2c_set_clientdata(client, ps_bridge);
> +
> +       drm_bridge_add(&ps_bridge->bridge);
> +
> +       return 0;
> +}
> +
> +static int ps8640_remove(struct i2c_client *client)
> +{
> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
> +
> +       drm_bridge_remove(&ps_bridge->bridge);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id ps8640_match[] = {
> +       { .compatible = "parade,ps8640" },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, ps8640_match);
> +
> +static struct i2c_driver ps8640_driver = {
> +       .probe_new = ps8640_probe,
> +       .remove = ps8640_remove,
> +       .driver = {
> +               .name = "ps8640",
> +               .of_match_table = ps8640_match,
> +       },
> +};
> +module_i2c_driver(ps8640_driver);
> +
> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");

Since you just did a major refactor, do you want to add your name here?

> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.20.1
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:44     ` Nicolas Boichat
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Boichat @ 2019-12-20  8:44 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml, Andrzej Hajda,
	moderated list:ARM/Mediatek SoC support, dri-devel,
	Daniel Vetter, Hsin-Yi Wang, Matthias Brugger,
	Collabora Kernel ML, linux-arm Mailing List, Laurent Pinchart

On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> From: Jitao Shi <jitao.shi@mediatek.com>
>
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [uli: followed API changes, removed FW update feature]
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
> [snip]
>
>  drivers/gpu/drm/bridge/Kconfig         |  11 +
>  drivers/gpu/drm/bridge/Makefile        |   1 +
>  drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++

Half the size! Sounds great.

Mostly nits below.

>  3 files changed, 366 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>
> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
> new file mode 100644
> index 000000000000..aa0045037f44
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> @@ -0,0 +1,354 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of_graph.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +
> +#define PAGE2_GPIO_H           0xa7
> +#define PS_GPIO9               BIT(1)
> +#define PAGE2_I2C_BYPASS       0xea
> +#define I2C_BYPASS_EN          0xd0
> +#define PAGE2_MCS_EN           0xf3
> +#define MCS_EN                 BIT(0)
> +#define PAGE3_SET_ADD          0xfe
> +#define VDO_CTL_ADD            0x13
> +#define VDO_DIS                        0x18
> +#define VDO_EN                 0x1c
> +
> +/*
> + * PS8640 uses multiple addresses:
> + * page[0]: for DP control
> + * page[1]: for VIDEO Bridge
> + * page[2]: for control top
> + * page[3]: for DSI Link Control1
> + * page[4]: for MIPI Phy
> + * page[5]: for VPLL
> + * page[6]: for DSI Link Control2
> + * page[7]: for SPI ROM mapping
> + */
> +enum page_addr_offset {
> +       PAGE0_DP_CNTL = 0,
> +       PAGE1_VDO_BDG,
> +       PAGE2_TOP_CNTL,
> +       PAGE3_DSI_CNTL1,
> +       PAGE4_MIPI_PHY,
> +       PAGE5_VPLL,
> +       PAGE6_DSI_CNTL2,
> +       PAGE7_SPI_CNTL,
> +       MAX_DEVS
> +};
> +
> +struct ps8640 {
> +       struct drm_bridge bridge;
> +       struct drm_bridge *panel_bridge;
> +       struct mipi_dsi_device *dsi;
> +       struct i2c_client *page[MAX_DEVS];
> +       struct regulator_bulk_data supplies[2];
> +       struct gpio_desc *gpio_reset;
> +       struct gpio_desc *gpio_powerdown;
> +};
> +
> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
> +{
> +       return container_of(e, struct ps8640, bridge);
> +}
> +
> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
> +{
> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };

nit: const?

> +       int ret;
> +
> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
> +                                            sizeof(vdo_ctrl_buf),
> +                                            vdo_ctrl_buf);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
> +{
> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };

ditto

> +       int ret;
> +
> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
> +                                            sizeof(vdo_ctrl_buf),
> +                                            vdo_ctrl_buf);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}

Since the 2 functions are almost the same, you could shrink the driver
a bit further by merging them into one with a boolean parameter? (then
maybe give up on the const u8 comment).

> +
> +static void ps8640_pre_enable(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> +       unsigned long timeout;
> +       int ret, status;
> +
> +       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
> +                                   ps_bridge->supplies);
> +       if (ret < 0) {
> +               DRM_ERROR("cannot enable regulators %d\n", ret);
> +               return;
> +       }
> +
> +       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
> +       usleep_range(2000, 2500);
> +       gpiod_set_value(ps_bridge->gpio_reset, 1);
> +
> +       /*
> +        * Wait for the ps8640 embedded MCU to be ready
> +        * First wait 200ms and then check the MCU ready flag every 20ms
> +        */
> +       msleep(200);
> +
> +       timeout = jiffies + msecs_to_jiffies(200) + 1;
> +
> +       while (time_is_after_jiffies(timeout)) {
> +               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
> +               if (status < 0) {
> +                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
> +                       goto err_regulators_disable;
> +               }
> +               if ((status & PS_GPIO9) == PS_GPIO9)
> +                       break;
> +
> +               msleep(20);
> +       }
> +
> +       msleep(50);
> +
> +       /*
> +        * The Manufacturer Command Set (MCS) is a device dependent interface
> +        * intended for factory programming of the display module default
> +        * parameters. Once the display module is configured, the MCS shall be
> +        * disabled by the manufacturer. Once disabled, all MCS commands are
> +        * ignored by the display interface.
> +        */
> +       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
> +       if (status < 0) {
> +               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
> +               goto err_regulators_disable;
> +       }
> +
> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
> +                                       status & ~MCS_EN);
> +       if (ret < 0) {
> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
> +               goto err_regulators_disable;
> +       }
> +
> +       ret = ps8640_bridge_unmute(ps_bridge);
> +       if (ret)
> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);

failed to unmute? Or failed to enable?

> +
> +       /* Switch access edp panel's edid through i2c */
> +       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
> +                                       I2C_BYPASS_EN);
> +       if (ret < 0) {
> +               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
> +               goto err_regulators_disable;
> +       }
> +
> +       return;
> +
> +err_regulators_disable:
> +       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> +                              ps_bridge->supplies);
> +}
> +
> +static void ps8640_post_disable(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       int ret;
> +
> +       ret = ps8640_bridge_mute(ps_bridge);
> +       if (ret < 0)
> +               DRM_ERROR("failed to unmutevideo: %d\n", ret);

ditto

> +
> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
> +       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
> +       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> +                                    ps_bridge->supplies);
> +       if (ret < 0)
> +               DRM_ERROR("cannot disable regulators %d\n", ret);
> +}
> +
> +int ps8640_bridge_attach(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       struct device *dev = &ps_bridge->page[0]->dev;
> +       struct device_node *in_ep, *dsi_node;
> +       struct mipi_dsi_device *dsi;
> +       struct mipi_dsi_host *host;
> +       int ret;
> +       const struct mipi_dsi_device_info info = { .type = "ps8640",
> +                                                  .channel = 0,
> +                                                  .node = NULL,
> +                                                };
> +       /* port@0 is ps8640 dsi input port */
> +       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
> +       if (!in_ep)
> +               return -ENODEV;
> +
> +       dsi_node = of_graph_get_remote_port_parent(in_ep);
> +       of_node_put(in_ep);
> +       if (!dsi_node)
> +               return -ENODEV;
> +
> +       host = of_find_mipi_dsi_host_by_node(dsi_node);
> +       of_node_put(dsi_node);
> +       if (!host)
> +               return -ENODEV;
> +
> +       dsi = mipi_dsi_device_register_full(host, &info);
> +       if (IS_ERR(dsi)) {
> +               dev_err(dev, "failed to create dsi device\n");
> +               ret = PTR_ERR(dsi);
> +               return ret;
> +       }
> +
> +       ps_bridge->dsi = dsi;
> +
> +       dsi->host = host;
> +       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
> +                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +       dsi->format = MIPI_DSI_FMT_RGB888;
> +       dsi->lanes = 4;
> +       ret = mipi_dsi_attach(dsi);
> +       if (ret)
> +               goto err_dsi_attach;
> +
> +       /* Attach the panel-bridge to the dsi bridge */
> +       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
> +                                &ps_bridge->bridge);
> +
> +err_dsi_attach:
> +       mipi_dsi_device_unregister(dsi);
> +       return ret;
> +}
> +
> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
> +       .attach = ps8640_bridge_attach,
> +       .post_disable = ps8640_post_disable,
> +       .pre_enable = ps8640_pre_enable,
> +};
> +
> +static int ps8640_probe(struct i2c_client *client)
> +{
> +       struct device *dev = &client->dev;
> +       struct device_node *np = dev->of_node;
> +       struct ps8640 *ps_bridge;
> +       struct drm_panel *panel;
> +       int ret;
> +       u32 i;
> +
> +       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
> +       if (!ps_bridge)
> +               return -ENOMEM;
> +
> +       /* port@1 is ps8640 output port */
> +       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
> +       if (ret < 0)
> +               return ret;
> +       if (!panel)
> +               return -ENODEV;
> +
> +       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
> +
> +       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
> +       if (IS_ERR(ps_bridge->panel_bridge))
> +               return PTR_ERR(ps_bridge->panel_bridge);
> +
> +       ps_bridge->supplies[0].supply = "vdd33";
> +       ps_bridge->supplies[1].supply = "vdd12";
> +       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
> +                                     ps_bridge->supplies);
> +       if (ret)
> +               return ret;
> +
> +       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
> +                                                  GPIOD_OUT_LOW);
> +       if (IS_ERR(ps_bridge->gpio_powerdown))
> +               return PTR_ERR(ps_bridge->gpio_powerdown);
> +
> +       /*
> +        * Request the reset pin low to avoid the bridge being
> +        * initialized prematurely
> +        */
> +       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
> +                                              GPIOD_OUT_LOW);
> +       if (IS_ERR(ps_bridge->gpio_reset))
> +               return PTR_ERR(ps_bridge->gpio_reset);
> +
> +       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
> +       ps_bridge->bridge.of_node = dev->of_node;
> +
> +       ps_bridge->page[PAGE0_DP_CNTL] = client;
> +
> +       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
> +               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
> +                                                            client->adapter,
> +                                                            client->addr + i);
> +               if (IS_ERR(ps_bridge->page[i])) {
> +                       dev_err(dev, "failed i2c dummy device, address%02x\n",

Space after address?

> +                               client->addr + i);
> +                       return PTR_ERR(ps_bridge->page[i]);
> +               }
> +       }
> +
> +       i2c_set_clientdata(client, ps_bridge);
> +
> +       drm_bridge_add(&ps_bridge->bridge);
> +
> +       return 0;
> +}
> +
> +static int ps8640_remove(struct i2c_client *client)
> +{
> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
> +
> +       drm_bridge_remove(&ps_bridge->bridge);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id ps8640_match[] = {
> +       { .compatible = "parade,ps8640" },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, ps8640_match);
> +
> +static struct i2c_driver ps8640_driver = {
> +       .probe_new = ps8640_probe,
> +       .remove = ps8640_remove,
> +       .driver = {
> +               .name = "ps8640",
> +               .of_match_table = ps8640_match,
> +       },
> +};
> +module_i2c_driver(ps8640_driver);
> +
> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");

Since you just did a major refactor, do you want to add your name here?

> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.20.1
>

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:44     ` Nicolas Boichat
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Boichat @ 2019-12-20  8:44 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml, Daniel Kurtz, Andrzej Hajda,
	moderated list:ARM/Mediatek SoC support, dri-devel,
	Daniel Vetter, Hsin-Yi Wang, Matthias Brugger,
	Collabora Kernel ML, linux-arm Mailing List, Laurent Pinchart

On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> From: Jitao Shi <jitao.shi@mediatek.com>
>
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [uli: followed API changes, removed FW update feature]
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
> [snip]
>
>  drivers/gpu/drm/bridge/Kconfig         |  11 +
>  drivers/gpu/drm/bridge/Makefile        |   1 +
>  drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++

Half the size! Sounds great.

Mostly nits below.

>  3 files changed, 366 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>
> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
> new file mode 100644
> index 000000000000..aa0045037f44
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> @@ -0,0 +1,354 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of_graph.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +
> +#define PAGE2_GPIO_H           0xa7
> +#define PS_GPIO9               BIT(1)
> +#define PAGE2_I2C_BYPASS       0xea
> +#define I2C_BYPASS_EN          0xd0
> +#define PAGE2_MCS_EN           0xf3
> +#define MCS_EN                 BIT(0)
> +#define PAGE3_SET_ADD          0xfe
> +#define VDO_CTL_ADD            0x13
> +#define VDO_DIS                        0x18
> +#define VDO_EN                 0x1c
> +
> +/*
> + * PS8640 uses multiple addresses:
> + * page[0]: for DP control
> + * page[1]: for VIDEO Bridge
> + * page[2]: for control top
> + * page[3]: for DSI Link Control1
> + * page[4]: for MIPI Phy
> + * page[5]: for VPLL
> + * page[6]: for DSI Link Control2
> + * page[7]: for SPI ROM mapping
> + */
> +enum page_addr_offset {
> +       PAGE0_DP_CNTL = 0,
> +       PAGE1_VDO_BDG,
> +       PAGE2_TOP_CNTL,
> +       PAGE3_DSI_CNTL1,
> +       PAGE4_MIPI_PHY,
> +       PAGE5_VPLL,
> +       PAGE6_DSI_CNTL2,
> +       PAGE7_SPI_CNTL,
> +       MAX_DEVS
> +};
> +
> +struct ps8640 {
> +       struct drm_bridge bridge;
> +       struct drm_bridge *panel_bridge;
> +       struct mipi_dsi_device *dsi;
> +       struct i2c_client *page[MAX_DEVS];
> +       struct regulator_bulk_data supplies[2];
> +       struct gpio_desc *gpio_reset;
> +       struct gpio_desc *gpio_powerdown;
> +};
> +
> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
> +{
> +       return container_of(e, struct ps8640, bridge);
> +}
> +
> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
> +{
> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };

nit: const?

> +       int ret;
> +
> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
> +                                            sizeof(vdo_ctrl_buf),
> +                                            vdo_ctrl_buf);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
> +{
> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };

ditto

> +       int ret;
> +
> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
> +                                            sizeof(vdo_ctrl_buf),
> +                                            vdo_ctrl_buf);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}

Since the 2 functions are almost the same, you could shrink the driver
a bit further by merging them into one with a boolean parameter? (then
maybe give up on the const u8 comment).

> +
> +static void ps8640_pre_enable(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> +       unsigned long timeout;
> +       int ret, status;
> +
> +       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
> +                                   ps_bridge->supplies);
> +       if (ret < 0) {
> +               DRM_ERROR("cannot enable regulators %d\n", ret);
> +               return;
> +       }
> +
> +       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
> +       usleep_range(2000, 2500);
> +       gpiod_set_value(ps_bridge->gpio_reset, 1);
> +
> +       /*
> +        * Wait for the ps8640 embedded MCU to be ready
> +        * First wait 200ms and then check the MCU ready flag every 20ms
> +        */
> +       msleep(200);
> +
> +       timeout = jiffies + msecs_to_jiffies(200) + 1;
> +
> +       while (time_is_after_jiffies(timeout)) {
> +               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
> +               if (status < 0) {
> +                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
> +                       goto err_regulators_disable;
> +               }
> +               if ((status & PS_GPIO9) == PS_GPIO9)
> +                       break;
> +
> +               msleep(20);
> +       }
> +
> +       msleep(50);
> +
> +       /*
> +        * The Manufacturer Command Set (MCS) is a device dependent interface
> +        * intended for factory programming of the display module default
> +        * parameters. Once the display module is configured, the MCS shall be
> +        * disabled by the manufacturer. Once disabled, all MCS commands are
> +        * ignored by the display interface.
> +        */
> +       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
> +       if (status < 0) {
> +               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
> +               goto err_regulators_disable;
> +       }
> +
> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
> +                                       status & ~MCS_EN);
> +       if (ret < 0) {
> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
> +               goto err_regulators_disable;
> +       }
> +
> +       ret = ps8640_bridge_unmute(ps_bridge);
> +       if (ret)
> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);

failed to unmute? Or failed to enable?

> +
> +       /* Switch access edp panel's edid through i2c */
> +       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
> +                                       I2C_BYPASS_EN);
> +       if (ret < 0) {
> +               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
> +               goto err_regulators_disable;
> +       }
> +
> +       return;
> +
> +err_regulators_disable:
> +       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> +                              ps_bridge->supplies);
> +}
> +
> +static void ps8640_post_disable(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       int ret;
> +
> +       ret = ps8640_bridge_mute(ps_bridge);
> +       if (ret < 0)
> +               DRM_ERROR("failed to unmutevideo: %d\n", ret);

ditto

> +
> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
> +       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
> +       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> +                                    ps_bridge->supplies);
> +       if (ret < 0)
> +               DRM_ERROR("cannot disable regulators %d\n", ret);
> +}
> +
> +int ps8640_bridge_attach(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       struct device *dev = &ps_bridge->page[0]->dev;
> +       struct device_node *in_ep, *dsi_node;
> +       struct mipi_dsi_device *dsi;
> +       struct mipi_dsi_host *host;
> +       int ret;
> +       const struct mipi_dsi_device_info info = { .type = "ps8640",
> +                                                  .channel = 0,
> +                                                  .node = NULL,
> +                                                };
> +       /* port@0 is ps8640 dsi input port */
> +       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
> +       if (!in_ep)
> +               return -ENODEV;
> +
> +       dsi_node = of_graph_get_remote_port_parent(in_ep);
> +       of_node_put(in_ep);
> +       if (!dsi_node)
> +               return -ENODEV;
> +
> +       host = of_find_mipi_dsi_host_by_node(dsi_node);
> +       of_node_put(dsi_node);
> +       if (!host)
> +               return -ENODEV;
> +
> +       dsi = mipi_dsi_device_register_full(host, &info);
> +       if (IS_ERR(dsi)) {
> +               dev_err(dev, "failed to create dsi device\n");
> +               ret = PTR_ERR(dsi);
> +               return ret;
> +       }
> +
> +       ps_bridge->dsi = dsi;
> +
> +       dsi->host = host;
> +       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
> +                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +       dsi->format = MIPI_DSI_FMT_RGB888;
> +       dsi->lanes = 4;
> +       ret = mipi_dsi_attach(dsi);
> +       if (ret)
> +               goto err_dsi_attach;
> +
> +       /* Attach the panel-bridge to the dsi bridge */
> +       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
> +                                &ps_bridge->bridge);
> +
> +err_dsi_attach:
> +       mipi_dsi_device_unregister(dsi);
> +       return ret;
> +}
> +
> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
> +       .attach = ps8640_bridge_attach,
> +       .post_disable = ps8640_post_disable,
> +       .pre_enable = ps8640_pre_enable,
> +};
> +
> +static int ps8640_probe(struct i2c_client *client)
> +{
> +       struct device *dev = &client->dev;
> +       struct device_node *np = dev->of_node;
> +       struct ps8640 *ps_bridge;
> +       struct drm_panel *panel;
> +       int ret;
> +       u32 i;
> +
> +       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
> +       if (!ps_bridge)
> +               return -ENOMEM;
> +
> +       /* port@1 is ps8640 output port */
> +       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
> +       if (ret < 0)
> +               return ret;
> +       if (!panel)
> +               return -ENODEV;
> +
> +       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
> +
> +       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
> +       if (IS_ERR(ps_bridge->panel_bridge))
> +               return PTR_ERR(ps_bridge->panel_bridge);
> +
> +       ps_bridge->supplies[0].supply = "vdd33";
> +       ps_bridge->supplies[1].supply = "vdd12";
> +       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
> +                                     ps_bridge->supplies);
> +       if (ret)
> +               return ret;
> +
> +       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
> +                                                  GPIOD_OUT_LOW);
> +       if (IS_ERR(ps_bridge->gpio_powerdown))
> +               return PTR_ERR(ps_bridge->gpio_powerdown);
> +
> +       /*
> +        * Request the reset pin low to avoid the bridge being
> +        * initialized prematurely
> +        */
> +       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
> +                                              GPIOD_OUT_LOW);
> +       if (IS_ERR(ps_bridge->gpio_reset))
> +               return PTR_ERR(ps_bridge->gpio_reset);
> +
> +       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
> +       ps_bridge->bridge.of_node = dev->of_node;
> +
> +       ps_bridge->page[PAGE0_DP_CNTL] = client;
> +
> +       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
> +               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
> +                                                            client->adapter,
> +                                                            client->addr + i);
> +               if (IS_ERR(ps_bridge->page[i])) {
> +                       dev_err(dev, "failed i2c dummy device, address%02x\n",

Space after address?

> +                               client->addr + i);
> +                       return PTR_ERR(ps_bridge->page[i]);
> +               }
> +       }
> +
> +       i2c_set_clientdata(client, ps_bridge);
> +
> +       drm_bridge_add(&ps_bridge->bridge);
> +
> +       return 0;
> +}
> +
> +static int ps8640_remove(struct i2c_client *client)
> +{
> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
> +
> +       drm_bridge_remove(&ps_bridge->bridge);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id ps8640_match[] = {
> +       { .compatible = "parade,ps8640" },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, ps8640_match);
> +
> +static struct i2c_driver ps8640_driver = {
> +       .probe_new = ps8640_probe,
> +       .remove = ps8640_remove,
> +       .driver = {
> +               .name = "ps8640",
> +               .of_match_table = ps8640_match,
> +       },
> +};
> +module_i2c_driver(ps8640_driver);
> +
> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");

Since you just did a major refactor, do you want to add your name here?

> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.20.1
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:44     ` Nicolas Boichat
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Boichat @ 2019-12-20  8:44 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml,
	moderated list:ARM/Mediatek SoC support, dri-devel, Hsin-Yi Wang,
	Matthias Brugger, Collabora Kernel ML, linux-arm Mailing List,
	Laurent Pinchart

On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> From: Jitao Shi <jitao.shi@mediatek.com>
>
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [uli: followed API changes, removed FW update feature]
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
> [snip]
>
>  drivers/gpu/drm/bridge/Kconfig         |  11 +
>  drivers/gpu/drm/bridge/Makefile        |   1 +
>  drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++

Half the size! Sounds great.

Mostly nits below.

>  3 files changed, 366 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>
> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
> new file mode 100644
> index 000000000000..aa0045037f44
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> @@ -0,0 +1,354 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of_graph.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +
> +#define PAGE2_GPIO_H           0xa7
> +#define PS_GPIO9               BIT(1)
> +#define PAGE2_I2C_BYPASS       0xea
> +#define I2C_BYPASS_EN          0xd0
> +#define PAGE2_MCS_EN           0xf3
> +#define MCS_EN                 BIT(0)
> +#define PAGE3_SET_ADD          0xfe
> +#define VDO_CTL_ADD            0x13
> +#define VDO_DIS                        0x18
> +#define VDO_EN                 0x1c
> +
> +/*
> + * PS8640 uses multiple addresses:
> + * page[0]: for DP control
> + * page[1]: for VIDEO Bridge
> + * page[2]: for control top
> + * page[3]: for DSI Link Control1
> + * page[4]: for MIPI Phy
> + * page[5]: for VPLL
> + * page[6]: for DSI Link Control2
> + * page[7]: for SPI ROM mapping
> + */
> +enum page_addr_offset {
> +       PAGE0_DP_CNTL = 0,
> +       PAGE1_VDO_BDG,
> +       PAGE2_TOP_CNTL,
> +       PAGE3_DSI_CNTL1,
> +       PAGE4_MIPI_PHY,
> +       PAGE5_VPLL,
> +       PAGE6_DSI_CNTL2,
> +       PAGE7_SPI_CNTL,
> +       MAX_DEVS
> +};
> +
> +struct ps8640 {
> +       struct drm_bridge bridge;
> +       struct drm_bridge *panel_bridge;
> +       struct mipi_dsi_device *dsi;
> +       struct i2c_client *page[MAX_DEVS];
> +       struct regulator_bulk_data supplies[2];
> +       struct gpio_desc *gpio_reset;
> +       struct gpio_desc *gpio_powerdown;
> +};
> +
> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
> +{
> +       return container_of(e, struct ps8640, bridge);
> +}
> +
> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
> +{
> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };

nit: const?

> +       int ret;
> +
> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
> +                                            sizeof(vdo_ctrl_buf),
> +                                            vdo_ctrl_buf);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
> +{
> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };

ditto

> +       int ret;
> +
> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
> +                                            sizeof(vdo_ctrl_buf),
> +                                            vdo_ctrl_buf);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}

Since the 2 functions are almost the same, you could shrink the driver
a bit further by merging them into one with a boolean parameter? (then
maybe give up on the const u8 comment).

> +
> +static void ps8640_pre_enable(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
> +       unsigned long timeout;
> +       int ret, status;
> +
> +       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
> +                                   ps_bridge->supplies);
> +       if (ret < 0) {
> +               DRM_ERROR("cannot enable regulators %d\n", ret);
> +               return;
> +       }
> +
> +       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
> +       usleep_range(2000, 2500);
> +       gpiod_set_value(ps_bridge->gpio_reset, 1);
> +
> +       /*
> +        * Wait for the ps8640 embedded MCU to be ready
> +        * First wait 200ms and then check the MCU ready flag every 20ms
> +        */
> +       msleep(200);
> +
> +       timeout = jiffies + msecs_to_jiffies(200) + 1;
> +
> +       while (time_is_after_jiffies(timeout)) {
> +               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
> +               if (status < 0) {
> +                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
> +                       goto err_regulators_disable;
> +               }
> +               if ((status & PS_GPIO9) == PS_GPIO9)
> +                       break;
> +
> +               msleep(20);
> +       }
> +
> +       msleep(50);
> +
> +       /*
> +        * The Manufacturer Command Set (MCS) is a device dependent interface
> +        * intended for factory programming of the display module default
> +        * parameters. Once the display module is configured, the MCS shall be
> +        * disabled by the manufacturer. Once disabled, all MCS commands are
> +        * ignored by the display interface.
> +        */
> +       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
> +       if (status < 0) {
> +               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
> +               goto err_regulators_disable;
> +       }
> +
> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
> +                                       status & ~MCS_EN);
> +       if (ret < 0) {
> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
> +               goto err_regulators_disable;
> +       }
> +
> +       ret = ps8640_bridge_unmute(ps_bridge);
> +       if (ret)
> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);

failed to unmute? Or failed to enable?

> +
> +       /* Switch access edp panel's edid through i2c */
> +       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
> +                                       I2C_BYPASS_EN);
> +       if (ret < 0) {
> +               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
> +               goto err_regulators_disable;
> +       }
> +
> +       return;
> +
> +err_regulators_disable:
> +       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> +                              ps_bridge->supplies);
> +}
> +
> +static void ps8640_post_disable(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       int ret;
> +
> +       ret = ps8640_bridge_mute(ps_bridge);
> +       if (ret < 0)
> +               DRM_ERROR("failed to unmutevideo: %d\n", ret);

ditto

> +
> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
> +       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
> +       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
> +                                    ps_bridge->supplies);
> +       if (ret < 0)
> +               DRM_ERROR("cannot disable regulators %d\n", ret);
> +}
> +
> +int ps8640_bridge_attach(struct drm_bridge *bridge)
> +{
> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> +       struct device *dev = &ps_bridge->page[0]->dev;
> +       struct device_node *in_ep, *dsi_node;
> +       struct mipi_dsi_device *dsi;
> +       struct mipi_dsi_host *host;
> +       int ret;
> +       const struct mipi_dsi_device_info info = { .type = "ps8640",
> +                                                  .channel = 0,
> +                                                  .node = NULL,
> +                                                };
> +       /* port@0 is ps8640 dsi input port */
> +       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
> +       if (!in_ep)
> +               return -ENODEV;
> +
> +       dsi_node = of_graph_get_remote_port_parent(in_ep);
> +       of_node_put(in_ep);
> +       if (!dsi_node)
> +               return -ENODEV;
> +
> +       host = of_find_mipi_dsi_host_by_node(dsi_node);
> +       of_node_put(dsi_node);
> +       if (!host)
> +               return -ENODEV;
> +
> +       dsi = mipi_dsi_device_register_full(host, &info);
> +       if (IS_ERR(dsi)) {
> +               dev_err(dev, "failed to create dsi device\n");
> +               ret = PTR_ERR(dsi);
> +               return ret;
> +       }
> +
> +       ps_bridge->dsi = dsi;
> +
> +       dsi->host = host;
> +       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
> +                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +       dsi->format = MIPI_DSI_FMT_RGB888;
> +       dsi->lanes = 4;
> +       ret = mipi_dsi_attach(dsi);
> +       if (ret)
> +               goto err_dsi_attach;
> +
> +       /* Attach the panel-bridge to the dsi bridge */
> +       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
> +                                &ps_bridge->bridge);
> +
> +err_dsi_attach:
> +       mipi_dsi_device_unregister(dsi);
> +       return ret;
> +}
> +
> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
> +       .attach = ps8640_bridge_attach,
> +       .post_disable = ps8640_post_disable,
> +       .pre_enable = ps8640_pre_enable,
> +};
> +
> +static int ps8640_probe(struct i2c_client *client)
> +{
> +       struct device *dev = &client->dev;
> +       struct device_node *np = dev->of_node;
> +       struct ps8640 *ps_bridge;
> +       struct drm_panel *panel;
> +       int ret;
> +       u32 i;
> +
> +       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
> +       if (!ps_bridge)
> +               return -ENOMEM;
> +
> +       /* port@1 is ps8640 output port */
> +       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
> +       if (ret < 0)
> +               return ret;
> +       if (!panel)
> +               return -ENODEV;
> +
> +       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
> +
> +       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
> +       if (IS_ERR(ps_bridge->panel_bridge))
> +               return PTR_ERR(ps_bridge->panel_bridge);
> +
> +       ps_bridge->supplies[0].supply = "vdd33";
> +       ps_bridge->supplies[1].supply = "vdd12";
> +       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
> +                                     ps_bridge->supplies);
> +       if (ret)
> +               return ret;
> +
> +       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
> +                                                  GPIOD_OUT_LOW);
> +       if (IS_ERR(ps_bridge->gpio_powerdown))
> +               return PTR_ERR(ps_bridge->gpio_powerdown);
> +
> +       /*
> +        * Request the reset pin low to avoid the bridge being
> +        * initialized prematurely
> +        */
> +       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
> +                                              GPIOD_OUT_LOW);
> +       if (IS_ERR(ps_bridge->gpio_reset))
> +               return PTR_ERR(ps_bridge->gpio_reset);
> +
> +       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
> +       ps_bridge->bridge.of_node = dev->of_node;
> +
> +       ps_bridge->page[PAGE0_DP_CNTL] = client;
> +
> +       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
> +               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
> +                                                            client->adapter,
> +                                                            client->addr + i);
> +               if (IS_ERR(ps_bridge->page[i])) {
> +                       dev_err(dev, "failed i2c dummy device, address%02x\n",

Space after address?

> +                               client->addr + i);
> +                       return PTR_ERR(ps_bridge->page[i]);
> +               }
> +       }
> +
> +       i2c_set_clientdata(client, ps_bridge);
> +
> +       drm_bridge_add(&ps_bridge->bridge);
> +
> +       return 0;
> +}
> +
> +static int ps8640_remove(struct i2c_client *client)
> +{
> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
> +
> +       drm_bridge_remove(&ps_bridge->bridge);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id ps8640_match[] = {
> +       { .compatible = "parade,ps8640" },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, ps8640_match);
> +
> +static struct i2c_driver ps8640_driver = {
> +       .probe_new = ps8640_probe,
> +       .remove = ps8640_remove,
> +       .driver = {
> +               .name = "ps8640",
> +               .of_match_table = ps8640_match,
> +       },
> +};
> +module_i2c_driver(ps8640_driver);
> +
> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");

Since you just did a major refactor, do you want to add your name here?

> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.20.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
  2019-12-20  8:17   ` Enric Balletbo i Serra
  (?)
  (?)
@ 2019-12-20  8:55     ` Hsin-Yi Wang
  -1 siblings, 0 replies; 44+ messages in thread
From: Hsin-Yi Wang @ 2019-12-20  8:55 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: lkml, Collabora Kernel ML, Matthias Brugger, Nicolas Boichat,
	Jitao Shi, Daniel Kurtz, Ulrich Hecht,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Andrzej Hajda, Jonas Karlman, dri-devel, Neil Armstrong,
	linux-mediatek, David Airlie, Jernej Skrabec, Laurent Pinchart,
	Daniel Vetter

On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> From: Jitao Shi <jitao.shi@mediatek.com>
>
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [uli: followed API changes, removed FW update feature]
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
> ---
tested on mt8173 chromebook

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:55     ` Hsin-Yi Wang
  0 siblings, 0 replies; 44+ messages in thread
From: Hsin-Yi Wang @ 2019-12-20  8:55 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Nicolas Boichat, Jitao Shi,
	Jonas Karlman, David Airlie, Neil Armstrong, lkml, Andrzej Hajda,
	linux-mediatek, dri-devel, Daniel Vetter, Matthias Brugger,
	Collabora Kernel ML,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Laurent Pinchart

On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> From: Jitao Shi <jitao.shi@mediatek.com>
>
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [uli: followed API changes, removed FW update feature]
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
> ---
tested on mt8173 chromebook

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:55     ` Hsin-Yi Wang
  0 siblings, 0 replies; 44+ messages in thread
From: Hsin-Yi Wang @ 2019-12-20  8:55 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Nicolas Boichat, Jitao Shi,
	Jonas Karlman, David Airlie, Neil Armstrong, lkml, Daniel Kurtz,
	Andrzej Hajda, linux-mediatek, dri-devel, Daniel Vetter,
	Matthias Brugger, Collabora Kernel ML,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Laurent Pinchart

On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> From: Jitao Shi <jitao.shi@mediatek.com>
>
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [uli: followed API changes, removed FW update feature]
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
> ---
tested on mt8173 chromebook

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-20  8:55     ` Hsin-Yi Wang
  0 siblings, 0 replies; 44+ messages in thread
From: Hsin-Yi Wang @ 2019-12-20  8:55 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Nicolas Boichat, Jitao Shi,
	Jonas Karlman, David Airlie, Neil Armstrong, lkml,
	linux-mediatek, dri-devel, Matthias Brugger, Collabora Kernel ML,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Laurent Pinchart

On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> From: Jitao Shi <jitao.shi@mediatek.com>
>
> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [uli: followed API changes, removed FW update feature]
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
> ---
tested on mt8173 chromebook
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
  2019-12-20  8:44     ` Nicolas Boichat
  (?)
  (?)
@ 2019-12-23  7:09       ` Enric Balletbo i Serra
  -1 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23  7:09 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: lkml, Collabora Kernel ML, Matthias Brugger, Hsin-Yi Wang,
	Jitao Shi, Daniel Kurtz, Ulrich Hecht, linux-arm Mailing List,
	Andrzej Hajda, Jonas Karlman, dri-devel, Neil Armstrong,
	moderated list:ARM/Mediatek SoC support, David Airlie,
	Jernej Skrabec, Laurent Pinchart, Daniel Vetter

Hi Nicolas,

Many thanks for you review. Just preparing a new version with your comments
addressed.

On 20/12/19 9:44, Nicolas Boichat wrote:
> On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>>
>> From: Jitao Shi <jitao.shi@mediatek.com>
>>
>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>
>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> [uli: followed API changes, removed FW update feature]
>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> ---
>> [snip]
>>
>>  drivers/gpu/drm/bridge/Kconfig         |  11 +
>>  drivers/gpu/drm/bridge/Makefile        |   1 +
>>  drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++
> 
> Half the size! Sounds great.
> 
> Mostly nits below.
> 
>>  3 files changed, 366 insertions(+)
>>  create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>>
>> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
>> new file mode 100644
>> index 000000000000..aa0045037f44
>> --- /dev/null
>> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
>> @@ -0,0 +1,354 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2016 MediaTek Inc.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/of_graph.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_mipi_dsi.h>
>> +#include <drm/drm_of.h>
>> +#include <drm/drm_panel.h>
>> +#include <drm/drm_print.h>
>> +
>> +#define PAGE2_GPIO_H           0xa7
>> +#define PS_GPIO9               BIT(1)
>> +#define PAGE2_I2C_BYPASS       0xea
>> +#define I2C_BYPASS_EN          0xd0
>> +#define PAGE2_MCS_EN           0xf3
>> +#define MCS_EN                 BIT(0)
>> +#define PAGE3_SET_ADD          0xfe
>> +#define VDO_CTL_ADD            0x13
>> +#define VDO_DIS                        0x18
>> +#define VDO_EN                 0x1c
>> +
>> +/*
>> + * PS8640 uses multiple addresses:
>> + * page[0]: for DP control
>> + * page[1]: for VIDEO Bridge
>> + * page[2]: for control top
>> + * page[3]: for DSI Link Control1
>> + * page[4]: for MIPI Phy
>> + * page[5]: for VPLL
>> + * page[6]: for DSI Link Control2
>> + * page[7]: for SPI ROM mapping
>> + */
>> +enum page_addr_offset {
>> +       PAGE0_DP_CNTL = 0,
>> +       PAGE1_VDO_BDG,
>> +       PAGE2_TOP_CNTL,
>> +       PAGE3_DSI_CNTL1,
>> +       PAGE4_MIPI_PHY,
>> +       PAGE5_VPLL,
>> +       PAGE6_DSI_CNTL2,
>> +       PAGE7_SPI_CNTL,
>> +       MAX_DEVS
>> +};
>> +
>> +struct ps8640 {
>> +       struct drm_bridge bridge;
>> +       struct drm_bridge *panel_bridge;
>> +       struct mipi_dsi_device *dsi;
>> +       struct i2c_client *page[MAX_DEVS];
>> +       struct regulator_bulk_data supplies[2];
>> +       struct gpio_desc *gpio_reset;
>> +       struct gpio_desc *gpio_powerdown;
>> +};
>> +
>> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
>> +{
>> +       return container_of(e, struct ps8640, bridge);
>> +}
>> +
>> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
>> +{
>> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
>> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };
> 
> nit: const?
> 
>> +       int ret;
>> +
>> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
>> +                                            sizeof(vdo_ctrl_buf),
>> +                                            vdo_ctrl_buf);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return 0;
>> +}
>> +
>> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
>> +{
>> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
>> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };
> 
> ditto
> 
>> +       int ret;
>> +
>> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
>> +                                            sizeof(vdo_ctrl_buf),
>> +                                            vdo_ctrl_buf);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return 0;
>> +}
> 
> Since the 2 functions are almost the same, you could shrink the driver
> a bit further by merging them into one with a boolean parameter? (then
> maybe give up on the const u8 comment).
> 

I decided to merge the two functions and use and enum instead of a boolean
parameter, so the "bool" value is more understandable.

>> +
>> +static void ps8640_pre_enable(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
>> +       unsigned long timeout;
>> +       int ret, status;
>> +
>> +       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
>> +                                   ps_bridge->supplies);
>> +       if (ret < 0) {
>> +               DRM_ERROR("cannot enable regulators %d\n", ret);
>> +               return;
>> +       }
>> +
>> +       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
>> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
>> +       usleep_range(2000, 2500);
>> +       gpiod_set_value(ps_bridge->gpio_reset, 1);
>> +
>> +       /*
>> +        * Wait for the ps8640 embedded MCU to be ready
>> +        * First wait 200ms and then check the MCU ready flag every 20ms
>> +        */
>> +       msleep(200);
>> +
>> +       timeout = jiffies + msecs_to_jiffies(200) + 1;
>> +
>> +       while (time_is_after_jiffies(timeout)) {
>> +               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
>> +               if (status < 0) {
>> +                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
>> +                       goto err_regulators_disable;
>> +               }
>> +               if ((status & PS_GPIO9) == PS_GPIO9)
>> +                       break;
>> +
>> +               msleep(20);
>> +       }
>> +
>> +       msleep(50);
>> +
>> +       /*
>> +        * The Manufacturer Command Set (MCS) is a device dependent interface
>> +        * intended for factory programming of the display module default
>> +        * parameters. Once the display module is configured, the MCS shall be
>> +        * disabled by the manufacturer. Once disabled, all MCS commands are
>> +        * ignored by the display interface.
>> +        */
>> +       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
>> +       if (status < 0) {
>> +               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
>> +                                       status & ~MCS_EN);
>> +       if (ret < 0) {
>> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       ret = ps8640_bridge_unmute(ps_bridge);
>> +       if (ret)
>> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
> 
> failed to unmute? Or failed to enable?
> 

failed to unmute sound more clear to me.

>> +
>> +       /* Switch access edp panel's edid through i2c */
>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
>> +                                       I2C_BYPASS_EN);
>> +       if (ret < 0) {
>> +               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       return;
>> +
>> +err_regulators_disable:
>> +       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> +                              ps_bridge->supplies);
>> +}
>> +
>> +static void ps8640_post_disable(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       int ret;
>> +
>> +       ret = ps8640_bridge_mute(ps_bridge);
>> +       if (ret < 0)
>> +               DRM_ERROR("failed to unmutevideo: %d\n", ret);
> 
> ditto
> 

Done.

>> +
>> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
>> +       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
>> +       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> +                                    ps_bridge->supplies);
>> +       if (ret < 0)
>> +               DRM_ERROR("cannot disable regulators %d\n", ret);
>> +}
>> +
>> +int ps8640_bridge_attach(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       struct device *dev = &ps_bridge->page[0]->dev;
>> +       struct device_node *in_ep, *dsi_node;
>> +       struct mipi_dsi_device *dsi;
>> +       struct mipi_dsi_host *host;
>> +       int ret;
>> +       const struct mipi_dsi_device_info info = { .type = "ps8640",
>> +                                                  .channel = 0,
>> +                                                  .node = NULL,
>> +                                                };
>> +       /* port@0 is ps8640 dsi input port */
>> +       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
>> +       if (!in_ep)
>> +               return -ENODEV;
>> +
>> +       dsi_node = of_graph_get_remote_port_parent(in_ep);
>> +       of_node_put(in_ep);
>> +       if (!dsi_node)
>> +               return -ENODEV;
>> +
>> +       host = of_find_mipi_dsi_host_by_node(dsi_node);
>> +       of_node_put(dsi_node);
>> +       if (!host)
>> +               return -ENODEV;
>> +
>> +       dsi = mipi_dsi_device_register_full(host, &info);
>> +       if (IS_ERR(dsi)) {
>> +               dev_err(dev, "failed to create dsi device\n");
>> +               ret = PTR_ERR(dsi);
>> +               return ret;
>> +       }
>> +
>> +       ps_bridge->dsi = dsi;
>> +
>> +       dsi->host = host;
>> +       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
>> +                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> +       dsi->format = MIPI_DSI_FMT_RGB888;
>> +       dsi->lanes = 4;
>> +       ret = mipi_dsi_attach(dsi);
>> +       if (ret)
>> +               goto err_dsi_attach;
>> +
>> +       /* Attach the panel-bridge to the dsi bridge */
>> +       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
>> +                                &ps_bridge->bridge);
>> +
>> +err_dsi_attach:
>> +       mipi_dsi_device_unregister(dsi);
>> +       return ret;
>> +}
>> +
>> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
>> +       .attach = ps8640_bridge_attach,
>> +       .post_disable = ps8640_post_disable,
>> +       .pre_enable = ps8640_pre_enable,
>> +};
>> +
>> +static int ps8640_probe(struct i2c_client *client)
>> +{
>> +       struct device *dev = &client->dev;
>> +       struct device_node *np = dev->of_node;
>> +       struct ps8640 *ps_bridge;
>> +       struct drm_panel *panel;
>> +       int ret;
>> +       u32 i;
>> +
>> +       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
>> +       if (!ps_bridge)
>> +               return -ENOMEM;
>> +
>> +       /* port@1 is ps8640 output port */
>> +       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
>> +       if (ret < 0)
>> +               return ret;
>> +       if (!panel)
>> +               return -ENODEV;
>> +
>> +       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
>> +
>> +       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
>> +       if (IS_ERR(ps_bridge->panel_bridge))
>> +               return PTR_ERR(ps_bridge->panel_bridge);
>> +
>> +       ps_bridge->supplies[0].supply = "vdd33";
>> +       ps_bridge->supplies[1].supply = "vdd12";
>> +       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
>> +                                     ps_bridge->supplies);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
>> +                                                  GPIOD_OUT_LOW);
>> +       if (IS_ERR(ps_bridge->gpio_powerdown))
>> +               return PTR_ERR(ps_bridge->gpio_powerdown);
>> +
>> +       /*
>> +        * Request the reset pin low to avoid the bridge being
>> +        * initialized prematurely
>> +        */
>> +       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
>> +                                              GPIOD_OUT_LOW);
>> +       if (IS_ERR(ps_bridge->gpio_reset))
>> +               return PTR_ERR(ps_bridge->gpio_reset);
>> +
>> +       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
>> +       ps_bridge->bridge.of_node = dev->of_node;
>> +
>> +       ps_bridge->page[PAGE0_DP_CNTL] = client;
>> +
>> +       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
>> +               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
>> +                                                            client->adapter,
>> +                                                            client->addr + i);
>> +               if (IS_ERR(ps_bridge->page[i])) {
>> +                       dev_err(dev, "failed i2c dummy device, address%02x\n",
> 
> Space after address?
> 

Ack and done.

>> +                               client->addr + i);
>> +                       return PTR_ERR(ps_bridge->page[i]);
>> +               }
>> +       }
>> +
>> +       i2c_set_clientdata(client, ps_bridge);
>> +
>> +       drm_bridge_add(&ps_bridge->bridge);
>> +
>> +       return 0;
>> +}
>> +
>> +static int ps8640_remove(struct i2c_client *client)
>> +{
>> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
>> +
>> +       drm_bridge_remove(&ps_bridge->bridge);
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct of_device_id ps8640_match[] = {
>> +       { .compatible = "parade,ps8640" },
>> +       { }
>> +};
>> +MODULE_DEVICE_TABLE(of, ps8640_match);
>> +
>> +static struct i2c_driver ps8640_driver = {
>> +       .probe_new = ps8640_probe,
>> +       .remove = ps8640_remove,
>> +       .driver = {
>> +               .name = "ps8640",
>> +               .of_match_table = ps8640_match,
>> +       },
>> +};
>> +module_i2c_driver(ps8640_driver);
>> +
>> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
>> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
> 
> Since you just did a major refactor, do you want to add your name here?
> 

Sure.

Thanks,
 Enric

>> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.20.1
>>
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23  7:09       ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23  7:09 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml, Andrzej Hajda,
	moderated list:ARM/Mediatek SoC support, dri-devel,
	Daniel Vetter, Hsin-Yi Wang, Matthias Brugger,
	Collabora Kernel ML, linux-arm Mailing List, Laurent Pinchart

Hi Nicolas,

Many thanks for you review. Just preparing a new version with your comments
addressed.

On 20/12/19 9:44, Nicolas Boichat wrote:
> On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>>
>> From: Jitao Shi <jitao.shi@mediatek.com>
>>
>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>
>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> [uli: followed API changes, removed FW update feature]
>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> ---
>> [snip]
>>
>>  drivers/gpu/drm/bridge/Kconfig         |  11 +
>>  drivers/gpu/drm/bridge/Makefile        |   1 +
>>  drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++
> 
> Half the size! Sounds great.
> 
> Mostly nits below.
> 
>>  3 files changed, 366 insertions(+)
>>  create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>>
>> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
>> new file mode 100644
>> index 000000000000..aa0045037f44
>> --- /dev/null
>> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
>> @@ -0,0 +1,354 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2016 MediaTek Inc.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/of_graph.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_mipi_dsi.h>
>> +#include <drm/drm_of.h>
>> +#include <drm/drm_panel.h>
>> +#include <drm/drm_print.h>
>> +
>> +#define PAGE2_GPIO_H           0xa7
>> +#define PS_GPIO9               BIT(1)
>> +#define PAGE2_I2C_BYPASS       0xea
>> +#define I2C_BYPASS_EN          0xd0
>> +#define PAGE2_MCS_EN           0xf3
>> +#define MCS_EN                 BIT(0)
>> +#define PAGE3_SET_ADD          0xfe
>> +#define VDO_CTL_ADD            0x13
>> +#define VDO_DIS                        0x18
>> +#define VDO_EN                 0x1c
>> +
>> +/*
>> + * PS8640 uses multiple addresses:
>> + * page[0]: for DP control
>> + * page[1]: for VIDEO Bridge
>> + * page[2]: for control top
>> + * page[3]: for DSI Link Control1
>> + * page[4]: for MIPI Phy
>> + * page[5]: for VPLL
>> + * page[6]: for DSI Link Control2
>> + * page[7]: for SPI ROM mapping
>> + */
>> +enum page_addr_offset {
>> +       PAGE0_DP_CNTL = 0,
>> +       PAGE1_VDO_BDG,
>> +       PAGE2_TOP_CNTL,
>> +       PAGE3_DSI_CNTL1,
>> +       PAGE4_MIPI_PHY,
>> +       PAGE5_VPLL,
>> +       PAGE6_DSI_CNTL2,
>> +       PAGE7_SPI_CNTL,
>> +       MAX_DEVS
>> +};
>> +
>> +struct ps8640 {
>> +       struct drm_bridge bridge;
>> +       struct drm_bridge *panel_bridge;
>> +       struct mipi_dsi_device *dsi;
>> +       struct i2c_client *page[MAX_DEVS];
>> +       struct regulator_bulk_data supplies[2];
>> +       struct gpio_desc *gpio_reset;
>> +       struct gpio_desc *gpio_powerdown;
>> +};
>> +
>> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
>> +{
>> +       return container_of(e, struct ps8640, bridge);
>> +}
>> +
>> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
>> +{
>> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
>> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };
> 
> nit: const?
> 
>> +       int ret;
>> +
>> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
>> +                                            sizeof(vdo_ctrl_buf),
>> +                                            vdo_ctrl_buf);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return 0;
>> +}
>> +
>> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
>> +{
>> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
>> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };
> 
> ditto
> 
>> +       int ret;
>> +
>> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
>> +                                            sizeof(vdo_ctrl_buf),
>> +                                            vdo_ctrl_buf);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return 0;
>> +}
> 
> Since the 2 functions are almost the same, you could shrink the driver
> a bit further by merging them into one with a boolean parameter? (then
> maybe give up on the const u8 comment).
> 

I decided to merge the two functions and use and enum instead of a boolean
parameter, so the "bool" value is more understandable.

>> +
>> +static void ps8640_pre_enable(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
>> +       unsigned long timeout;
>> +       int ret, status;
>> +
>> +       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
>> +                                   ps_bridge->supplies);
>> +       if (ret < 0) {
>> +               DRM_ERROR("cannot enable regulators %d\n", ret);
>> +               return;
>> +       }
>> +
>> +       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
>> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
>> +       usleep_range(2000, 2500);
>> +       gpiod_set_value(ps_bridge->gpio_reset, 1);
>> +
>> +       /*
>> +        * Wait for the ps8640 embedded MCU to be ready
>> +        * First wait 200ms and then check the MCU ready flag every 20ms
>> +        */
>> +       msleep(200);
>> +
>> +       timeout = jiffies + msecs_to_jiffies(200) + 1;
>> +
>> +       while (time_is_after_jiffies(timeout)) {
>> +               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
>> +               if (status < 0) {
>> +                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
>> +                       goto err_regulators_disable;
>> +               }
>> +               if ((status & PS_GPIO9) == PS_GPIO9)
>> +                       break;
>> +
>> +               msleep(20);
>> +       }
>> +
>> +       msleep(50);
>> +
>> +       /*
>> +        * The Manufacturer Command Set (MCS) is a device dependent interface
>> +        * intended for factory programming of the display module default
>> +        * parameters. Once the display module is configured, the MCS shall be
>> +        * disabled by the manufacturer. Once disabled, all MCS commands are
>> +        * ignored by the display interface.
>> +        */
>> +       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
>> +       if (status < 0) {
>> +               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
>> +                                       status & ~MCS_EN);
>> +       if (ret < 0) {
>> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       ret = ps8640_bridge_unmute(ps_bridge);
>> +       if (ret)
>> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
> 
> failed to unmute? Or failed to enable?
> 

failed to unmute sound more clear to me.

>> +
>> +       /* Switch access edp panel's edid through i2c */
>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
>> +                                       I2C_BYPASS_EN);
>> +       if (ret < 0) {
>> +               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       return;
>> +
>> +err_regulators_disable:
>> +       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> +                              ps_bridge->supplies);
>> +}
>> +
>> +static void ps8640_post_disable(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       int ret;
>> +
>> +       ret = ps8640_bridge_mute(ps_bridge);
>> +       if (ret < 0)
>> +               DRM_ERROR("failed to unmutevideo: %d\n", ret);
> 
> ditto
> 

Done.

>> +
>> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
>> +       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
>> +       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> +                                    ps_bridge->supplies);
>> +       if (ret < 0)
>> +               DRM_ERROR("cannot disable regulators %d\n", ret);
>> +}
>> +
>> +int ps8640_bridge_attach(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       struct device *dev = &ps_bridge->page[0]->dev;
>> +       struct device_node *in_ep, *dsi_node;
>> +       struct mipi_dsi_device *dsi;
>> +       struct mipi_dsi_host *host;
>> +       int ret;
>> +       const struct mipi_dsi_device_info info = { .type = "ps8640",
>> +                                                  .channel = 0,
>> +                                                  .node = NULL,
>> +                                                };
>> +       /* port@0 is ps8640 dsi input port */
>> +       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
>> +       if (!in_ep)
>> +               return -ENODEV;
>> +
>> +       dsi_node = of_graph_get_remote_port_parent(in_ep);
>> +       of_node_put(in_ep);
>> +       if (!dsi_node)
>> +               return -ENODEV;
>> +
>> +       host = of_find_mipi_dsi_host_by_node(dsi_node);
>> +       of_node_put(dsi_node);
>> +       if (!host)
>> +               return -ENODEV;
>> +
>> +       dsi = mipi_dsi_device_register_full(host, &info);
>> +       if (IS_ERR(dsi)) {
>> +               dev_err(dev, "failed to create dsi device\n");
>> +               ret = PTR_ERR(dsi);
>> +               return ret;
>> +       }
>> +
>> +       ps_bridge->dsi = dsi;
>> +
>> +       dsi->host = host;
>> +       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
>> +                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> +       dsi->format = MIPI_DSI_FMT_RGB888;
>> +       dsi->lanes = 4;
>> +       ret = mipi_dsi_attach(dsi);
>> +       if (ret)
>> +               goto err_dsi_attach;
>> +
>> +       /* Attach the panel-bridge to the dsi bridge */
>> +       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
>> +                                &ps_bridge->bridge);
>> +
>> +err_dsi_attach:
>> +       mipi_dsi_device_unregister(dsi);
>> +       return ret;
>> +}
>> +
>> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
>> +       .attach = ps8640_bridge_attach,
>> +       .post_disable = ps8640_post_disable,
>> +       .pre_enable = ps8640_pre_enable,
>> +};
>> +
>> +static int ps8640_probe(struct i2c_client *client)
>> +{
>> +       struct device *dev = &client->dev;
>> +       struct device_node *np = dev->of_node;
>> +       struct ps8640 *ps_bridge;
>> +       struct drm_panel *panel;
>> +       int ret;
>> +       u32 i;
>> +
>> +       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
>> +       if (!ps_bridge)
>> +               return -ENOMEM;
>> +
>> +       /* port@1 is ps8640 output port */
>> +       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
>> +       if (ret < 0)
>> +               return ret;
>> +       if (!panel)
>> +               return -ENODEV;
>> +
>> +       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
>> +
>> +       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
>> +       if (IS_ERR(ps_bridge->panel_bridge))
>> +               return PTR_ERR(ps_bridge->panel_bridge);
>> +
>> +       ps_bridge->supplies[0].supply = "vdd33";
>> +       ps_bridge->supplies[1].supply = "vdd12";
>> +       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
>> +                                     ps_bridge->supplies);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
>> +                                                  GPIOD_OUT_LOW);
>> +       if (IS_ERR(ps_bridge->gpio_powerdown))
>> +               return PTR_ERR(ps_bridge->gpio_powerdown);
>> +
>> +       /*
>> +        * Request the reset pin low to avoid the bridge being
>> +        * initialized prematurely
>> +        */
>> +       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
>> +                                              GPIOD_OUT_LOW);
>> +       if (IS_ERR(ps_bridge->gpio_reset))
>> +               return PTR_ERR(ps_bridge->gpio_reset);
>> +
>> +       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
>> +       ps_bridge->bridge.of_node = dev->of_node;
>> +
>> +       ps_bridge->page[PAGE0_DP_CNTL] = client;
>> +
>> +       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
>> +               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
>> +                                                            client->adapter,
>> +                                                            client->addr + i);
>> +               if (IS_ERR(ps_bridge->page[i])) {
>> +                       dev_err(dev, "failed i2c dummy device, address%02x\n",
> 
> Space after address?
> 

Ack and done.

>> +                               client->addr + i);
>> +                       return PTR_ERR(ps_bridge->page[i]);
>> +               }
>> +       }
>> +
>> +       i2c_set_clientdata(client, ps_bridge);
>> +
>> +       drm_bridge_add(&ps_bridge->bridge);
>> +
>> +       return 0;
>> +}
>> +
>> +static int ps8640_remove(struct i2c_client *client)
>> +{
>> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
>> +
>> +       drm_bridge_remove(&ps_bridge->bridge);
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct of_device_id ps8640_match[] = {
>> +       { .compatible = "parade,ps8640" },
>> +       { }
>> +};
>> +MODULE_DEVICE_TABLE(of, ps8640_match);
>> +
>> +static struct i2c_driver ps8640_driver = {
>> +       .probe_new = ps8640_probe,
>> +       .remove = ps8640_remove,
>> +       .driver = {
>> +               .name = "ps8640",
>> +               .of_match_table = ps8640_match,
>> +       },
>> +};
>> +module_i2c_driver(ps8640_driver);
>> +
>> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
>> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
> 
> Since you just did a major refactor, do you want to add your name here?
> 

Sure.

Thanks,
 Enric

>> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.20.1
>>
> 

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23  7:09       ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23  7:09 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml, Daniel Kurtz, Andrzej Hajda,
	moderated list:ARM/Mediatek SoC support, dri-devel,
	Daniel Vetter, Hsin-Yi Wang, Matthias Brugger,
	Collabora Kernel ML, linux-arm Mailing List, Laurent Pinchart

Hi Nicolas,

Many thanks for you review. Just preparing a new version with your comments
addressed.

On 20/12/19 9:44, Nicolas Boichat wrote:
> On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>>
>> From: Jitao Shi <jitao.shi@mediatek.com>
>>
>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>
>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> [uli: followed API changes, removed FW update feature]
>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> ---
>> [snip]
>>
>>  drivers/gpu/drm/bridge/Kconfig         |  11 +
>>  drivers/gpu/drm/bridge/Makefile        |   1 +
>>  drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++
> 
> Half the size! Sounds great.
> 
> Mostly nits below.
> 
>>  3 files changed, 366 insertions(+)
>>  create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>>
>> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
>> new file mode 100644
>> index 000000000000..aa0045037f44
>> --- /dev/null
>> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
>> @@ -0,0 +1,354 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2016 MediaTek Inc.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/of_graph.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_mipi_dsi.h>
>> +#include <drm/drm_of.h>
>> +#include <drm/drm_panel.h>
>> +#include <drm/drm_print.h>
>> +
>> +#define PAGE2_GPIO_H           0xa7
>> +#define PS_GPIO9               BIT(1)
>> +#define PAGE2_I2C_BYPASS       0xea
>> +#define I2C_BYPASS_EN          0xd0
>> +#define PAGE2_MCS_EN           0xf3
>> +#define MCS_EN                 BIT(0)
>> +#define PAGE3_SET_ADD          0xfe
>> +#define VDO_CTL_ADD            0x13
>> +#define VDO_DIS                        0x18
>> +#define VDO_EN                 0x1c
>> +
>> +/*
>> + * PS8640 uses multiple addresses:
>> + * page[0]: for DP control
>> + * page[1]: for VIDEO Bridge
>> + * page[2]: for control top
>> + * page[3]: for DSI Link Control1
>> + * page[4]: for MIPI Phy
>> + * page[5]: for VPLL
>> + * page[6]: for DSI Link Control2
>> + * page[7]: for SPI ROM mapping
>> + */
>> +enum page_addr_offset {
>> +       PAGE0_DP_CNTL = 0,
>> +       PAGE1_VDO_BDG,
>> +       PAGE2_TOP_CNTL,
>> +       PAGE3_DSI_CNTL1,
>> +       PAGE4_MIPI_PHY,
>> +       PAGE5_VPLL,
>> +       PAGE6_DSI_CNTL2,
>> +       PAGE7_SPI_CNTL,
>> +       MAX_DEVS
>> +};
>> +
>> +struct ps8640 {
>> +       struct drm_bridge bridge;
>> +       struct drm_bridge *panel_bridge;
>> +       struct mipi_dsi_device *dsi;
>> +       struct i2c_client *page[MAX_DEVS];
>> +       struct regulator_bulk_data supplies[2];
>> +       struct gpio_desc *gpio_reset;
>> +       struct gpio_desc *gpio_powerdown;
>> +};
>> +
>> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
>> +{
>> +       return container_of(e, struct ps8640, bridge);
>> +}
>> +
>> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
>> +{
>> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
>> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };
> 
> nit: const?
> 
>> +       int ret;
>> +
>> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
>> +                                            sizeof(vdo_ctrl_buf),
>> +                                            vdo_ctrl_buf);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return 0;
>> +}
>> +
>> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
>> +{
>> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
>> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };
> 
> ditto
> 
>> +       int ret;
>> +
>> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
>> +                                            sizeof(vdo_ctrl_buf),
>> +                                            vdo_ctrl_buf);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return 0;
>> +}
> 
> Since the 2 functions are almost the same, you could shrink the driver
> a bit further by merging them into one with a boolean parameter? (then
> maybe give up on the const u8 comment).
> 

I decided to merge the two functions and use and enum instead of a boolean
parameter, so the "bool" value is more understandable.

>> +
>> +static void ps8640_pre_enable(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
>> +       unsigned long timeout;
>> +       int ret, status;
>> +
>> +       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
>> +                                   ps_bridge->supplies);
>> +       if (ret < 0) {
>> +               DRM_ERROR("cannot enable regulators %d\n", ret);
>> +               return;
>> +       }
>> +
>> +       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
>> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
>> +       usleep_range(2000, 2500);
>> +       gpiod_set_value(ps_bridge->gpio_reset, 1);
>> +
>> +       /*
>> +        * Wait for the ps8640 embedded MCU to be ready
>> +        * First wait 200ms and then check the MCU ready flag every 20ms
>> +        */
>> +       msleep(200);
>> +
>> +       timeout = jiffies + msecs_to_jiffies(200) + 1;
>> +
>> +       while (time_is_after_jiffies(timeout)) {
>> +               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
>> +               if (status < 0) {
>> +                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
>> +                       goto err_regulators_disable;
>> +               }
>> +               if ((status & PS_GPIO9) == PS_GPIO9)
>> +                       break;
>> +
>> +               msleep(20);
>> +       }
>> +
>> +       msleep(50);
>> +
>> +       /*
>> +        * The Manufacturer Command Set (MCS) is a device dependent interface
>> +        * intended for factory programming of the display module default
>> +        * parameters. Once the display module is configured, the MCS shall be
>> +        * disabled by the manufacturer. Once disabled, all MCS commands are
>> +        * ignored by the display interface.
>> +        */
>> +       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
>> +       if (status < 0) {
>> +               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
>> +                                       status & ~MCS_EN);
>> +       if (ret < 0) {
>> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       ret = ps8640_bridge_unmute(ps_bridge);
>> +       if (ret)
>> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
> 
> failed to unmute? Or failed to enable?
> 

failed to unmute sound more clear to me.

>> +
>> +       /* Switch access edp panel's edid through i2c */
>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
>> +                                       I2C_BYPASS_EN);
>> +       if (ret < 0) {
>> +               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       return;
>> +
>> +err_regulators_disable:
>> +       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> +                              ps_bridge->supplies);
>> +}
>> +
>> +static void ps8640_post_disable(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       int ret;
>> +
>> +       ret = ps8640_bridge_mute(ps_bridge);
>> +       if (ret < 0)
>> +               DRM_ERROR("failed to unmutevideo: %d\n", ret);
> 
> ditto
> 

Done.

>> +
>> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
>> +       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
>> +       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> +                                    ps_bridge->supplies);
>> +       if (ret < 0)
>> +               DRM_ERROR("cannot disable regulators %d\n", ret);
>> +}
>> +
>> +int ps8640_bridge_attach(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       struct device *dev = &ps_bridge->page[0]->dev;
>> +       struct device_node *in_ep, *dsi_node;
>> +       struct mipi_dsi_device *dsi;
>> +       struct mipi_dsi_host *host;
>> +       int ret;
>> +       const struct mipi_dsi_device_info info = { .type = "ps8640",
>> +                                                  .channel = 0,
>> +                                                  .node = NULL,
>> +                                                };
>> +       /* port@0 is ps8640 dsi input port */
>> +       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
>> +       if (!in_ep)
>> +               return -ENODEV;
>> +
>> +       dsi_node = of_graph_get_remote_port_parent(in_ep);
>> +       of_node_put(in_ep);
>> +       if (!dsi_node)
>> +               return -ENODEV;
>> +
>> +       host = of_find_mipi_dsi_host_by_node(dsi_node);
>> +       of_node_put(dsi_node);
>> +       if (!host)
>> +               return -ENODEV;
>> +
>> +       dsi = mipi_dsi_device_register_full(host, &info);
>> +       if (IS_ERR(dsi)) {
>> +               dev_err(dev, "failed to create dsi device\n");
>> +               ret = PTR_ERR(dsi);
>> +               return ret;
>> +       }
>> +
>> +       ps_bridge->dsi = dsi;
>> +
>> +       dsi->host = host;
>> +       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
>> +                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> +       dsi->format = MIPI_DSI_FMT_RGB888;
>> +       dsi->lanes = 4;
>> +       ret = mipi_dsi_attach(dsi);
>> +       if (ret)
>> +               goto err_dsi_attach;
>> +
>> +       /* Attach the panel-bridge to the dsi bridge */
>> +       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
>> +                                &ps_bridge->bridge);
>> +
>> +err_dsi_attach:
>> +       mipi_dsi_device_unregister(dsi);
>> +       return ret;
>> +}
>> +
>> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
>> +       .attach = ps8640_bridge_attach,
>> +       .post_disable = ps8640_post_disable,
>> +       .pre_enable = ps8640_pre_enable,
>> +};
>> +
>> +static int ps8640_probe(struct i2c_client *client)
>> +{
>> +       struct device *dev = &client->dev;
>> +       struct device_node *np = dev->of_node;
>> +       struct ps8640 *ps_bridge;
>> +       struct drm_panel *panel;
>> +       int ret;
>> +       u32 i;
>> +
>> +       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
>> +       if (!ps_bridge)
>> +               return -ENOMEM;
>> +
>> +       /* port@1 is ps8640 output port */
>> +       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
>> +       if (ret < 0)
>> +               return ret;
>> +       if (!panel)
>> +               return -ENODEV;
>> +
>> +       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
>> +
>> +       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
>> +       if (IS_ERR(ps_bridge->panel_bridge))
>> +               return PTR_ERR(ps_bridge->panel_bridge);
>> +
>> +       ps_bridge->supplies[0].supply = "vdd33";
>> +       ps_bridge->supplies[1].supply = "vdd12";
>> +       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
>> +                                     ps_bridge->supplies);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
>> +                                                  GPIOD_OUT_LOW);
>> +       if (IS_ERR(ps_bridge->gpio_powerdown))
>> +               return PTR_ERR(ps_bridge->gpio_powerdown);
>> +
>> +       /*
>> +        * Request the reset pin low to avoid the bridge being
>> +        * initialized prematurely
>> +        */
>> +       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
>> +                                              GPIOD_OUT_LOW);
>> +       if (IS_ERR(ps_bridge->gpio_reset))
>> +               return PTR_ERR(ps_bridge->gpio_reset);
>> +
>> +       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
>> +       ps_bridge->bridge.of_node = dev->of_node;
>> +
>> +       ps_bridge->page[PAGE0_DP_CNTL] = client;
>> +
>> +       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
>> +               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
>> +                                                            client->adapter,
>> +                                                            client->addr + i);
>> +               if (IS_ERR(ps_bridge->page[i])) {
>> +                       dev_err(dev, "failed i2c dummy device, address%02x\n",
> 
> Space after address?
> 

Ack and done.

>> +                               client->addr + i);
>> +                       return PTR_ERR(ps_bridge->page[i]);
>> +               }
>> +       }
>> +
>> +       i2c_set_clientdata(client, ps_bridge);
>> +
>> +       drm_bridge_add(&ps_bridge->bridge);
>> +
>> +       return 0;
>> +}
>> +
>> +static int ps8640_remove(struct i2c_client *client)
>> +{
>> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
>> +
>> +       drm_bridge_remove(&ps_bridge->bridge);
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct of_device_id ps8640_match[] = {
>> +       { .compatible = "parade,ps8640" },
>> +       { }
>> +};
>> +MODULE_DEVICE_TABLE(of, ps8640_match);
>> +
>> +static struct i2c_driver ps8640_driver = {
>> +       .probe_new = ps8640_probe,
>> +       .remove = ps8640_remove,
>> +       .driver = {
>> +               .name = "ps8640",
>> +               .of_match_table = ps8640_match,
>> +       },
>> +};
>> +module_i2c_driver(ps8640_driver);
>> +
>> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
>> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
> 
> Since you just did a major refactor, do you want to add your name here?
> 

Sure.

Thanks,
 Enric

>> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.20.1
>>
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23  7:09       ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23  7:09 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml,
	moderated list:ARM/Mediatek SoC support, dri-devel, Hsin-Yi Wang,
	Matthias Brugger, Collabora Kernel ML, linux-arm Mailing List,
	Laurent Pinchart

Hi Nicolas,

Many thanks for you review. Just preparing a new version with your comments
addressed.

On 20/12/19 9:44, Nicolas Boichat wrote:
> On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>>
>> From: Jitao Shi <jitao.shi@mediatek.com>
>>
>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>
>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> [uli: followed API changes, removed FW update feature]
>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> ---
>> [snip]
>>
>>  drivers/gpu/drm/bridge/Kconfig         |  11 +
>>  drivers/gpu/drm/bridge/Makefile        |   1 +
>>  drivers/gpu/drm/bridge/parade-ps8640.c | 354 +++++++++++++++++++++++++
> 
> Half the size! Sounds great.
> 
> Mostly nits below.
> 
>>  3 files changed, 366 insertions(+)
>>  create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>>
>> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
>> new file mode 100644
>> index 000000000000..aa0045037f44
>> --- /dev/null
>> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
>> @@ -0,0 +1,354 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2016 MediaTek Inc.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/of_graph.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_mipi_dsi.h>
>> +#include <drm/drm_of.h>
>> +#include <drm/drm_panel.h>
>> +#include <drm/drm_print.h>
>> +
>> +#define PAGE2_GPIO_H           0xa7
>> +#define PS_GPIO9               BIT(1)
>> +#define PAGE2_I2C_BYPASS       0xea
>> +#define I2C_BYPASS_EN          0xd0
>> +#define PAGE2_MCS_EN           0xf3
>> +#define MCS_EN                 BIT(0)
>> +#define PAGE3_SET_ADD          0xfe
>> +#define VDO_CTL_ADD            0x13
>> +#define VDO_DIS                        0x18
>> +#define VDO_EN                 0x1c
>> +
>> +/*
>> + * PS8640 uses multiple addresses:
>> + * page[0]: for DP control
>> + * page[1]: for VIDEO Bridge
>> + * page[2]: for control top
>> + * page[3]: for DSI Link Control1
>> + * page[4]: for MIPI Phy
>> + * page[5]: for VPLL
>> + * page[6]: for DSI Link Control2
>> + * page[7]: for SPI ROM mapping
>> + */
>> +enum page_addr_offset {
>> +       PAGE0_DP_CNTL = 0,
>> +       PAGE1_VDO_BDG,
>> +       PAGE2_TOP_CNTL,
>> +       PAGE3_DSI_CNTL1,
>> +       PAGE4_MIPI_PHY,
>> +       PAGE5_VPLL,
>> +       PAGE6_DSI_CNTL2,
>> +       PAGE7_SPI_CNTL,
>> +       MAX_DEVS
>> +};
>> +
>> +struct ps8640 {
>> +       struct drm_bridge bridge;
>> +       struct drm_bridge *panel_bridge;
>> +       struct mipi_dsi_device *dsi;
>> +       struct i2c_client *page[MAX_DEVS];
>> +       struct regulator_bulk_data supplies[2];
>> +       struct gpio_desc *gpio_reset;
>> +       struct gpio_desc *gpio_powerdown;
>> +};
>> +
>> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
>> +{
>> +       return container_of(e, struct ps8640, bridge);
>> +}
>> +
>> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
>> +{
>> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
>> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_EN };
> 
> nit: const?
> 
>> +       int ret;
>> +
>> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
>> +                                            sizeof(vdo_ctrl_buf),
>> +                                            vdo_ctrl_buf);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return 0;
>> +}
>> +
>> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
>> +{
>> +       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
>> +       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, VDO_DIS };
> 
> ditto
> 
>> +       int ret;
>> +
>> +       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
>> +                                            sizeof(vdo_ctrl_buf),
>> +                                            vdo_ctrl_buf);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       return 0;
>> +}
> 
> Since the 2 functions are almost the same, you could shrink the driver
> a bit further by merging them into one with a boolean parameter? (then
> maybe give up on the const u8 comment).
> 

I decided to merge the two functions and use and enum instead of a boolean
parameter, so the "bool" value is more understandable.

>> +
>> +static void ps8640_pre_enable(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
>> +       unsigned long timeout;
>> +       int ret, status;
>> +
>> +       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
>> +                                   ps_bridge->supplies);
>> +       if (ret < 0) {
>> +               DRM_ERROR("cannot enable regulators %d\n", ret);
>> +               return;
>> +       }
>> +
>> +       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
>> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
>> +       usleep_range(2000, 2500);
>> +       gpiod_set_value(ps_bridge->gpio_reset, 1);
>> +
>> +       /*
>> +        * Wait for the ps8640 embedded MCU to be ready
>> +        * First wait 200ms and then check the MCU ready flag every 20ms
>> +        */
>> +       msleep(200);
>> +
>> +       timeout = jiffies + msecs_to_jiffies(200) + 1;
>> +
>> +       while (time_is_after_jiffies(timeout)) {
>> +               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
>> +               if (status < 0) {
>> +                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
>> +                       goto err_regulators_disable;
>> +               }
>> +               if ((status & PS_GPIO9) == PS_GPIO9)
>> +                       break;
>> +
>> +               msleep(20);
>> +       }
>> +
>> +       msleep(50);
>> +
>> +       /*
>> +        * The Manufacturer Command Set (MCS) is a device dependent interface
>> +        * intended for factory programming of the display module default
>> +        * parameters. Once the display module is configured, the MCS shall be
>> +        * disabled by the manufacturer. Once disabled, all MCS commands are
>> +        * ignored by the display interface.
>> +        */
>> +       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
>> +       if (status < 0) {
>> +               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
>> +                                       status & ~MCS_EN);
>> +       if (ret < 0) {
>> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       ret = ps8640_bridge_unmute(ps_bridge);
>> +       if (ret)
>> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
> 
> failed to unmute? Or failed to enable?
> 

failed to unmute sound more clear to me.

>> +
>> +       /* Switch access edp panel's edid through i2c */
>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
>> +                                       I2C_BYPASS_EN);
>> +       if (ret < 0) {
>> +               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
>> +               goto err_regulators_disable;
>> +       }
>> +
>> +       return;
>> +
>> +err_regulators_disable:
>> +       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> +                              ps_bridge->supplies);
>> +}
>> +
>> +static void ps8640_post_disable(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       int ret;
>> +
>> +       ret = ps8640_bridge_mute(ps_bridge);
>> +       if (ret < 0)
>> +               DRM_ERROR("failed to unmutevideo: %d\n", ret);
> 
> ditto
> 

Done.

>> +
>> +       gpiod_set_value(ps_bridge->gpio_reset, 0);
>> +       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
>> +       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> +                                    ps_bridge->supplies);
>> +       if (ret < 0)
>> +               DRM_ERROR("cannot disable regulators %d\n", ret);
>> +}
>> +
>> +int ps8640_bridge_attach(struct drm_bridge *bridge)
>> +{
>> +       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> +       struct device *dev = &ps_bridge->page[0]->dev;
>> +       struct device_node *in_ep, *dsi_node;
>> +       struct mipi_dsi_device *dsi;
>> +       struct mipi_dsi_host *host;
>> +       int ret;
>> +       const struct mipi_dsi_device_info info = { .type = "ps8640",
>> +                                                  .channel = 0,
>> +                                                  .node = NULL,
>> +                                                };
>> +       /* port@0 is ps8640 dsi input port */
>> +       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
>> +       if (!in_ep)
>> +               return -ENODEV;
>> +
>> +       dsi_node = of_graph_get_remote_port_parent(in_ep);
>> +       of_node_put(in_ep);
>> +       if (!dsi_node)
>> +               return -ENODEV;
>> +
>> +       host = of_find_mipi_dsi_host_by_node(dsi_node);
>> +       of_node_put(dsi_node);
>> +       if (!host)
>> +               return -ENODEV;
>> +
>> +       dsi = mipi_dsi_device_register_full(host, &info);
>> +       if (IS_ERR(dsi)) {
>> +               dev_err(dev, "failed to create dsi device\n");
>> +               ret = PTR_ERR(dsi);
>> +               return ret;
>> +       }
>> +
>> +       ps_bridge->dsi = dsi;
>> +
>> +       dsi->host = host;
>> +       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
>> +                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> +       dsi->format = MIPI_DSI_FMT_RGB888;
>> +       dsi->lanes = 4;
>> +       ret = mipi_dsi_attach(dsi);
>> +       if (ret)
>> +               goto err_dsi_attach;
>> +
>> +       /* Attach the panel-bridge to the dsi bridge */
>> +       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
>> +                                &ps_bridge->bridge);
>> +
>> +err_dsi_attach:
>> +       mipi_dsi_device_unregister(dsi);
>> +       return ret;
>> +}
>> +
>> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
>> +       .attach = ps8640_bridge_attach,
>> +       .post_disable = ps8640_post_disable,
>> +       .pre_enable = ps8640_pre_enable,
>> +};
>> +
>> +static int ps8640_probe(struct i2c_client *client)
>> +{
>> +       struct device *dev = &client->dev;
>> +       struct device_node *np = dev->of_node;
>> +       struct ps8640 *ps_bridge;
>> +       struct drm_panel *panel;
>> +       int ret;
>> +       u32 i;
>> +
>> +       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
>> +       if (!ps_bridge)
>> +               return -ENOMEM;
>> +
>> +       /* port@1 is ps8640 output port */
>> +       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
>> +       if (ret < 0)
>> +               return ret;
>> +       if (!panel)
>> +               return -ENODEV;
>> +
>> +       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
>> +
>> +       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
>> +       if (IS_ERR(ps_bridge->panel_bridge))
>> +               return PTR_ERR(ps_bridge->panel_bridge);
>> +
>> +       ps_bridge->supplies[0].supply = "vdd33";
>> +       ps_bridge->supplies[1].supply = "vdd12";
>> +       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
>> +                                     ps_bridge->supplies);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
>> +                                                  GPIOD_OUT_LOW);
>> +       if (IS_ERR(ps_bridge->gpio_powerdown))
>> +               return PTR_ERR(ps_bridge->gpio_powerdown);
>> +
>> +       /*
>> +        * Request the reset pin low to avoid the bridge being
>> +        * initialized prematurely
>> +        */
>> +       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
>> +                                              GPIOD_OUT_LOW);
>> +       if (IS_ERR(ps_bridge->gpio_reset))
>> +               return PTR_ERR(ps_bridge->gpio_reset);
>> +
>> +       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
>> +       ps_bridge->bridge.of_node = dev->of_node;
>> +
>> +       ps_bridge->page[PAGE0_DP_CNTL] = client;
>> +
>> +       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
>> +               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
>> +                                                            client->adapter,
>> +                                                            client->addr + i);
>> +               if (IS_ERR(ps_bridge->page[i])) {
>> +                       dev_err(dev, "failed i2c dummy device, address%02x\n",
> 
> Space after address?
> 

Ack and done.

>> +                               client->addr + i);
>> +                       return PTR_ERR(ps_bridge->page[i]);
>> +               }
>> +       }
>> +
>> +       i2c_set_clientdata(client, ps_bridge);
>> +
>> +       drm_bridge_add(&ps_bridge->bridge);
>> +
>> +       return 0;
>> +}
>> +
>> +static int ps8640_remove(struct i2c_client *client)
>> +{
>> +       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
>> +
>> +       drm_bridge_remove(&ps_bridge->bridge);
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct of_device_id ps8640_match[] = {
>> +       { .compatible = "parade,ps8640" },
>> +       { }
>> +};
>> +MODULE_DEVICE_TABLE(of, ps8640_match);
>> +
>> +static struct i2c_driver ps8640_driver = {
>> +       .probe_new = ps8640_probe,
>> +       .remove = ps8640_remove,
>> +       .driver = {
>> +               .name = "ps8640",
>> +               .of_match_table = ps8640_match,
>> +       },
>> +};
>> +module_i2c_driver(ps8640_driver);
>> +
>> +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
>> +MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
> 
> Since you just did a major refactor, do you want to add your name here?
> 

Sure.

Thanks,
 Enric

>> +MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.20.1
>>
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
  2019-12-23  7:09       ` Enric Balletbo i Serra
  (?)
  (?)
@ 2019-12-23  9:14         ` Nicolas Boichat
  -1 siblings, 0 replies; 44+ messages in thread
From: Nicolas Boichat @ 2019-12-23  9:14 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: lkml, Collabora Kernel ML, Matthias Brugger, Hsin-Yi Wang,
	Jitao Shi, Daniel Kurtz, Ulrich Hecht, linux-arm Mailing List,
	Andrzej Hajda, Jonas Karlman, dri-devel, Neil Armstrong,
	moderated list:ARM/Mediatek SoC support, David Airlie,
	Jernej Skrabec, Laurent Pinchart, Daniel Vetter

On Mon, Dec 23, 2019 at 3:10 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> Hi Nicolas,
>
> Many thanks for you review. Just preparing a new version with your comments
> addressed.
>
> On 20/12/19 9:44, Nicolas Boichat wrote:
> > On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
> > <enric.balletbo@collabora.com> wrote:
> >>
> >> From: Jitao Shi <jitao.shi@mediatek.com>
> >>
> >> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
> >>
> >> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> >> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> >> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> [uli: followed API changes, removed FW update feature]
> >> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> ---
> [snip]
> >> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
> >> +                                       status & ~MCS_EN);
> >> +       if (ret < 0) {
> >> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
> >> +               goto err_regulators_disable;
> >> +       }
> >> +
> >> +       ret = ps8640_bridge_unmute(ps_bridge);
> >> +       if (ret)
> >> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
> >
> > failed to unmute? Or failed to enable?
> >
>
> failed to unmute sound more clear to me.

I may be wrong, but I have the feeling that the functions
"mute/unmute" video/display, actually... And that the function naming
is strange...

You could just try to remove the calls, as there is no audio on the
board you have (elm), so if video still works, maybe this is actually
audio ,-)

Thanks,

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23  9:14         ` Nicolas Boichat
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Boichat @ 2019-12-23  9:14 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml, Andrzej Hajda,
	moderated list:ARM/Mediatek SoC support, dri-devel,
	Daniel Vetter, Hsin-Yi Wang, Matthias Brugger,
	Collabora Kernel ML, linux-arm Mailing List, Laurent Pinchart

On Mon, Dec 23, 2019 at 3:10 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> Hi Nicolas,
>
> Many thanks for you review. Just preparing a new version with your comments
> addressed.
>
> On 20/12/19 9:44, Nicolas Boichat wrote:
> > On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
> > <enric.balletbo@collabora.com> wrote:
> >>
> >> From: Jitao Shi <jitao.shi@mediatek.com>
> >>
> >> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
> >>
> >> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> >> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> >> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> [uli: followed API changes, removed FW update feature]
> >> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> ---
> [snip]
> >> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
> >> +                                       status & ~MCS_EN);
> >> +       if (ret < 0) {
> >> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
> >> +               goto err_regulators_disable;
> >> +       }
> >> +
> >> +       ret = ps8640_bridge_unmute(ps_bridge);
> >> +       if (ret)
> >> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
> >
> > failed to unmute? Or failed to enable?
> >
>
> failed to unmute sound more clear to me.

I may be wrong, but I have the feeling that the functions
"mute/unmute" video/display, actually... And that the function naming
is strange...

You could just try to remove the calls, as there is no audio on the
board you have (elm), so if video still works, maybe this is actually
audio ,-)

Thanks,

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23  9:14         ` Nicolas Boichat
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Boichat @ 2019-12-23  9:14 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml, Daniel Kurtz, Andrzej Hajda,
	moderated list:ARM/Mediatek SoC support, dri-devel,
	Daniel Vetter, Hsin-Yi Wang, Matthias Brugger,
	Collabora Kernel ML, linux-arm Mailing List, Laurent Pinchart

On Mon, Dec 23, 2019 at 3:10 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> Hi Nicolas,
>
> Many thanks for you review. Just preparing a new version with your comments
> addressed.
>
> On 20/12/19 9:44, Nicolas Boichat wrote:
> > On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
> > <enric.balletbo@collabora.com> wrote:
> >>
> >> From: Jitao Shi <jitao.shi@mediatek.com>
> >>
> >> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
> >>
> >> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> >> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> >> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> [uli: followed API changes, removed FW update feature]
> >> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> ---
> [snip]
> >> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
> >> +                                       status & ~MCS_EN);
> >> +       if (ret < 0) {
> >> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
> >> +               goto err_regulators_disable;
> >> +       }
> >> +
> >> +       ret = ps8640_bridge_unmute(ps_bridge);
> >> +       if (ret)
> >> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
> >
> > failed to unmute? Or failed to enable?
> >
>
> failed to unmute sound more clear to me.

I may be wrong, but I have the feeling that the functions
"mute/unmute" video/display, actually... And that the function naming
is strange...

You could just try to remove the calls, as there is no audio on the
board you have (elm), so if video still works, maybe this is actually
audio ,-)

Thanks,

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23  9:14         ` Nicolas Boichat
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Boichat @ 2019-12-23  9:14 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml,
	moderated list:ARM/Mediatek SoC support, dri-devel, Hsin-Yi Wang,
	Matthias Brugger, Collabora Kernel ML, linux-arm Mailing List,
	Laurent Pinchart

On Mon, Dec 23, 2019 at 3:10 PM Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
>
> Hi Nicolas,
>
> Many thanks for you review. Just preparing a new version with your comments
> addressed.
>
> On 20/12/19 9:44, Nicolas Boichat wrote:
> > On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
> > <enric.balletbo@collabora.com> wrote:
> >>
> >> From: Jitao Shi <jitao.shi@mediatek.com>
> >>
> >> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
> >>
> >> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> >> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
> >> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> [uli: followed API changes, removed FW update feature]
> >> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> ---
> [snip]
> >> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
> >> +                                       status & ~MCS_EN);
> >> +       if (ret < 0) {
> >> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
> >> +               goto err_regulators_disable;
> >> +       }
> >> +
> >> +       ret = ps8640_bridge_unmute(ps_bridge);
> >> +       if (ret)
> >> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
> >
> > failed to unmute? Or failed to enable?
> >
>
> failed to unmute sound more clear to me.

I may be wrong, but I have the feeling that the functions
"mute/unmute" video/display, actually... And that the function naming
is strange...

You could just try to remove the calls, as there is no audio on the
board you have (elm), so if video still works, maybe this is actually
audio ,-)

Thanks,
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
  2019-12-23  9:14         ` Nicolas Boichat
  (?)
  (?)
@ 2019-12-23 14:27           ` Enric Balletbo i Serra
  -1 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23 14:27 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: lkml, Collabora Kernel ML, Matthias Brugger, Hsin-Yi Wang,
	Jitao Shi, Daniel Kurtz, Ulrich Hecht, linux-arm Mailing List,
	Andrzej Hajda, Jonas Karlman, dri-devel, Neil Armstrong,
	moderated list:ARM/Mediatek SoC support, David Airlie,
	Jernej Skrabec, Laurent Pinchart, Daniel Vetter

Hi Nicolas,

On 23/12/19 10:14, Nicolas Boichat wrote:
> On Mon, Dec 23, 2019 at 3:10 PM Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>>
>> Hi Nicolas,
>>
>> Many thanks for you review. Just preparing a new version with your comments
>> addressed.
>>
>> On 20/12/19 9:44, Nicolas Boichat wrote:
>>> On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
>>> <enric.balletbo@collabora.com> wrote:
>>>>
>>>> From: Jitao Shi <jitao.shi@mediatek.com>
>>>>
>>>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>>>
>>>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>>>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>>>> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>>> [uli: followed API changes, removed FW update feature]
>>>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>>>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>>> ---
>> [snip]
>>>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
>>>> +                                       status & ~MCS_EN);
>>>> +       if (ret < 0) {
>>>> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
>>>> +               goto err_regulators_disable;
>>>> +       }
>>>> +
>>>> +       ret = ps8640_bridge_unmute(ps_bridge);
>>>> +       if (ret)
>>>> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
>>>
>>> failed to unmute? Or failed to enable?
>>>
>>
>> failed to unmute sound more clear to me.
> 
> I may be wrong, but I have the feeling that the functions
> "mute/unmute" video/display, actually... And that the function naming
> is strange...
> 

Yes, that's strange.

> You could just try to remove the calls, as there is no audio on the
> board you have (elm), so if video still works, maybe this is actually
> audio ,-)
> 

And without those the display doesn't work. So I suspect that what is wrong and
confusing is the message, instead of mute/unmute, and based on the register
names this looks more like an internal regulator that you need to enable and
disable, so I'll change the error message accordingly.

Thanks,
 Enric

> Thanks,
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23 14:27           ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23 14:27 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml, Andrzej Hajda,
	moderated list:ARM/Mediatek SoC support, dri-devel,
	Daniel Vetter, Hsin-Yi Wang, Matthias Brugger,
	Collabora Kernel ML, linux-arm Mailing List, Laurent Pinchart

Hi Nicolas,

On 23/12/19 10:14, Nicolas Boichat wrote:
> On Mon, Dec 23, 2019 at 3:10 PM Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>>
>> Hi Nicolas,
>>
>> Many thanks for you review. Just preparing a new version with your comments
>> addressed.
>>
>> On 20/12/19 9:44, Nicolas Boichat wrote:
>>> On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
>>> <enric.balletbo@collabora.com> wrote:
>>>>
>>>> From: Jitao Shi <jitao.shi@mediatek.com>
>>>>
>>>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>>>
>>>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>>>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>>>> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>>> [uli: followed API changes, removed FW update feature]
>>>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>>>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>>> ---
>> [snip]
>>>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
>>>> +                                       status & ~MCS_EN);
>>>> +       if (ret < 0) {
>>>> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
>>>> +               goto err_regulators_disable;
>>>> +       }
>>>> +
>>>> +       ret = ps8640_bridge_unmute(ps_bridge);
>>>> +       if (ret)
>>>> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
>>>
>>> failed to unmute? Or failed to enable?
>>>
>>
>> failed to unmute sound more clear to me.
> 
> I may be wrong, but I have the feeling that the functions
> "mute/unmute" video/display, actually... And that the function naming
> is strange...
> 

Yes, that's strange.

> You could just try to remove the calls, as there is no audio on the
> board you have (elm), so if video still works, maybe this is actually
> audio ,-)
> 

And without those the display doesn't work. So I suspect that what is wrong and
confusing is the message, instead of mute/unmute, and based on the register
names this looks more like an internal regulator that you need to enable and
disable, so I'll change the error message accordingly.

Thanks,
 Enric

> Thanks,
> 

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23 14:27           ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23 14:27 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml, Daniel Kurtz, Andrzej Hajda,
	moderated list:ARM/Mediatek SoC support, dri-devel,
	Daniel Vetter, Hsin-Yi Wang, Matthias Brugger,
	Collabora Kernel ML, linux-arm Mailing List, Laurent Pinchart

Hi Nicolas,

On 23/12/19 10:14, Nicolas Boichat wrote:
> On Mon, Dec 23, 2019 at 3:10 PM Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>>
>> Hi Nicolas,
>>
>> Many thanks for you review. Just preparing a new version with your comments
>> addressed.
>>
>> On 20/12/19 9:44, Nicolas Boichat wrote:
>>> On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
>>> <enric.balletbo@collabora.com> wrote:
>>>>
>>>> From: Jitao Shi <jitao.shi@mediatek.com>
>>>>
>>>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>>>
>>>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>>>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>>>> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>>> [uli: followed API changes, removed FW update feature]
>>>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>>>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>>> ---
>> [snip]
>>>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
>>>> +                                       status & ~MCS_EN);
>>>> +       if (ret < 0) {
>>>> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
>>>> +               goto err_regulators_disable;
>>>> +       }
>>>> +
>>>> +       ret = ps8640_bridge_unmute(ps_bridge);
>>>> +       if (ret)
>>>> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
>>>
>>> failed to unmute? Or failed to enable?
>>>
>>
>> failed to unmute sound more clear to me.
> 
> I may be wrong, but I have the feeling that the functions
> "mute/unmute" video/display, actually... And that the function naming
> is strange...
> 

Yes, that's strange.

> You could just try to remove the calls, as there is no audio on the
> board you have (elm), so if video still works, maybe this is actually
> audio ,-)
> 

And without those the display doesn't work. So I suspect that what is wrong and
confusing is the message, instead of mute/unmute, and based on the register
names this looks more like an internal regulator that you need to enable and
disable, so I'll change the error message accordingly.

Thanks,
 Enric

> Thanks,
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
@ 2019-12-23 14:27           ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23 14:27 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Ulrich Hecht, Jernej Skrabec, Jitao Shi, Jonas Karlman,
	David Airlie, Neil Armstrong, lkml,
	moderated list:ARM/Mediatek SoC support, dri-devel, Hsin-Yi Wang,
	Matthias Brugger, Collabora Kernel ML, linux-arm Mailing List,
	Laurent Pinchart

Hi Nicolas,

On 23/12/19 10:14, Nicolas Boichat wrote:
> On Mon, Dec 23, 2019 at 3:10 PM Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>>
>> Hi Nicolas,
>>
>> Many thanks for you review. Just preparing a new version with your comments
>> addressed.
>>
>> On 20/12/19 9:44, Nicolas Boichat wrote:
>>> On Fri, Dec 20, 2019 at 4:17 PM Enric Balletbo i Serra
>>> <enric.balletbo@collabora.com> wrote:
>>>>
>>>> From: Jitao Shi <jitao.shi@mediatek.com>
>>>>
>>>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>>>
>>>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>>>> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
>>>> Reviewed-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>>> [uli: followed API changes, removed FW update feature]
>>>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>>>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>>> ---
>> [snip]
>>>> +       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
>>>> +                                       status & ~MCS_EN);
>>>> +       if (ret < 0) {
>>>> +               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
>>>> +               goto err_regulators_disable;
>>>> +       }
>>>> +
>>>> +       ret = ps8640_bridge_unmute(ps_bridge);
>>>> +       if (ret)
>>>> +               DRM_ERROR("failed to enable unmutevideo: %d\n", ret);
>>>
>>> failed to unmute? Or failed to enable?
>>>
>>
>> failed to unmute sound more clear to me.
> 
> I may be wrong, but I have the feeling that the functions
> "mute/unmute" video/display, actually... And that the function naming
> is strange...
> 

Yes, that's strange.

> You could just try to remove the calls, as there is no audio on the
> board you have (elm), so if video still works, maybe this is actually
> audio ,-)
> 

And without those the display doesn't work. So I suspect that what is wrong and
confusing is the message, instead of mute/unmute, and based on the register
names this looks more like an internal regulator that you need to enable and
disable, so I'll change the error message accordingly.

Thanks,
 Enric

> Thanks,
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
  2019-12-26 14:27     ` Ezequiel Garcia
  (?)
  (?)
@ 2019-12-27  9:19       ` Enric Balletbo i Serra
  -1 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-27  9:19 UTC (permalink / raw)
  To: Ezequiel Garcia, linux-kernel, Rob Herring
  Cc: Collabora Kernel ML, matthias.bgg, drinkcat, hsinyi, Jitao Shi,
	Rob Herring, Philipp Zabel, Ulrich Hecht, linux-arm-kernel,
	devicetree, dri-devel, linux-mediatek, David Airlie,
	Mark Rutland, Daniel Vetter

Hi Ezequiel,

On 26/12/19 15:27, Ezequiel Garcia wrote:
> Hi Enric, Rob,
> 
> On Mon, 2019-12-23 at 15:35 +0100, Enric Balletbo i Serra wrote:
>> From: Jitao Shi <jitao.shi@mediatek.com>
>>
>> Add documentation for DT properties supported by
>> ps8640 DSI-eDP converter.
>>
>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>> Acked-by: Rob Herring <robh@kernel.org>
>> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [..]
>> +
>> +  ports:
>> +    type: object
>> +    description:
>> +      A node containing DSI input & output port nodes with endpoint
>> +      definitions as documented in
>> +      Documentation/devicetree/bindings/media/video-interfaces.txt
>> +      Documentation/devicetree/bindings/graph.txt
>> +    properties:
>> +      port@0:
>> +        type: object
>> +        description: |
>> +          Video port for DSI input
>> +
>> +      port@1:
>> +        type: object
>> +        description: |
>> +          Video port for eDP output (panel or connector).
>> +
>> +    required:
>> +      - port@0
>> +
> 
> Is it correct to require port@0 ? This could be called port@1
> or port@2, and IIUC it should bind the same.
> 

My understanding is that at least the Video port for DSI input is required,
which makes sense, otherwise you have the chip connected nowhere. port@1 is
optional because it could be connected to a eDP panel or can just be a connector.

About your second question, I am not sure I understand you. You mean that have a
DT like this should work?

            ports {
                #address-cells = <1>;
                #size-cells = <0>;

                port@1 {
                    reg = <0>;
                    ps8640_in: endpoint {
                        remote-endpoint = <&dsi0_out>;
                    };
                };

                port@2 {
                    reg = <1>;
                    ps8640_out: endpoint {
                        remote-endpoint = <&panel_in>;
                   };
                };
            };


Probably yes, because the driver what really looks is the register value, but
that's odd and probably a bad practice. Also if I am not wrong the convention is
name the nodes with port@<reg property> (like we do in i2c devices for example)

port@0 is the label that has the register value to 0.
port@1 is the label that has the register value to 1.
...

Thanks,
 Enric

> Thanks,
> Ezequiel 
> 
>> +required:
>> +  - compatible
>> +  - reg
>> +  - powerdown-gpios
>> +  - reset-gpios
>> +  - vdd12-supply
>> +  - vdd33-supply
>> +  - ports
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/gpio/gpio.h>
>> +    i2c0 {
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        ps8640: edp-bridge@18 {
>> +            compatible = "parade,ps8640";
>> +            reg = <0x18>;
>> +            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
>> +            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
>> +            vdd12-supply = <&ps8640_fixed_1v2>;
>> +            vdd33-supply = <&mt6397_vgp2_reg>;
>> +
>> +            ports {
>> +                #address-cells = <1>;
>> +                #size-cells = <0>;
>> +
>> +                port@0 {
>> +                    reg = <0>;
>> +                    ps8640_in: endpoint {
>> +                        remote-endpoint = <&dsi0_out>;
>> +                    };
>> +                };
>> +
>> +                port@1 {
>> +                    reg = <1>;
>> +                    ps8640_out: endpoint {
>> +                        remote-endpoint = <&panel_in>;
>> +                   };
>> +                };
>> +            };
>> +        };
>> +    };
>> +
>> -- 
>> 2.20.1
>>
>>
> 
> 
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-27  9:19       ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-27  9:19 UTC (permalink / raw)
  To: Ezequiel Garcia, linux-kernel, Rob Herring
  Cc: Mark Rutland, Rob Herring, drinkcat, Jitao Shi, Daniel Vetter,
	Ulrich Hecht, David Airlie, dri-devel, devicetree,
	linux-mediatek, Philipp Zabel, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

Hi Ezequiel,

On 26/12/19 15:27, Ezequiel Garcia wrote:
> Hi Enric, Rob,
> 
> On Mon, 2019-12-23 at 15:35 +0100, Enric Balletbo i Serra wrote:
>> From: Jitao Shi <jitao.shi@mediatek.com>
>>
>> Add documentation for DT properties supported by
>> ps8640 DSI-eDP converter.
>>
>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>> Acked-by: Rob Herring <robh@kernel.org>
>> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [..]
>> +
>> +  ports:
>> +    type: object
>> +    description:
>> +      A node containing DSI input & output port nodes with endpoint
>> +      definitions as documented in
>> +      Documentation/devicetree/bindings/media/video-interfaces.txt
>> +      Documentation/devicetree/bindings/graph.txt
>> +    properties:
>> +      port@0:
>> +        type: object
>> +        description: |
>> +          Video port for DSI input
>> +
>> +      port@1:
>> +        type: object
>> +        description: |
>> +          Video port for eDP output (panel or connector).
>> +
>> +    required:
>> +      - port@0
>> +
> 
> Is it correct to require port@0 ? This could be called port@1
> or port@2, and IIUC it should bind the same.
> 

My understanding is that at least the Video port for DSI input is required,
which makes sense, otherwise you have the chip connected nowhere. port@1 is
optional because it could be connected to a eDP panel or can just be a connector.

About your second question, I am not sure I understand you. You mean that have a
DT like this should work?

            ports {
                #address-cells = <1>;
                #size-cells = <0>;

                port@1 {
                    reg = <0>;
                    ps8640_in: endpoint {
                        remote-endpoint = <&dsi0_out>;
                    };
                };

                port@2 {
                    reg = <1>;
                    ps8640_out: endpoint {
                        remote-endpoint = <&panel_in>;
                   };
                };
            };


Probably yes, because the driver what really looks is the register value, but
that's odd and probably a bad practice. Also if I am not wrong the convention is
name the nodes with port@<reg property> (like we do in i2c devices for example)

port@0 is the label that has the register value to 0.
port@1 is the label that has the register value to 1.
...

Thanks,
 Enric

> Thanks,
> Ezequiel 
> 
>> +required:
>> +  - compatible
>> +  - reg
>> +  - powerdown-gpios
>> +  - reset-gpios
>> +  - vdd12-supply
>> +  - vdd33-supply
>> +  - ports
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/gpio/gpio.h>
>> +    i2c0 {
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        ps8640: edp-bridge@18 {
>> +            compatible = "parade,ps8640";
>> +            reg = <0x18>;
>> +            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
>> +            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
>> +            vdd12-supply = <&ps8640_fixed_1v2>;
>> +            vdd33-supply = <&mt6397_vgp2_reg>;
>> +
>> +            ports {
>> +                #address-cells = <1>;
>> +                #size-cells = <0>;
>> +
>> +                port@0 {
>> +                    reg = <0>;
>> +                    ps8640_in: endpoint {
>> +                        remote-endpoint = <&dsi0_out>;
>> +                    };
>> +                };
>> +
>> +                port@1 {
>> +                    reg = <1>;
>> +                    ps8640_out: endpoint {
>> +                        remote-endpoint = <&panel_in>;
>> +                   };
>> +                };
>> +            };
>> +        };
>> +    };
>> +
>> -- 
>> 2.20.1
>>
>>
> 
> 
> 

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-27  9:19       ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-27  9:19 UTC (permalink / raw)
  To: Ezequiel Garcia, linux-kernel, Rob Herring
  Cc: Mark Rutland, Rob Herring, drinkcat, Jitao Shi, Daniel Vetter,
	Ulrich Hecht, David Airlie, dri-devel, devicetree,
	linux-mediatek, Philipp Zabel, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

Hi Ezequiel,

On 26/12/19 15:27, Ezequiel Garcia wrote:
> Hi Enric, Rob,
> 
> On Mon, 2019-12-23 at 15:35 +0100, Enric Balletbo i Serra wrote:
>> From: Jitao Shi <jitao.shi@mediatek.com>
>>
>> Add documentation for DT properties supported by
>> ps8640 DSI-eDP converter.
>>
>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>> Acked-by: Rob Herring <robh@kernel.org>
>> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [..]
>> +
>> +  ports:
>> +    type: object
>> +    description:
>> +      A node containing DSI input & output port nodes with endpoint
>> +      definitions as documented in
>> +      Documentation/devicetree/bindings/media/video-interfaces.txt
>> +      Documentation/devicetree/bindings/graph.txt
>> +    properties:
>> +      port@0:
>> +        type: object
>> +        description: |
>> +          Video port for DSI input
>> +
>> +      port@1:
>> +        type: object
>> +        description: |
>> +          Video port for eDP output (panel or connector).
>> +
>> +    required:
>> +      - port@0
>> +
> 
> Is it correct to require port@0 ? This could be called port@1
> or port@2, and IIUC it should bind the same.
> 

My understanding is that at least the Video port for DSI input is required,
which makes sense, otherwise you have the chip connected nowhere. port@1 is
optional because it could be connected to a eDP panel or can just be a connector.

About your second question, I am not sure I understand you. You mean that have a
DT like this should work?

            ports {
                #address-cells = <1>;
                #size-cells = <0>;

                port@1 {
                    reg = <0>;
                    ps8640_in: endpoint {
                        remote-endpoint = <&dsi0_out>;
                    };
                };

                port@2 {
                    reg = <1>;
                    ps8640_out: endpoint {
                        remote-endpoint = <&panel_in>;
                   };
                };
            };


Probably yes, because the driver what really looks is the register value, but
that's odd and probably a bad practice. Also if I am not wrong the convention is
name the nodes with port@<reg property> (like we do in i2c devices for example)

port@0 is the label that has the register value to 0.
port@1 is the label that has the register value to 1.
...

Thanks,
 Enric

> Thanks,
> Ezequiel 
> 
>> +required:
>> +  - compatible
>> +  - reg
>> +  - powerdown-gpios
>> +  - reset-gpios
>> +  - vdd12-supply
>> +  - vdd33-supply
>> +  - ports
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/gpio/gpio.h>
>> +    i2c0 {
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        ps8640: edp-bridge@18 {
>> +            compatible = "parade,ps8640";
>> +            reg = <0x18>;
>> +            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
>> +            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
>> +            vdd12-supply = <&ps8640_fixed_1v2>;
>> +            vdd33-supply = <&mt6397_vgp2_reg>;
>> +
>> +            ports {
>> +                #address-cells = <1>;
>> +                #size-cells = <0>;
>> +
>> +                port@0 {
>> +                    reg = <0>;
>> +                    ps8640_in: endpoint {
>> +                        remote-endpoint = <&dsi0_out>;
>> +                    };
>> +                };
>> +
>> +                port@1 {
>> +                    reg = <1>;
>> +                    ps8640_out: endpoint {
>> +                        remote-endpoint = <&panel_in>;
>> +                   };
>> +                };
>> +            };
>> +        };
>> +    };
>> +
>> -- 
>> 2.20.1
>>
>>
> 
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-27  9:19       ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-27  9:19 UTC (permalink / raw)
  To: Ezequiel Garcia, linux-kernel, Rob Herring
  Cc: Mark Rutland, drinkcat, Jitao Shi, Ulrich Hecht, David Airlie,
	dri-devel, devicetree, linux-mediatek, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

Hi Ezequiel,

On 26/12/19 15:27, Ezequiel Garcia wrote:
> Hi Enric, Rob,
> 
> On Mon, 2019-12-23 at 15:35 +0100, Enric Balletbo i Serra wrote:
>> From: Jitao Shi <jitao.shi@mediatek.com>
>>
>> Add documentation for DT properties supported by
>> ps8640 DSI-eDP converter.
>>
>> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
>> Acked-by: Rob Herring <robh@kernel.org>
>> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
>> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> [..]
>> +
>> +  ports:
>> +    type: object
>> +    description:
>> +      A node containing DSI input & output port nodes with endpoint
>> +      definitions as documented in
>> +      Documentation/devicetree/bindings/media/video-interfaces.txt
>> +      Documentation/devicetree/bindings/graph.txt
>> +    properties:
>> +      port@0:
>> +        type: object
>> +        description: |
>> +          Video port for DSI input
>> +
>> +      port@1:
>> +        type: object
>> +        description: |
>> +          Video port for eDP output (panel or connector).
>> +
>> +    required:
>> +      - port@0
>> +
> 
> Is it correct to require port@0 ? This could be called port@1
> or port@2, and IIUC it should bind the same.
> 

My understanding is that at least the Video port for DSI input is required,
which makes sense, otherwise you have the chip connected nowhere. port@1 is
optional because it could be connected to a eDP panel or can just be a connector.

About your second question, I am not sure I understand you. You mean that have a
DT like this should work?

            ports {
                #address-cells = <1>;
                #size-cells = <0>;

                port@1 {
                    reg = <0>;
                    ps8640_in: endpoint {
                        remote-endpoint = <&dsi0_out>;
                    };
                };

                port@2 {
                    reg = <1>;
                    ps8640_out: endpoint {
                        remote-endpoint = <&panel_in>;
                   };
                };
            };


Probably yes, because the driver what really looks is the register value, but
that's odd and probably a bad practice. Also if I am not wrong the convention is
name the nodes with port@<reg property> (like we do in i2c devices for example)

port@0 is the label that has the register value to 0.
port@1 is the label that has the register value to 1.
...

Thanks,
 Enric

> Thanks,
> Ezequiel 
> 
>> +required:
>> +  - compatible
>> +  - reg
>> +  - powerdown-gpios
>> +  - reset-gpios
>> +  - vdd12-supply
>> +  - vdd33-supply
>> +  - ports
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/gpio/gpio.h>
>> +    i2c0 {
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        ps8640: edp-bridge@18 {
>> +            compatible = "parade,ps8640";
>> +            reg = <0x18>;
>> +            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
>> +            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
>> +            vdd12-supply = <&ps8640_fixed_1v2>;
>> +            vdd33-supply = <&mt6397_vgp2_reg>;
>> +
>> +            ports {
>> +                #address-cells = <1>;
>> +                #size-cells = <0>;
>> +
>> +                port@0 {
>> +                    reg = <0>;
>> +                    ps8640_in: endpoint {
>> +                        remote-endpoint = <&dsi0_out>;
>> +                    };
>> +                };
>> +
>> +                port@1 {
>> +                    reg = <1>;
>> +                    ps8640_out: endpoint {
>> +                        remote-endpoint = <&panel_in>;
>> +                   };
>> +                };
>> +            };
>> +        };
>> +    };
>> +
>> -- 
>> 2.20.1
>>
>>
> 
> 
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
  2019-12-23 14:35   ` Enric Balletbo i Serra
  (?)
  (?)
@ 2019-12-26 14:27     ` Ezequiel Garcia
  -1 siblings, 0 replies; 44+ messages in thread
From: Ezequiel Garcia @ 2019-12-26 14:27 UTC (permalink / raw)
  To: Enric Balletbo i Serra, linux-kernel, Rob Herring
  Cc: Collabora Kernel ML, matthias.bgg, drinkcat, hsinyi, Jitao Shi,
	Rob Herring, Philipp Zabel, Ulrich Hecht, linux-arm-kernel,
	devicetree, dri-devel, linux-mediatek, David Airlie,
	Mark Rutland, Daniel Vetter

Hi Enric, Rob,

On Mon, 2019-12-23 at 15:35 +0100, Enric Balletbo i Serra wrote:
> From: Jitao Shi <jitao.shi@mediatek.com>
> 
> Add documentation for DT properties supported by
> ps8640 DSI-eDP converter.
> 
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Acked-by: Rob Herring <robh@kernel.org>
> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
[..]
> +
> +  ports:
> +    type: object
> +    description:
> +      A node containing DSI input & output port nodes with endpoint
> +      definitions as documented in
> +      Documentation/devicetree/bindings/media/video-interfaces.txt
> +      Documentation/devicetree/bindings/graph.txt
> +    properties:
> +      port@0:
> +        type: object
> +        description: |
> +          Video port for DSI input
> +
> +      port@1:
> +        type: object
> +        description: |
> +          Video port for eDP output (panel or connector).
> +
> +    required:
> +      - port@0
> +

Is it correct to require port@0 ? This could be called port@1
or port@2, and IIUC it should bind the same.

Thanks,
Ezequiel 

> +required:
> +  - compatible
> +  - reg
> +  - powerdown-gpios
> +  - reset-gpios
> +  - vdd12-supply
> +  - vdd33-supply
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    i2c0 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        ps8640: edp-bridge@18 {
> +            compatible = "parade,ps8640";
> +            reg = <0x18>;
> +            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
> +            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
> +            vdd12-supply = <&ps8640_fixed_1v2>;
> +            vdd33-supply = <&mt6397_vgp2_reg>;
> +
> +            ports {
> +                #address-cells = <1>;
> +                #size-cells = <0>;
> +
> +                port@0 {
> +                    reg = <0>;
> +                    ps8640_in: endpoint {
> +                        remote-endpoint = <&dsi0_out>;
> +                    };
> +                };
> +
> +                port@1 {
> +                    reg = <1>;
> +                    ps8640_out: endpoint {
> +                        remote-endpoint = <&panel_in>;
> +                   };
> +                };
> +            };
> +        };
> +    };
> +
> -- 
> 2.20.1
> 
> 



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-26 14:27     ` Ezequiel Garcia
  0 siblings, 0 replies; 44+ messages in thread
From: Ezequiel Garcia @ 2019-12-26 14:27 UTC (permalink / raw)
  To: Enric Balletbo i Serra, linux-kernel, Rob Herring
  Cc: Mark Rutland, Rob Herring, drinkcat, Jitao Shi, Daniel Vetter,
	Ulrich Hecht, David Airlie, dri-devel, devicetree,
	linux-mediatek, Philipp Zabel, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

Hi Enric, Rob,

On Mon, 2019-12-23 at 15:35 +0100, Enric Balletbo i Serra wrote:
> From: Jitao Shi <jitao.shi@mediatek.com>
> 
> Add documentation for DT properties supported by
> ps8640 DSI-eDP converter.
> 
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Acked-by: Rob Herring <robh@kernel.org>
> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
[..]
> +
> +  ports:
> +    type: object
> +    description:
> +      A node containing DSI input & output port nodes with endpoint
> +      definitions as documented in
> +      Documentation/devicetree/bindings/media/video-interfaces.txt
> +      Documentation/devicetree/bindings/graph.txt
> +    properties:
> +      port@0:
> +        type: object
> +        description: |
> +          Video port for DSI input
> +
> +      port@1:
> +        type: object
> +        description: |
> +          Video port for eDP output (panel or connector).
> +
> +    required:
> +      - port@0
> +

Is it correct to require port@0 ? This could be called port@1
or port@2, and IIUC it should bind the same.

Thanks,
Ezequiel 

> +required:
> +  - compatible
> +  - reg
> +  - powerdown-gpios
> +  - reset-gpios
> +  - vdd12-supply
> +  - vdd33-supply
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    i2c0 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        ps8640: edp-bridge@18 {
> +            compatible = "parade,ps8640";
> +            reg = <0x18>;
> +            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
> +            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
> +            vdd12-supply = <&ps8640_fixed_1v2>;
> +            vdd33-supply = <&mt6397_vgp2_reg>;
> +
> +            ports {
> +                #address-cells = <1>;
> +                #size-cells = <0>;
> +
> +                port@0 {
> +                    reg = <0>;
> +                    ps8640_in: endpoint {
> +                        remote-endpoint = <&dsi0_out>;
> +                    };
> +                };
> +
> +                port@1 {
> +                    reg = <1>;
> +                    ps8640_out: endpoint {
> +                        remote-endpoint = <&panel_in>;
> +                   };
> +                };
> +            };
> +        };
> +    };
> +
> -- 
> 2.20.1
> 
> 



_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-26 14:27     ` Ezequiel Garcia
  0 siblings, 0 replies; 44+ messages in thread
From: Ezequiel Garcia @ 2019-12-26 14:27 UTC (permalink / raw)
  To: Enric Balletbo i Serra, linux-kernel, Rob Herring
  Cc: Mark Rutland, Rob Herring, drinkcat, Jitao Shi, Daniel Vetter,
	Ulrich Hecht, David Airlie, dri-devel, devicetree,
	linux-mediatek, Philipp Zabel, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

Hi Enric, Rob,

On Mon, 2019-12-23 at 15:35 +0100, Enric Balletbo i Serra wrote:
> From: Jitao Shi <jitao.shi@mediatek.com>
> 
> Add documentation for DT properties supported by
> ps8640 DSI-eDP converter.
> 
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Acked-by: Rob Herring <robh@kernel.org>
> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
[..]
> +
> +  ports:
> +    type: object
> +    description:
> +      A node containing DSI input & output port nodes with endpoint
> +      definitions as documented in
> +      Documentation/devicetree/bindings/media/video-interfaces.txt
> +      Documentation/devicetree/bindings/graph.txt
> +    properties:
> +      port@0:
> +        type: object
> +        description: |
> +          Video port for DSI input
> +
> +      port@1:
> +        type: object
> +        description: |
> +          Video port for eDP output (panel or connector).
> +
> +    required:
> +      - port@0
> +

Is it correct to require port@0 ? This could be called port@1
or port@2, and IIUC it should bind the same.

Thanks,
Ezequiel 

> +required:
> +  - compatible
> +  - reg
> +  - powerdown-gpios
> +  - reset-gpios
> +  - vdd12-supply
> +  - vdd33-supply
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    i2c0 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        ps8640: edp-bridge@18 {
> +            compatible = "parade,ps8640";
> +            reg = <0x18>;
> +            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
> +            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
> +            vdd12-supply = <&ps8640_fixed_1v2>;
> +            vdd33-supply = <&mt6397_vgp2_reg>;
> +
> +            ports {
> +                #address-cells = <1>;
> +                #size-cells = <0>;
> +
> +                port@0 {
> +                    reg = <0>;
> +                    ps8640_in: endpoint {
> +                        remote-endpoint = <&dsi0_out>;
> +                    };
> +                };
> +
> +                port@1 {
> +                    reg = <1>;
> +                    ps8640_out: endpoint {
> +                        remote-endpoint = <&panel_in>;
> +                   };
> +                };
> +            };
> +        };
> +    };
> +
> -- 
> 2.20.1
> 
> 



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-26 14:27     ` Ezequiel Garcia
  0 siblings, 0 replies; 44+ messages in thread
From: Ezequiel Garcia @ 2019-12-26 14:27 UTC (permalink / raw)
  To: Enric Balletbo i Serra, linux-kernel, Rob Herring
  Cc: Mark Rutland, drinkcat, Jitao Shi, Ulrich Hecht, David Airlie,
	dri-devel, devicetree, linux-mediatek, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

Hi Enric, Rob,

On Mon, 2019-12-23 at 15:35 +0100, Enric Balletbo i Serra wrote:
> From: Jitao Shi <jitao.shi@mediatek.com>
> 
> Add documentation for DT properties supported by
> ps8640 DSI-eDP converter.
> 
> Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
> Acked-by: Rob Herring <robh@kernel.org>
> Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Ulrich Hecht <uli@fpond.eu>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
[..]
> +
> +  ports:
> +    type: object
> +    description:
> +      A node containing DSI input & output port nodes with endpoint
> +      definitions as documented in
> +      Documentation/devicetree/bindings/media/video-interfaces.txt
> +      Documentation/devicetree/bindings/graph.txt
> +    properties:
> +      port@0:
> +        type: object
> +        description: |
> +          Video port for DSI input
> +
> +      port@1:
> +        type: object
> +        description: |
> +          Video port for eDP output (panel or connector).
> +
> +    required:
> +      - port@0
> +

Is it correct to require port@0 ? This could be called port@1
or port@2, and IIUC it should bind the same.

Thanks,
Ezequiel 

> +required:
> +  - compatible
> +  - reg
> +  - powerdown-gpios
> +  - reset-gpios
> +  - vdd12-supply
> +  - vdd33-supply
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    i2c0 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        ps8640: edp-bridge@18 {
> +            compatible = "parade,ps8640";
> +            reg = <0x18>;
> +            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
> +            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
> +            vdd12-supply = <&ps8640_fixed_1v2>;
> +            vdd33-supply = <&mt6397_vgp2_reg>;
> +
> +            ports {
> +                #address-cells = <1>;
> +                #size-cells = <0>;
> +
> +                port@0 {
> +                    reg = <0>;
> +                    ps8640_in: endpoint {
> +                        remote-endpoint = <&dsi0_out>;
> +                    };
> +                };
> +
> +                port@1 {
> +                    reg = <1>;
> +                    ps8640_out: endpoint {
> +                        remote-endpoint = <&panel_in>;
> +                   };
> +                };
> +            };
> +        };
> +    };
> +
> -- 
> 2.20.1
> 
> 


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
  2019-12-23 14:35 [PATCH v22 0/2] drm/bridge: PS8640 MIPI-to-eDP bridge Enric Balletbo i Serra
  2019-12-23 14:35   ` Enric Balletbo i Serra
  (?)
@ 2019-12-23 14:35   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23 14:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Collabora Kernel ML, matthias.bgg, drinkcat, hsinyi, Jitao Shi,
	Rob Herring, Philipp Zabel, Ulrich Hecht, linux-arm-kernel,
	devicetree, dri-devel, Rob Herring, linux-mediatek, David Airlie,
	Mark Rutland, Daniel Vetter

From: Jitao Shi <jitao.shi@mediatek.com>

Add documentation for DT properties supported by
ps8640 DSI-eDP converter.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
I maintained the ack from Rob Herring and the review from Philipp
because in essence the only thing I did is migrate to YAML format and
check that no errors are reported via dtbs_check. Just let me know if
you're not agree.

Apart from this note that I removed the mode-sel property because is not
used and I renamed sleep-gpios to powerdown-gpios.

Changes in v23: None
Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.

Changes in v21: None
Changes in v19: None
Changes in v18: None
Changes in v17: None
Changes in v16: None
Changes in v15: None
Changes in v14: None
Changes in v13: None
Changes in v12: None
Changes in v11: None

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644
index 000000000000..5dff93641bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-23 14:35   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23 14:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, Rob Herring, drinkcat, Jitao Shi, Daniel Vetter,
	Ulrich Hecht, David Airlie, dri-devel, devicetree, Rob Herring,
	linux-mediatek, Philipp Zabel, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

From: Jitao Shi <jitao.shi@mediatek.com>

Add documentation for DT properties supported by
ps8640 DSI-eDP converter.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
I maintained the ack from Rob Herring and the review from Philipp
because in essence the only thing I did is migrate to YAML format and
check that no errors are reported via dtbs_check. Just let me know if
you're not agree.

Apart from this note that I removed the mode-sel property because is not
used and I renamed sleep-gpios to powerdown-gpios.

Changes in v23: None
Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.

Changes in v21: None
Changes in v19: None
Changes in v18: None
Changes in v17: None
Changes in v16: None
Changes in v15: None
Changes in v14: None
Changes in v13: None
Changes in v12: None
Changes in v11: None

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644
index 000000000000..5dff93641bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
-- 
2.20.1


_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-23 14:35   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23 14:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, Rob Herring, drinkcat, Jitao Shi, Daniel Vetter,
	Ulrich Hecht, David Airlie, dri-devel, devicetree, Rob Herring,
	linux-mediatek, Philipp Zabel, hsinyi, matthias.bgg,
	Collabora Kernel ML, linux-arm-kernel

From: Jitao Shi <jitao.shi@mediatek.com>

Add documentation for DT properties supported by
ps8640 DSI-eDP converter.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
I maintained the ack from Rob Herring and the review from Philipp
because in essence the only thing I did is migrate to YAML format and
check that no errors are reported via dtbs_check. Just let me know if
you're not agree.

Apart from this note that I removed the mode-sel property because is not
used and I renamed sleep-gpios to powerdown-gpios.

Changes in v23: None
Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.

Changes in v21: None
Changes in v19: None
Changes in v18: None
Changes in v17: None
Changes in v16: None
Changes in v15: None
Changes in v14: None
Changes in v13: None
Changes in v12: None
Changes in v11: None

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644
index 000000000000..5dff93641bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties
@ 2019-12-23 14:35   ` Enric Balletbo i Serra
  0 siblings, 0 replies; 44+ messages in thread
From: Enric Balletbo i Serra @ 2019-12-23 14:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Rutland, drinkcat, Jitao Shi, Ulrich Hecht, David Airlie,
	dri-devel, devicetree, Rob Herring, linux-mediatek, hsinyi,
	matthias.bgg, Collabora Kernel ML, linux-arm-kernel

From: Jitao Shi <jitao.shi@mediatek.com>

Add documentation for DT properties supported by
ps8640 DSI-eDP converter.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Ulrich Hecht <uli@fpond.eu>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
I maintained the ack from Rob Herring and the review from Philipp
because in essence the only thing I did is migrate to YAML format and
check that no errors are reported via dtbs_check. Just let me know if
you're not agree.

Apart from this note that I removed the mode-sel property because is not
used and I renamed sleep-gpios to powerdown-gpios.

Changes in v23: None
Changes in v22:
- Migrate to YAML format (Maxime Ripart)
- Remove mode-sel property.
- Rename sleep-gpios to powerdown-gpios.

Changes in v21: None
Changes in v19: None
Changes in v18: None
Changes in v17: None
Changes in v16: None
Changes in v15: None
Changes in v14: None
Changes in v13: None
Changes in v12: None
Changes in v11: None

 .../bindings/display/bridge/ps8640.yaml       | 112 ++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ps8640.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644
index 000000000000..5dff93641bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2019-12-27 10:39 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-20  8:17 [PATCH v22 0/2] drm/bridge: PS8640 MIPI-to-eDP bridge Enric Balletbo i Serra
2019-12-20  8:17 ` Enric Balletbo i Serra
2019-12-20  8:17 ` Enric Balletbo i Serra
2019-12-20  8:17 ` Enric Balletbo i Serra
2019-12-20  8:17 ` [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties Enric Balletbo i Serra
2019-12-20  8:17   ` Enric Balletbo i Serra
2019-12-20  8:17   ` Enric Balletbo i Serra
2019-12-20  8:17   ` Enric Balletbo i Serra
2019-12-20  8:17 ` [PATCH v22 2/2] drm/bridge: Add I2C based driver for ps8640 bridge Enric Balletbo i Serra
2019-12-20  8:17   ` Enric Balletbo i Serra
2019-12-20  8:17   ` Enric Balletbo i Serra
2019-12-20  8:17   ` Enric Balletbo i Serra
2019-12-20  8:44   ` Nicolas Boichat
2019-12-20  8:44     ` Nicolas Boichat
2019-12-20  8:44     ` Nicolas Boichat
2019-12-20  8:44     ` Nicolas Boichat
2019-12-23  7:09     ` Enric Balletbo i Serra
2019-12-23  7:09       ` Enric Balletbo i Serra
2019-12-23  7:09       ` Enric Balletbo i Serra
2019-12-23  7:09       ` Enric Balletbo i Serra
2019-12-23  9:14       ` Nicolas Boichat
2019-12-23  9:14         ` Nicolas Boichat
2019-12-23  9:14         ` Nicolas Boichat
2019-12-23  9:14         ` Nicolas Boichat
2019-12-23 14:27         ` Enric Balletbo i Serra
2019-12-23 14:27           ` Enric Balletbo i Serra
2019-12-23 14:27           ` Enric Balletbo i Serra
2019-12-23 14:27           ` Enric Balletbo i Serra
2019-12-20  8:55   ` Hsin-Yi Wang
2019-12-20  8:55     ` Hsin-Yi Wang
2019-12-20  8:55     ` Hsin-Yi Wang
2019-12-20  8:55     ` Hsin-Yi Wang
2019-12-23 14:35 [PATCH v22 0/2] drm/bridge: PS8640 MIPI-to-eDP bridge Enric Balletbo i Serra
2019-12-23 14:35 ` [PATCH v22 1/2] Documentation: bridge: Add documentation for ps8640 DT properties Enric Balletbo i Serra
2019-12-23 14:35   ` Enric Balletbo i Serra
2019-12-23 14:35   ` Enric Balletbo i Serra
2019-12-23 14:35   ` Enric Balletbo i Serra
2019-12-26 14:27   ` Ezequiel Garcia
2019-12-26 14:27     ` Ezequiel Garcia
2019-12-26 14:27     ` Ezequiel Garcia
2019-12-26 14:27     ` Ezequiel Garcia
2019-12-27  9:19     ` Enric Balletbo i Serra
2019-12-27  9:19       ` Enric Balletbo i Serra
2019-12-27  9:19       ` Enric Balletbo i Serra
2019-12-27  9:19       ` Enric Balletbo i Serra

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.