Hi,
Thanks for your patches.
On 2021/9/13 19:44, Gou Hao wrote:
From: gouhao gouhao@uniontech.com
uniontech inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I469VQ CVE: NA
Backport from mainline, please use:
mainline inclusion from mainline-x.x ...
fix hibmc did not get edid.
backport from openEuler master branch:
4eb4d99dfe: drm/hisilicon: Support i2c driver algorithms for bit-shift
a0d078d06e: drm/hisilicon: Features to support reading resolutions from EDID. Modified the a0d078d06e original patch.
Please send each patch for every upstream patches.
Your own change should be a new patch, except "adjust context".
Thansk, Xie XiuQi
add include/drm/drm_probe_helper.h
add drm_connector_init_with_ddc interface in /drivers/gpu/drm/drm_connector.c
Signed-off-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Andrzej Pietrasiewicz andrzej.p@collabora.com Signed-off-by: Tian Tao tiantao6@hisilicon.com Signed-off-by: Gou Hao gouhao@uniontech.com
drivers/gpu/drm/drm_connector.c | 35 +++++++ drivers/gpu/drm/hisilicon/hibmc/Makefile | 3 +- .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 27 +++++ .../gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c | 99 +++++++++++++++++++ .../gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 59 ++++++++--- include/drm/drm_connector.h | 17 ++++ include/drm/drm_probe_helper.h | 27 +++++ 7 files changed, 250 insertions(+), 17 deletions(-) create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c create mode 100644 include/drm/drm_probe_helper.h
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 6011d769d..ed49d0e93 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -290,6 +290,41 @@ out_put: } EXPORT_SYMBOL(drm_connector_init);
+/**
- drm_connector_init_with_ddc - Init a preallocated connector
- @dev: DRM device
- @connector: the connector to init
- @funcs: callbacks for this connector
- @connector_type: user visible type of the connector
- @ddc: pointer to the associated ddc adapter
- Initialises a preallocated connector. Connectors should be
- subclassed as part of driver connector objects.
- Ensures that the ddc field of the connector is correctly set.
- Returns:
- Zero on success, error code on failure.
- */
+int drm_connector_init_with_ddc(struct drm_device *dev,
struct drm_connector *connector,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc)
+{
- int ret;
- ret = drm_connector_init(dev, connector, funcs, connector_type);
- if (ret)
return ret;
- /* provide ddc symlink in sysfs */
- connector->ddc = ddc;
- return ret;
+} +EXPORT_SYMBOL(drm_connector_init_with_ddc);
/**
- drm_connector_attach_encoder - attach a connector to an encoder
- @connector: connector to attach
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile index 3df726696..14c1ca9c9 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile @@ -1,3 +1,4 @@ -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o \
hibmc_drm_fbdev.o hibmc_ttm.o hibmc_drm_i2c.o
obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index 4395dc667..2b42864ba 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -19,12 +19,24 @@ #ifndef HIBMC_DRM_DRV_H #define HIBMC_DRM_DRV_H
+#include <linux/gpio/consumer.h> +#include <linux/i2c-algo-bit.h> +#include <linux/i2c.h>
+#include <drm/drm_edid.h> #include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> #include <drm/ttm/ttm_bo_driver.h>
+struct hibmc_connector {
- struct drm_connector base;
- struct i2c_adapter adapter;
- struct i2c_algo_bit_data bit_data;
+};
struct hibmc_framebuffer { struct drm_framebuffer fb; struct drm_gem_object *obj; @@ -43,6 +55,8 @@ struct hibmc_drm_private { unsigned long fb_base; unsigned long fb_size; bool msi_enabled;
struct drm_encoder encoder;
struct hibmc_connector connector;
/* drm */ struct drm_device *dev;
@@ -60,6 +74,17 @@ struct hibmc_drm_private { bool mm_inited; };
+static inline struct hibmc_connector *to_hibmc_connector(struct drm_connector *connector) +{
- return container_of(connector, struct hibmc_connector, base);
+}
+static inline struct hibmc_drm_private *to_hibmc_drm_private(struct drm_device *dev) +{
- return dev->dev_private;
+}
#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb)
struct hibmc_bo { @@ -111,6 +136,8 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, u32 handle, u64 *offset); int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
+int hibmc_ddc_create(struct drm_device *drm_dev, struct hibmc_connector *connector);
extern const struct drm_mode_config_funcs hibmc_mode_funcs;
#endif diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c new file mode 100644 index 000000000..86d712090 --- /dev/null +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Hisilicon Hibmc SoC drm driver
- Based on the bochs drm driver.
- Copyright (c) 2016 Huawei Limited.
- Author:
Tian Tao <tiantao6@hisilicon.com>
- */
+#include <linux/delay.h> +#include <linux/pci.h>
+#include <drm/drm_atomic_helper.h> +#include <drm/drm_probe_helper.h>
+#include "hibmc_drm_drv.h"
+#define GPIO_DATA 0x0802A0 +#define GPIO_DATA_DIRECTION 0x0802A4
+#define I2C_SCL_MASK BIT(0) +#define I2C_SDA_MASK BIT(1)
+static void hibmc_set_i2c_signal(void *data, u32 mask, int value) +{
- struct hibmc_connector *hibmc_connector = data;
- struct hibmc_drm_private *priv = to_hibmc_drm_private(hibmc_connector->base.dev);
- u32 tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
- if (value) {
tmp_dir &= ~mask;
writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
- } else {
u32 tmp_data = readl(priv->mmio + GPIO_DATA);
tmp_data &= ~mask;
writel(tmp_data, priv->mmio + GPIO_DATA);
tmp_dir |= mask;
writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
- }
+}
+static int hibmc_get_i2c_signal(void *data, u32 mask) +{
- struct hibmc_connector *hibmc_connector = data;
- struct hibmc_drm_private *priv = to_hibmc_drm_private(hibmc_connector->base.dev);
- u32 tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
- if ((tmp_dir & mask) != mask) {
tmp_dir &= ~mask;
writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
- }
- return (readl(priv->mmio + GPIO_DATA) & mask) ? 1 : 0;
+}
+static void hibmc_ddc_setsda(void *data, int state) +{
- hibmc_set_i2c_signal(data, I2C_SDA_MASK, state);
+}
+static void hibmc_ddc_setscl(void *data, int state) +{
- hibmc_set_i2c_signal(data, I2C_SCL_MASK, state);
+}
+static int hibmc_ddc_getsda(void *data) +{
- return hibmc_get_i2c_signal(data, I2C_SDA_MASK);
+}
+static int hibmc_ddc_getscl(void *data) +{
- return hibmc_get_i2c_signal(data, I2C_SCL_MASK);
+}
+int hibmc_ddc_create(struct drm_device *drm_dev,
struct hibmc_connector *connector)
+{
- connector->adapter.owner = THIS_MODULE;
- connector->adapter.class = I2C_CLASS_DDC;
- snprintf(connector->adapter.name, I2C_NAME_SIZE, "HIS i2c bit bus");
- connector->adapter.dev.parent = &drm_dev->pdev->dev;
- i2c_set_adapdata(&connector->adapter, connector);
- connector->adapter.algo_data = &connector->bit_data;
- connector->bit_data.udelay = 20;
- connector->bit_data.timeout = usecs_to_jiffies(2000);
- connector->bit_data.data = connector;
- connector->bit_data.setsda = hibmc_ddc_setsda;
- connector->bit_data.setscl = hibmc_ddc_setscl;
- connector->bit_data.getsda = hibmc_ddc_getsda;
- connector->bit_data.getscl = hibmc_ddc_getscl;
- return i2c_bit_add_bus(&connector->adapter);
+} diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index 90319a902..3f176d500 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -59,11 +59,24 @@ static int hibmc_valid_mode(int w, int h) static int hibmc_connector_get_modes(struct drm_connector *connector) { int count;
- void *edid;
- struct hibmc_connector *hibmc_connector = to_hibmc_connector(connector);
- edid = drm_get_edid(connector, &hibmc_connector->adapter);
- if (edid) {
drm_connector_update_edid_property(connector, edid);
count = drm_add_edid_modes(connector, edid);
if (count)
goto out;
- }
- drm_connector_update_edid_property(connector, NULL);
- count = drm_add_modes_noedid(connector, 1920, 1200);
- count = drm_add_modes_noedid(connector,
connector->dev->mode_config.max_width,
drm_set_preferred_mode(connector, 1024, 768);connector->dev->mode_config.max_height);
+out:
- kfree(edid); return count;
}
@@ -86,6 +99,14 @@ hibmc_connector_best_encoder(struct drm_connector *connector) return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]); }
+static void hibmc_connector_destroy(struct drm_connector *connector) +{
- struct hibmc_connector *hibmc_connector = to_hibmc_connector(connector);
- i2c_del_adapter(&hibmc_connector->adapter);
- drm_connector_cleanup(connector);
+}
static const struct drm_connector_helper_funcs hibmc_connector_helper_funcs = { .get_modes = hibmc_connector_get_modes, @@ -95,7 +116,7 @@ static const struct drm_connector_helper_funcs
static const struct drm_connector_funcs hibmc_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .destroy = hibmc_connector_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@ -155,21 +176,15 @@ static const struct drm_encoder_funcs hibmc_encoder_funcs = { int hibmc_vdac_init(struct hibmc_drm_private *priv) { struct drm_device *dev = priv->dev;
- struct drm_encoder *encoder;
- struct drm_connector *connector;
- struct hibmc_connector *hibmc_connector = &priv->connector;
- struct drm_encoder *encoder = &priv->encoder;
- struct drm_connector *connector = &hibmc_connector->base; int ret;
- connector = hibmc_connector_init(priv);
- if (IS_ERR(connector)) {
DRM_ERROR("failed to create connector: %ld\n",
PTR_ERR(connector));
return PTR_ERR(connector);
- }
- encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL);
- if (!encoder) {
DRM_ERROR("failed to alloc memory when init encoder\n");
return -ENOMEM;
ret = hibmc_ddc_create(dev, hibmc_connector);
if (ret) {
DRM_ERROR("failed to create ddc: %d\n", ret);
return ret;
}
encoder->possible_crtcs = 0x1;
@@ -181,6 +196,18 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) }
drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
ret = drm_connector_init_with_ddc(dev, connector,
&hibmc_connector_funcs,
DRM_MODE_CONNECTOR_VGA,
&hibmc_connector->adapter);
if (ret) {
DRM_ERROR("failed to init connector: %d\n", ret);
return ret;
}
drm_connector_helper_add(connector, &hibmc_connector_helper_funcs);
drm_connector_attach_encoder(connector, encoder);
return 0;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 97ea41dc6..b9efb4564 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -998,6 +998,18 @@ struct drm_connector { * [0]: progressive, [1]: interlaced */ int audio_latency[2];
- /**
* @ddc: associated ddc adapter.
* A connector usually has its associated ddc adapter. If a driver uses
* this field, then an appropriate symbolic link is created in connector
* sysfs directory to make it easy for the user to tell which i2c
* adapter is for a particular display.
*
* The field should be set by calling drm_connector_init_with_ddc().
*/
- struct i2c_adapter *ddc;
- /**
- @null_edid_counter: track sinks that give us all zeros for the EDID.
- Needed to workaround some HW bugs where we get all 0s
@@ -1083,6 +1095,11 @@ int drm_connector_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type); +int drm_connector_init_with_ddc(struct drm_device *dev,
struct drm_connector *connector,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc);
int drm_connector_register(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector); int drm_connector_attach_encoder(struct drm_connector *connector, diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h new file mode 100644 index 000000000..8d3ed2834 --- /dev/null +++ b/include/drm/drm_probe_helper.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT
+#ifndef __DRM_PROBE_HELPER_H__ +#define __DRM_PROBE_HELPER_H__
+#include <linux/types.h>
+struct drm_connector; +struct drm_device; +struct drm_modeset_acquire_ctx;
+int drm_helper_probe_single_connector_modes(struct drm_connector
*connector, uint32_t maxX,
uint32_t maxY);
+int drm_helper_probe_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force);
+void drm_kms_helper_poll_init(struct drm_device *dev); +void drm_kms_helper_poll_fini(struct drm_device *dev); +bool drm_helper_hpd_irq_event(struct drm_device *dev); +void drm_kms_helper_hotplug_event(struct drm_device *dev);
+void drm_kms_helper_poll_disable(struct drm_device *dev); +void drm_kms_helper_poll_enable(struct drm_device *dev); +bool drm_kms_helper_is_poll_worker(void);
+#endif