aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3407-drm-amd-display-refactor-gpio-to-allocate-hw_contain.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3407-drm-amd-display-refactor-gpio-to-allocate-hw_contain.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3407-drm-amd-display-refactor-gpio-to-allocate-hw_contain.patch812
1 files changed, 812 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3407-drm-amd-display-refactor-gpio-to-allocate-hw_contain.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3407-drm-amd-display-refactor-gpio-to-allocate-hw_contain.patch
new file mode 100644
index 00000000..dc20f736
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3407-drm-amd-display-refactor-gpio-to-allocate-hw_contain.patch
@@ -0,0 +1,812 @@
+From c88c69c8487f0424fa6a08b35d3a92fa4b01cf91 Mon Sep 17 00:00:00 2001
+From: Su Sung Chung <Su.Chung@amd.com>
+Date: Mon, 8 Jul 2019 11:31:39 -0400
+Subject: [PATCH 3407/4256] drm/amd/display: refactor gpio to allocate
+ hw_container in constructor
+
+[why]
+if dynamic allocation fails during gpio_open, it will cause crash due to
+page fault.
+
+[how]
+handle allocation when gpio object gets created and prevent from calling
+gpio_open if allocation failed
+
+Signed-off-by: Su Sung Chung <Su.Chung@amd.com>
+Reviewed-by: Jun Lei <Jun.Lei@amd.com>
+Acked-by: Leo Li <sunpeng.li@amd.com>
+---
+ .../dc/gpio/dce110/hw_factory_dce110.c | 18 +++--
+ .../dc/gpio/dce120/hw_factory_dce120.c | 14 ++--
+ .../display/dc/gpio/dce80/hw_factory_dce80.c | 14 ++--
+ .../display/dc/gpio/dcn10/hw_factory_dcn10.c | 12 +--
+ .../display/dc/gpio/dcn20/hw_factory_dcn20.c | 12 +--
+ .../dc/gpio/diagnostics/hw_factory_diag.c | 9 +--
+ .../gpu/drm/amd/display/dc/gpio/gpio_base.c | 74 ++++++++++++++++++-
+ .../drm/amd/display/dc/gpio/gpio_service.c | 51 ++++++-------
+ .../drm/amd/display/dc/gpio/gpio_service.h | 6 +-
+ drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c | 26 ++++---
+ drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h | 5 +-
+ .../gpu/drm/amd/display/dc/gpio/hw_factory.h | 48 ++++++------
+ .../gpu/drm/amd/display/dc/gpio/hw_generic.c | 32 ++++----
+ .../gpu/drm/amd/display/dc/gpio/hw_generic.h | 6 +-
+ drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c | 31 ++++----
+ drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h | 5 +-
+ drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h | 10 +++
+ .../drm/amd/display/include/gpio_interface.h | 9 +++
+ 18 files changed, 245 insertions(+), 137 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c b/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c
+index 20d81bca119c..66e4841f41e4 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c
+@@ -24,9 +24,15 @@
+ */
+
+ #include "dm_services.h"
++
+ #include "include/gpio_types.h"
+ #include "../hw_factory.h"
+
++#include "../hw_gpio.h"
++#include "../hw_ddc.h"
++#include "../hw_hpd.h"
++#include "../hw_generic.h"
++
+ #include "hw_factory_dce110.h"
+
+ #include "dce/dce_11_0_d.h"
+@@ -143,12 +149,12 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en)
+ }
+
+ static const struct hw_factory_funcs funcs = {
+- .create_ddc_data = dal_hw_ddc_create,
+- .create_ddc_clock = dal_hw_ddc_create,
+- .create_generic = NULL,
+- .create_hpd = dal_hw_hpd_create,
+- .create_sync = NULL,
+- .create_gsl = NULL,
++ .init_ddc_data = dal_hw_ddc_init,
++ .init_generic = NULL,
++ .init_hpd = dal_hw_hpd_init,
++ .get_ddc_pin = dal_hw_ddc_get_pin,
++ .get_hpd_pin = dal_hw_hpd_get_pin,
++ .get_generic_pin = NULL,
+ .define_hpd_registers = define_hpd_registers,
+ .define_ddc_registers = define_ddc_registers
+ };
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c b/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c
+index ea3f888e5c65..cf98aa827a9a 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c
+@@ -27,10 +27,10 @@
+ #include "include/gpio_types.h"
+ #include "../hw_factory.h"
+
+-
+ #include "../hw_gpio.h"
+ #include "../hw_ddc.h"
+ #include "../hw_hpd.h"
++#include "../hw_generic.h"
+
+ #include "hw_factory_dce120.h"
+
+@@ -164,12 +164,12 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en)
+
+ /* fucntion table */
+ static const struct hw_factory_funcs funcs = {
+- .create_ddc_data = dal_hw_ddc_create,
+- .create_ddc_clock = dal_hw_ddc_create,
+- .create_generic = NULL,
+- .create_hpd = dal_hw_hpd_create,
+- .create_sync = NULL,
+- .create_gsl = NULL,
++ .init_ddc_data = dal_hw_ddc_init,
++ .init_generic = NULL,
++ .init_hpd = dal_hw_hpd_init,
++ .get_ddc_pin = dal_hw_ddc_get_pin,
++ .get_hpd_pin = dal_hw_hpd_get_pin,
++ .get_generic_pin = NULL,
+ .define_hpd_registers = define_hpd_registers,
+ .define_ddc_registers = define_ddc_registers
+ };
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c b/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c
+index 48b67866377e..496d3ffb74bb 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c
+@@ -32,10 +32,12 @@
+ #include "../hw_gpio.h"
+ #include "../hw_ddc.h"
+ #include "../hw_hpd.h"
++#include "../hw_generic.h"
+
+ #include "dce/dce_8_0_d.h"
+ #include "dce/dce_8_0_sh_mask.h"
+
++
+ #define REG(reg_name)\
+ mm ## reg_name
+
+@@ -147,12 +149,12 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en)
+ }
+
+ static const struct hw_factory_funcs funcs = {
+- .create_ddc_data = dal_hw_ddc_create,
+- .create_ddc_clock = dal_hw_ddc_create,
+- .create_generic = NULL,
+- .create_hpd = dal_hw_hpd_create,
+- .create_sync = NULL,
+- .create_gsl = NULL,
++ .init_ddc_data = dal_hw_ddc_init,
++ .init_generic = NULL,
++ .init_hpd = dal_hw_hpd_init,
++ .get_ddc_pin = dal_hw_ddc_get_pin,
++ .get_hpd_pin = dal_hw_hpd_get_pin,
++ .get_generic_pin = NULL,
+ .define_hpd_registers = define_hpd_registers,
+ .define_ddc_registers = define_ddc_registers
+ };
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c
+index 5711f30cf848..b38c96c9fed3 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c
+@@ -196,12 +196,12 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en)
+
+ /* fucntion table */
+ static const struct hw_factory_funcs funcs = {
+- .create_ddc_data = dal_hw_ddc_create,
+- .create_ddc_clock = dal_hw_ddc_create,
+- .create_generic = dal_hw_generic_create,
+- .create_hpd = dal_hw_hpd_create,
+- .create_sync = NULL,
+- .create_gsl = NULL,
++ .init_ddc_data = dal_hw_ddc_init,
++ .init_generic = dal_hw_generic_init,
++ .init_hpd = dal_hw_hpd_init,
++ .get_ddc_pin = dal_hw_ddc_get_pin,
++ .get_hpd_pin = dal_hw_hpd_get_pin,
++ .get_generic_pin = dal_hw_generic_get_pin,
+ .define_hpd_registers = define_hpd_registers,
+ .define_ddc_registers = define_ddc_registers,
+ .define_generic_registers = define_generic_registers
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c
+index afb7c0f111bf..43a440385b43 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c
+@@ -212,12 +212,12 @@ static void define_generic_registers(struct hw_gpio_pin *pin, uint32_t en)
+
+ /* fucntion table */
+ static const struct hw_factory_funcs funcs = {
+- .create_ddc_data = dal_hw_ddc_create,
+- .create_ddc_clock = dal_hw_ddc_create,
+- .create_generic = dal_hw_generic_create,
+- .create_hpd = dal_hw_hpd_create,
+- .create_sync = NULL,
+- .create_gsl = NULL,
++ .init_ddc_data = dal_hw_ddc_init,
++ .init_generic = dal_hw_generic_init,
++ .init_hpd = dal_hw_hpd_init,
++ .get_ddc_pin = dal_hw_ddc_get_pin,
++ .get_hpd_pin = dal_hw_hpd_get_pin,
++ .get_generic_pin = dal_hw_generic_get_pin,
+ .define_hpd_registers = define_hpd_registers,
+ .define_ddc_registers = define_ddc_registers,
+ .define_generic_registers = define_generic_registers,
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c b/drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c
+index f15288c3986e..df68430aeb0c 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c
+@@ -42,12 +42,9 @@
+
+ /* function table */
+ static const struct hw_factory_funcs funcs = {
+- .create_ddc_data = NULL,
+- .create_ddc_clock = NULL,
+- .create_generic = NULL,
+- .create_hpd = NULL,
+- .create_sync = NULL,
+- .create_gsl = NULL,
++ .init_ddc_data = NULL,
++ .init_generic = NULL,
++ .init_hpd = NULL,
+ };
+
+ void dal_hw_factory_diag_fpga_init(struct hw_factory *factory)
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c
+index cf76ea2d9f5a..c6f1a7c3affd 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c
+@@ -65,10 +65,14 @@ enum gpio_result dal_gpio_open_ex(
+ return GPIO_RESULT_ALREADY_OPENED;
+ }
+
++ // No action if allocation failed during gpio construct
++ if (!gpio->hw_container.ddc) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++ }
+ gpio->mode = mode;
+
+- return dal_gpio_service_open(
+- gpio->service, gpio->id, gpio->en, mode, &gpio->pin);
++ return dal_gpio_service_open(gpio);
+ }
+
+ enum gpio_result dal_gpio_get_value(
+@@ -229,6 +233,21 @@ enum gpio_pin_output_state dal_gpio_get_output_state(
+ return gpio->output_state;
+ }
+
++struct hw_ddc *dal_gpio_get_ddc(struct gpio *gpio)
++{
++ return gpio->hw_container.ddc;
++}
++
++struct hw_hpd *dal_gpio_get_hpd(struct gpio *gpio)
++{
++ return gpio->hw_container.hpd;
++}
++
++struct hw_generic *dal_gpio_get_generic(struct gpio *gpio)
++{
++ return gpio->hw_container.generic;
++}
++
+ void dal_gpio_close(
+ struct gpio *gpio)
+ {
+@@ -265,6 +284,30 @@ struct gpio *dal_gpio_create(
+ gpio->mode = GPIO_MODE_UNKNOWN;
+ gpio->output_state = output_state;
+
++ //initialize hw_container union based on id
++ switch (gpio->id) {
++ case GPIO_ID_DDC_DATA:
++ gpio->service->factory.funcs->init_ddc_data(&gpio->hw_container.ddc, service->ctx, id, en);
++ break;
++ case GPIO_ID_DDC_CLOCK:
++ gpio->service->factory.funcs->init_ddc_data(&gpio->hw_container.ddc, service->ctx, id, en);
++ break;
++ case GPIO_ID_GENERIC:
++ gpio->service->factory.funcs->init_generic(&gpio->hw_container.generic, service->ctx, id, en);
++ break;
++ case GPIO_ID_HPD:
++ gpio->service->factory.funcs->init_hpd(&gpio->hw_container.hpd, service->ctx, id, en);
++ break;
++ // TODO: currently gpio for sync and gsl does not get created, might need it later
++ case GPIO_ID_SYNC:
++ break;
++ case GPIO_ID_GSL:
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ gpio->pin = NULL;
++ }
++
+ return gpio;
+ }
+
+@@ -278,6 +321,33 @@ void dal_gpio_destroy(
+
+ dal_gpio_close(*gpio);
+
++ switch ((*gpio)->id) {
++ case GPIO_ID_DDC_DATA:
++ kfree((*gpio)->hw_container.ddc);
++ (*gpio)->hw_container.ddc = NULL;
++ break;
++ case GPIO_ID_DDC_CLOCK:
++ //TODO: might want to change it to init_ddc_clock
++ kfree((*gpio)->hw_container.ddc);
++ (*gpio)->hw_container.ddc = NULL;
++ break;
++ case GPIO_ID_GENERIC:
++ kfree((*gpio)->hw_container.generic);
++ (*gpio)->hw_container.generic = NULL;
++ break;
++ case GPIO_ID_HPD:
++ kfree((*gpio)->hw_container.hpd);
++ (*gpio)->hw_container.hpd = NULL;
++ break;
++ // TODO: currently gpio for sync and gsl does not get created, might need it later
++ case GPIO_ID_SYNC:
++ break;
++ case GPIO_ID_GSL:
++ break;
++ default:
++ break;
++ }
++
+ kfree(*gpio);
+
+ *gpio = NULL;
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
+index 80f938e68285..30028223f8bc 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
+@@ -288,13 +288,15 @@ enum gpio_result dal_gpio_service_unlock(
+ }
+
+ enum gpio_result dal_gpio_service_open(
+- struct gpio_service *service,
+- enum gpio_id id,
+- uint32_t en,
+- enum gpio_mode mode,
+- struct hw_gpio_pin **ptr)
++ struct gpio *gpio)
+ {
+- struct hw_gpio_pin *pin;
++ struct gpio_service *service = gpio->service;
++ enum gpio_id id = gpio->id;
++ uint32_t en = gpio->en;
++ enum gpio_mode mode = gpio->mode;
++
++ struct hw_gpio_pin **pin = &gpio->pin;
++
+
+ if (!service->busyness[id]) {
+ ASSERT_CRITICAL(false);
+@@ -308,51 +310,43 @@ enum gpio_result dal_gpio_service_open(
+
+ switch (id) {
+ case GPIO_ID_DDC_DATA:
+- pin = service->factory.funcs->create_ddc_data(
+- service->ctx, id, en);
+- service->factory.funcs->define_ddc_registers(pin, en);
++ *pin = service->factory.funcs->get_ddc_pin(gpio);
++ service->factory.funcs->define_ddc_registers(*pin, en);
+ break;
+ case GPIO_ID_DDC_CLOCK:
+- pin = service->factory.funcs->create_ddc_clock(
+- service->ctx, id, en);
+- service->factory.funcs->define_ddc_registers(pin, en);
++ *pin = service->factory.funcs->get_ddc_pin(gpio);
++ service->factory.funcs->define_ddc_registers(*pin, en);
+ break;
+ case GPIO_ID_GENERIC:
+- pin = service->factory.funcs->create_generic(
+- service->ctx, id, en);
+- service->factory.funcs->define_generic_registers(pin, en);
++ *pin = service->factory.funcs->get_generic_pin(gpio);
++ service->factory.funcs->define_generic_registers(*pin, en);
+ break;
+ case GPIO_ID_HPD:
+- pin = service->factory.funcs->create_hpd(
+- service->ctx, id, en);
+- service->factory.funcs->define_hpd_registers(pin, en);
++ *pin = service->factory.funcs->get_hpd_pin(gpio);
++ service->factory.funcs->define_hpd_registers(*pin, en);
+ break;
++
++ //TODO: gsl and sync support? create_sync and create_gsl are NULL
+ case GPIO_ID_SYNC:
+- pin = service->factory.funcs->create_sync(
+- service->ctx, id, en);
+- break;
+ case GPIO_ID_GSL:
+- pin = service->factory.funcs->create_gsl(
+- service->ctx, id, en);
+ break;
+ default:
+ ASSERT_CRITICAL(false);
+ return GPIO_RESULT_NON_SPECIFIC_ERROR;
+ }
+
+- if (!pin) {
++ if (!*pin) {
+ ASSERT_CRITICAL(false);
+ return GPIO_RESULT_NON_SPECIFIC_ERROR;
+ }
+
+- if (!pin->funcs->open(pin, mode)) {
++ if (!(*pin)->funcs->open(*pin, mode)) {
+ ASSERT_CRITICAL(false);
+- dal_gpio_service_close(service, &pin);
++ dal_gpio_service_close(service, pin);
+ return GPIO_RESULT_OPEN_FAILED;
+ }
+
+ set_pin_busy(service, id, en);
+- *ptr = pin;
+ return GPIO_RESULT_OK;
+ }
+
+@@ -374,11 +368,10 @@ void dal_gpio_service_close(
+
+ pin->funcs->close(pin);
+
+- pin->funcs->destroy(ptr);
++ *ptr = NULL;
+ }
+ }
+
+-
+ enum dc_irq_source dal_irq_get_source(
+ const struct gpio *irq)
+ {
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h
+index 0c678af75331..b9775a131ecd 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h
++++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h
+@@ -42,11 +42,7 @@ struct gpio_service {
+ };
+
+ enum gpio_result dal_gpio_service_open(
+- struct gpio_service *service,
+- enum gpio_id id,
+- uint32_t en,
+- enum gpio_mode mode,
+- struct hw_gpio_pin **ptr);
++ struct gpio *gpio);
+
+ void dal_gpio_service_close(
+ struct gpio_service *service,
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c
+index 49a99248e7f6..e1c84a2f7298 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c
+@@ -25,6 +25,7 @@
+
+ #include "dm_services.h"
+
++#include "include/gpio_interface.h"
+ #include "include/gpio_types.h"
+ #include "hw_gpio.h"
+ #include "hw_ddc.h"
+@@ -42,6 +43,8 @@
+ #define REG(reg)\
+ (ddc->regs->reg)
+
++struct gpio;
++
+ static void destruct(
+ struct hw_ddc *pin)
+ {
+@@ -224,24 +227,29 @@ static void construct(
+ ddc->base.base.funcs = &funcs;
+ }
+
+-struct hw_gpio_pin *dal_hw_ddc_create(
++void dal_hw_ddc_init(
++ struct hw_ddc **hw_ddc,
+ struct dc_context *ctx,
+ enum gpio_id id,
+ uint32_t en)
+ {
+- struct hw_ddc *pin;
+-
+ if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) {
+ ASSERT_CRITICAL(false);
+- return NULL;
++ *hw_ddc = NULL;
+ }
+
+- pin = kzalloc(sizeof(struct hw_ddc), GFP_KERNEL);
+- if (!pin) {
++ *hw_ddc = kzalloc(sizeof(struct hw_ddc), GFP_KERNEL);
++ if (!*hw_ddc) {
+ ASSERT_CRITICAL(false);
+- return NULL;
++ return;
+ }
+
+- construct(pin, id, en, ctx);
+- return &pin->base.base;
++ construct(*hw_ddc, id, en, ctx);
++}
++
++struct hw_gpio_pin *dal_hw_ddc_get_pin(struct gpio *gpio)
++{
++ struct hw_ddc *hw_ddc = dal_gpio_get_ddc(gpio);
++
++ return &hw_ddc->base.base;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h
+index 9690e2a885d7..cc30e65df431 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h
++++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h
+@@ -38,9 +38,12 @@ struct hw_ddc {
+ #define HW_DDC_FROM_BASE(hw_gpio) \
+ container_of((HW_GPIO_FROM_BASE(hw_gpio)), struct hw_ddc, base)
+
+-struct hw_gpio_pin *dal_hw_ddc_create(
++void dal_hw_ddc_init(
++ struct hw_ddc **hw_ddc,
+ struct dc_context *ctx,
+ enum gpio_id id,
+ uint32_t en);
+
++struct hw_gpio_pin *dal_hw_ddc_get_pin(struct gpio *gpio);
++
+ #endif
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h
+index 7017c9337348..e15b037f3bcd 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h
++++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h
+@@ -28,35 +28,35 @@
+
+ struct hw_gpio_pin;
+ struct hw_hpd;
++struct hw_ddc;
++struct hw_generic;
++struct gpio;
+
+ struct hw_factory {
+ uint32_t number_of_pins[GPIO_ID_COUNT];
+
+ const struct hw_factory_funcs {
+- struct hw_gpio_pin *(*create_ddc_data)(
+- struct dc_context *ctx,
+- enum gpio_id id,
+- uint32_t en);
+- struct hw_gpio_pin *(*create_ddc_clock)(
+- struct dc_context *ctx,
+- enum gpio_id id,
+- uint32_t en);
+- struct hw_gpio_pin *(*create_generic)(
+- struct dc_context *ctx,
+- enum gpio_id id,
+- uint32_t en);
+- struct hw_gpio_pin *(*create_hpd)(
+- struct dc_context *ctx,
+- enum gpio_id id,
+- uint32_t en);
+- struct hw_gpio_pin *(*create_sync)(
+- struct dc_context *ctx,
+- enum gpio_id id,
+- uint32_t en);
+- struct hw_gpio_pin *(*create_gsl)(
+- struct dc_context *ctx,
+- enum gpio_id id,
+- uint32_t en);
++ void (*init_ddc_data)(
++ struct hw_ddc **hw_ddc,
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ void (*init_generic)(
++ struct hw_generic **hw_generic,
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ void (*init_hpd)(
++ struct hw_hpd **hw_hpd,
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ struct hw_gpio_pin *(*get_hpd_pin)(
++ struct gpio *gpio);
++ struct hw_gpio_pin *(*get_ddc_pin)(
++ struct gpio *gpio);
++ struct hw_gpio_pin *(*get_generic_pin)(
++ struct gpio *gpio);
+ void (*define_hpd_registers)(
+ struct hw_gpio_pin *pin,
+ uint32_t en);
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c
+index ea0a1fc8cf23..f039c5982ac8 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c
+@@ -25,6 +25,7 @@
+
+ #include "dm_services.h"
+
++#include "include/gpio_interface.h"
+ #include "include/gpio_types.h"
+ #include "hw_gpio.h"
+ #include "hw_generic.h"
+@@ -41,6 +42,8 @@
+ #define REG(reg)\
+ (generic->regs->reg)
+
++struct gpio;
++
+ static void dal_hw_generic_construct(
+ struct hw_generic *pin,
+ enum gpio_id id,
+@@ -104,29 +107,30 @@ static void construct(
+ generic->base.base.funcs = &funcs;
+ }
+
+-struct hw_gpio_pin *dal_hw_generic_create(
++void dal_hw_generic_init(
++ struct hw_generic **hw_generic,
+ struct dc_context *ctx,
+ enum gpio_id id,
+ uint32_t en)
+ {
+- struct hw_generic *generic;
+-
+- if (id != GPIO_ID_GENERIC) {
++ if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) {
+ ASSERT_CRITICAL(false);
+- return NULL;
++ *hw_generic = NULL;
+ }
+
+- if ((en < GPIO_GENERIC_MIN) || (en > GPIO_GENERIC_MAX)) {
++ *hw_generic = kzalloc(sizeof(struct hw_generic), GFP_KERNEL);
++ if (!*hw_generic) {
+ ASSERT_CRITICAL(false);
+- return NULL;
++ return;
+ }
+
+- generic = kzalloc(sizeof(struct hw_generic), GFP_KERNEL);
+- if (!generic) {
+- ASSERT_CRITICAL(false);
+- return NULL;
+- }
++ construct(*hw_generic, id, en, ctx);
++}
++
++
++struct hw_gpio_pin *dal_hw_generic_get_pin(struct gpio *gpio)
++{
++ struct hw_generic *hw_generic = dal_gpio_get_generic(gpio);
+
+- construct(generic, id, en, ctx);
+- return &generic->base.base;
++ return &hw_generic->base.base;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.h
+index 3ea1c13e3ea6..bd6ffeb5e9df 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.h
++++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.h
+@@ -27,6 +27,7 @@
+ #define __DAL_HW_generic_H__
+
+ #include "generic_regs.h"
++#include "hw_gpio.h"
+
+ struct hw_generic {
+ struct hw_gpio base;
+@@ -38,9 +39,12 @@ struct hw_generic {
+ #define HW_GENERIC_FROM_BASE(hw_gpio) \
+ container_of((HW_GPIO_FROM_BASE(hw_gpio)), struct hw_generic, base)
+
+-struct hw_gpio_pin *dal_hw_generic_create(
++void dal_hw_generic_init(
++ struct hw_generic **hw_generic,
+ struct dc_context *ctx,
+ enum gpio_id id,
+ uint32_t en);
+
++struct hw_gpio_pin *dal_hw_generic_get_pin(struct gpio *gpio);
++
+ #endif
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c
+index 784feccc5853..88798cf3965e 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c
++++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c
+@@ -25,6 +25,7 @@
+
+ #include "dm_services.h"
+
++#include "include/gpio_interface.h"
+ #include "include/gpio_types.h"
+ #include "hw_gpio.h"
+ #include "hw_hpd.h"
+@@ -41,6 +42,8 @@
+ #define REG(reg)\
+ (hpd->regs->reg)
+
++struct gpio;
++
+ static void dal_hw_hpd_construct(
+ struct hw_hpd *pin,
+ enum gpio_id id,
+@@ -134,29 +137,29 @@ static void construct(
+ hpd->base.base.funcs = &funcs;
+ }
+
+-struct hw_gpio_pin *dal_hw_hpd_create(
++void dal_hw_hpd_init(
++ struct hw_hpd **hw_hpd,
+ struct dc_context *ctx,
+ enum gpio_id id,
+ uint32_t en)
+ {
+- struct hw_hpd *hpd;
+-
+- if (id != GPIO_ID_HPD) {
++ if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) {
+ ASSERT_CRITICAL(false);
+- return NULL;
++ *hw_hpd = NULL;
+ }
+
+- if ((en < GPIO_HPD_MIN) || (en > GPIO_HPD_MAX)) {
++ *hw_hpd = kzalloc(sizeof(struct hw_hpd), GFP_KERNEL);
++ if (!*hw_hpd) {
+ ASSERT_CRITICAL(false);
+- return NULL;
++ return;
+ }
+
+- hpd = kzalloc(sizeof(struct hw_hpd), GFP_KERNEL);
+- if (!hpd) {
+- ASSERT_CRITICAL(false);
+- return NULL;
+- }
++ construct(*hw_hpd, id, en, ctx);
++}
++
++struct hw_gpio_pin *dal_hw_hpd_get_pin(struct gpio *gpio)
++{
++ struct hw_hpd *hw_hpd = dal_gpio_get_hpd(gpio);
+
+- construct(hpd, id, en, ctx);
+- return &hpd->base.base;
++ return &hw_hpd->base.base;
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h
+index 4ab7a208f781..e7d8b3bb016c 100644
+--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h
++++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h
+@@ -38,9 +38,12 @@ struct hw_hpd {
+ #define HW_HPD_FROM_BASE(hw_gpio) \
+ container_of((HW_GPIO_FROM_BASE(hw_gpio)), struct hw_hpd, base)
+
+-struct hw_gpio_pin *dal_hw_hpd_create(
++void dal_hw_hpd_init(
++ struct hw_hpd **hw_hpd,
+ struct dc_context *ctx,
+ enum gpio_id id,
+ uint32_t en);
+
++struct hw_gpio_pin *dal_hw_hpd_get_pin(struct gpio *gpio);
++
+ #endif
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h b/drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h
+index 90d0148430fb..5253dc8b15f8 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h
+@@ -28,12 +28,22 @@
+
+ #include "gpio_types.h"
+
++
++union gpio_hw_container {
++ struct hw_ddc *ddc;
++ struct hw_generic *generic;
++ struct hw_hpd *hpd;
++};
++
+ struct gpio {
+ struct gpio_service *service;
+ struct hw_gpio_pin *pin;
+ enum gpio_id id;
+ uint32_t en;
++
++ union gpio_hw_container hw_container;
+ enum gpio_mode mode;
++
+ /* when GPIO comes from VBIOS, it has defined output state */
+ enum gpio_pin_output_state output_state;
+ };
+diff --git a/drivers/gpu/drm/amd/display/include/gpio_interface.h b/drivers/gpu/drm/amd/display/include/gpio_interface.h
+index 7de64195dc33..5e888a093c16 100644
+--- a/drivers/gpu/drm/amd/display/include/gpio_interface.h
++++ b/drivers/gpu/drm/amd/display/include/gpio_interface.h
+@@ -93,8 +93,17 @@ enum sync_source dal_gpio_get_sync_source(
+ enum gpio_pin_output_state dal_gpio_get_output_state(
+ const struct gpio *gpio);
+
++struct hw_ddc *dal_gpio_get_ddc(struct gpio *gpio);
++
++struct hw_hpd *dal_gpio_get_hpd(struct gpio *gpio);
++
++struct hw_generic *dal_gpio_get_generic(struct gpio *gpio);
++
+ /* Close the handle */
+ void dal_gpio_close(
+ struct gpio *gpio);
+
++
++
++
+ #endif
+--
+2.17.1
+