diff --git a/drivers/mfd/display-serdes/core.h b/drivers/mfd/display-serdes/core.h index f51c7d8e609e..b905cbdc79b8 100644 --- a/drivers/mfd/display-serdes/core.h +++ b/drivers/mfd/display-serdes/core.h @@ -404,6 +404,7 @@ struct serdes { struct kthread_delayed_work reg_check_work; bool use_reg_check_work; + bool dual_link; bool split_mode_enable; unsigned int reg_hw; unsigned int reg_use; @@ -459,6 +460,7 @@ void serdes_destroy_debugfs(struct serdes *serdes); extern struct serdes_chip_data serdes_bu18tl82_data; extern struct serdes_chip_data serdes_bu18rl82_data; extern struct serdes_chip_data serdes_max96745_data; +extern struct serdes_chip_data serdes_max96749_data; extern struct serdes_chip_data serdes_max96752_data; extern struct serdes_chip_data serdes_max96755_data; extern struct serdes_chip_data serdes_max96772_data; diff --git a/drivers/mfd/display-serdes/gpio.h b/drivers/mfd/display-serdes/gpio.h index 404e86354607..bb87511eb63f 100644 --- a/drivers/mfd/display-serdes/gpio.h +++ b/drivers/mfd/display-serdes/gpio.h @@ -43,6 +43,7 @@ enum serdes_id { ROHM_ID_BU18RL82, MAXIM_ID_MAX96745, + MAXIM_ID_MAX96749, MAXIM_ID_MAX96752, MAXIM_ID_MAX96755, MAXIM_ID_MAX96772, @@ -107,6 +108,35 @@ enum max96745_gpio_list { MAXIM_MAX96745_MFP25, }; +enum max96749_gpio_list { + MAXIM_MAX96749_MFP0 = 0, + MAXIM_MAX96749_MFP1, + MAXIM_MAX96749_MFP2, + MAXIM_MAX96749_MFP3, + MAXIM_MAX96749_MFP4, + MAXIM_MAX96749_MFP5, + MAXIM_MAX96749_MFP6, + MAXIM_MAX96749_MFP7, + MAXIM_MAX96749_MFP8, + MAXIM_MAX96749_MFP9, + MAXIM_MAX96749_MFP10, + MAXIM_MAX96749_MFP11, + MAXIM_MAX96749_MFP12, + MAXIM_MAX96749_MFP13, + MAXIM_MAX96749_MFP14, + MAXIM_MAX96749_MFP15, + MAXIM_MAX96749_MFP16, + MAXIM_MAX96749_MFP17, + MAXIM_MAX96749_MFP18, + MAXIM_MAX96749_MFP19, + MAXIM_MAX96749_MFP20, + MAXIM_MAX96749_MFP21, + MAXIM_MAX96749_MFP22, + MAXIM_MAX96749_MFP23, + MAXIM_MAX96749_MFP24, + MAXIM_MAX96749_MFP25, +}; + enum max96752_gpio_list { MAXIM_MAX96752_GPIO0 = 0, MAXIM_MAX96752_GPIO1, diff --git a/drivers/mfd/display-serdes/maxim/Kconfig b/drivers/mfd/display-serdes/maxim/Kconfig index e889dcd0bf82..fe34367ae86d 100644 --- a/drivers/mfd/display-serdes/maxim/Kconfig +++ b/drivers/mfd/display-serdes/maxim/Kconfig @@ -17,6 +17,12 @@ config SERDES_DISPLAY_CHIP_MAXIM_MAX96745 help To support maxim max96745 display serdes. +config SERDES_DISPLAY_CHIP_MAXIM_MAX96749 + tristate "maxim max96749 serdes" + default y + help + To support maxim max96749 display serdes. + config SERDES_DISPLAY_CHIP_MAXIM_MAX96752 tristate "maxim max96752 serdes" default y diff --git a/drivers/mfd/display-serdes/maxim/Makefile b/drivers/mfd/display-serdes/maxim/Makefile index 349233deda38..9fade01a4049 100644 --- a/drivers/mfd/display-serdes/maxim/Makefile +++ b/drivers/mfd/display-serdes/maxim/Makefile @@ -3,6 +3,7 @@ # maxim display serdes drivers configuration # obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745) += maxim-max96745.o +obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96749) += maxim-max96749.o obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752) += maxim-max96752.o obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755) += maxim-max96755.o obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96772) += maxim-max96772.o diff --git a/drivers/mfd/display-serdes/maxim/maxim-max96749.c b/drivers/mfd/display-serdes/maxim/maxim-max96749.c new file mode 100644 index 000000000000..0c9de2ace88d --- /dev/null +++ b/drivers/mfd/display-serdes/maxim/maxim-max96749.c @@ -0,0 +1,1028 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * maxim-max96749.c -- I2C register interface access for max96749 serdes chip + * + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + * + * Author: ZITONG CAI + */ + +#include "../core.h" +#include "maxim-max96749.h" + +static bool max96749_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x0076: + case 0x0086: + case 0x0100: + case 0x0200 ... 0x02ce: + case 0x7000: + case 0x7070: + case 0x7074: + return false; + default: + return true; + } +} + +static struct regmap_config max96749_regmap_config = { + .name = "max96749", + .reg_bits = 16, + .val_bits = 8, + .max_register = 0x8000, + .volatile_reg = max96749_volatile_reg, + .cache_type = REGCACHE_RBTREE, +}; + +struct serdes_function_data { + u8 gpio_out_dis:1; + u8 gpio_io_rx_en:1; + u8 gpio_tx_en_a:1; + u8 gpio_tx_en_b:1; + u8 gpio_rx_en_a:1; + u8 gpio_rx_en_b:1; + u8 gpio_tx_id; + u8 gpio_rx_id; +}; + +struct config_desc { + u16 reg; + u8 mask; + u8 val; +}; + +struct serdes_group_data { + const struct config_desc *configs; + int num_configs; +}; + +static int MAX96749_MFP0_pins[] = {0}; +static int MAX96749_MFP1_pins[] = {1}; +static int MAX96749_MFP2_pins[] = {2}; +static int MAX96749_MFP3_pins[] = {3}; +static int MAX96749_MFP4_pins[] = {4}; +static int MAX96749_MFP5_pins[] = {5}; +static int MAX96749_MFP6_pins[] = {6}; +static int MAX96749_MFP7_pins[] = {7}; + +static int MAX96749_MFP8_pins[] = {8}; +static int MAX96749_MFP9_pins[] = {9}; +static int MAX96749_MFP10_pins[] = {10}; +static int MAX96749_MFP11_pins[] = {11}; +static int MAX96749_MFP12_pins[] = {12}; +static int MAX96749_MFP13_pins[] = {13}; +static int MAX96749_MFP14_pins[] = {14}; +static int MAX96749_MFP15_pins[] = {15}; + +static int MAX96749_MFP16_pins[] = {16}; +static int MAX96749_MFP17_pins[] = {17}; +static int MAX96749_MFP18_pins[] = {18}; +static int MAX96749_MFP19_pins[] = {19}; +static int MAX96749_MFP20_pins[] = {20}; +static int MAX96749_MFP21_pins[] = {21}; +static int MAX96749_MFP22_pins[] = {22}; +static int MAX96749_MFP23_pins[] = {23}; + +static int MAX96749_MFP24_pins[] = {24}; +static int MAX96749_MFP25_pins[] = {25}; +static int MAX96749_I2C_pins[] = {3, 7}; +static int MAX96749_UART_pins[] = {3, 7}; + +#define GROUP_DESC(nm) \ +{ \ + .name = #nm, \ + .pins = nm ## _pins, \ + .num_pins = ARRAY_SIZE(nm ## _pins), \ +} + +static const char * const serdes_gpio_groups[] = { + "MAX96749_MFP0", "MAX96749_MFP1", "MAX96749_MFP2", "MAX96749_MFP3", + "MAX96749_MFP4", "MAX96749_MFP5", "MAX96749_MFP6", "MAX96749_MFP7", + + "MAX96749_MFP8", "MAX96749_MFP9", "MAX96749_MFP10", "MAX96749_MFP11", + "MAX96749_MFP12", "MAX96749_MFP13", "MAX96749_MFP14", "MAX96749_MFP15", + + "MAX96749_MFP16", "MAX96749_MFP17", "MAX96749_MFP18", "MAX96749_MFP19", + "MAX96749_MFP20", "MAX96749_MFP21", "MAX96749_MFP22", "MAX96749_MFP23", + + "MAX96749_MFP24", "MAX96749_MFP25", +}; + +static const char *MAX96749_I2C_groups[] = { "MAX96749_I2C" }; +static const char *MAX96749_UART_groups[] = { "MAX96749_UART" }; + +#define FUNCTION_DESC(nm) \ +{ \ + .name = #nm, \ + .group_names = nm##_groups, \ + .num_group_names = ARRAY_SIZE(nm##_groups), \ +} \ + +#define FUNCTION_DESC_GPIO_OUTPUT_A(id) \ +{ \ + .name = "SER_TXID"#id"_TO_DES_LINKA", \ + .group_names = serdes_gpio_groups, \ + .num_group_names = ARRAY_SIZE(serdes_gpio_groups), \ + .data = (void *)(const struct serdes_function_data []) { \ + { .gpio_out_dis = 1, .gpio_tx_en_a = 1, \ + .gpio_io_rx_en = 1, .gpio_tx_id = id } \ + }, \ +} \ + +#define FUNCTION_DESC_GPIO_OUTPUT_B(id) \ +{ \ + .name = "SER_TXID"#id"_TO_DES_LINKB", \ + .group_names = serdes_gpio_groups, \ + .num_group_names = ARRAY_SIZE(serdes_gpio_groups), \ + .data = (void *)(const struct serdes_function_data []) { \ + { .gpio_out_dis = 1, .gpio_tx_en_b = 1, \ + .gpio_io_rx_en = 1, .gpio_tx_id = id } \ + }, \ +} \ + +#define FUNCTION_DESC_GPIO_INPUT_A(id) \ +{ \ + .name = "DES_RXID"#id"_TO_SER_LINKA", \ + .group_names = serdes_gpio_groups, \ + .num_group_names = ARRAY_SIZE(serdes_gpio_groups), \ + .data = (void *)(const struct serdes_function_data []) { \ + { .gpio_rx_en_a = 1, .gpio_rx_id = id } \ + }, \ +} \ + +#define FUNCTION_DESC_GPIO_INPUT_B(id) \ +{ \ + .name = "DES_RXID"#id"_TO_SER_LINKB", \ + .group_names = serdes_gpio_groups, \ + .num_group_names = ARRAY_SIZE(serdes_gpio_groups), \ + .data = (void *)(const struct serdes_function_data []) { \ + { .gpio_rx_en_b = 1, .gpio_rx_id = id } \ + }, \ +} \ + +#define FUNCTION_DESC_GPIO() \ +{ \ + .name = "MAX96749_GPIO", \ + .group_names = serdes_gpio_groups, \ + .num_group_names = ARRAY_SIZE(serdes_gpio_groups), \ + .data = (void *)(const struct serdes_function_data []) { \ + { } \ + }, \ +} \ + +static struct pinctrl_pin_desc max96749_pins_desc[] = { + PINCTRL_PIN(MAXIM_MAX96749_MFP0, "MAX96749_MFP0"), + PINCTRL_PIN(MAXIM_MAX96749_MFP1, "MAX96749_MFP1"), + PINCTRL_PIN(MAXIM_MAX96749_MFP2, "MAX96749_MFP2"), + PINCTRL_PIN(MAXIM_MAX96749_MFP3, "MAX96749_MFP3"), + PINCTRL_PIN(MAXIM_MAX96749_MFP4, "MAX96749_MFP4"), + PINCTRL_PIN(MAXIM_MAX96749_MFP5, "MAX96749_MFP5"), + PINCTRL_PIN(MAXIM_MAX96749_MFP6, "MAX96749_MFP6"), + PINCTRL_PIN(MAXIM_MAX96749_MFP7, "MAX96749_MFP7"), + + PINCTRL_PIN(MAXIM_MAX96749_MFP8, "MAX96749_MFP8"), + PINCTRL_PIN(MAXIM_MAX96749_MFP9, "MAX96749_MFP9"), + PINCTRL_PIN(MAXIM_MAX96749_MFP10, "MAX96749_MFP10"), + PINCTRL_PIN(MAXIM_MAX96749_MFP11, "MAX96749_MFP11"), + PINCTRL_PIN(MAXIM_MAX96749_MFP12, "MAX96749_MFP12"), + PINCTRL_PIN(MAXIM_MAX96749_MFP13, "MAX96749_MFP13"), + PINCTRL_PIN(MAXIM_MAX96749_MFP14, "MAX96749_MFP14"), + PINCTRL_PIN(MAXIM_MAX96749_MFP15, "MAX96749_MFP15"), + + PINCTRL_PIN(MAXIM_MAX96749_MFP16, "MAX96749_MFP16"), + PINCTRL_PIN(MAXIM_MAX96749_MFP17, "MAX96749_MFP17"), + PINCTRL_PIN(MAXIM_MAX96749_MFP18, "MAX96749_MFP18"), + PINCTRL_PIN(MAXIM_MAX96749_MFP19, "MAX96749_MFP19"), + PINCTRL_PIN(MAXIM_MAX96749_MFP20, "MAX96749_MFP20"), + PINCTRL_PIN(MAXIM_MAX96749_MFP21, "MAX96749_MFP21"), + PINCTRL_PIN(MAXIM_MAX96749_MFP22, "MAX96749_MFP22"), + PINCTRL_PIN(MAXIM_MAX96749_MFP23, "MAX96749_MFP23"), + + PINCTRL_PIN(MAXIM_MAX96749_MFP24, "MAX96749_MFP24"), + PINCTRL_PIN(MAXIM_MAX96749_MFP25, "MAX96749_MFP25"), +}; + +static struct group_desc max96749_groups_desc[] = { + GROUP_DESC(MAX96749_MFP0), + GROUP_DESC(MAX96749_MFP1), + GROUP_DESC(MAX96749_MFP2), + GROUP_DESC(MAX96749_MFP3), + GROUP_DESC(MAX96749_MFP4), + GROUP_DESC(MAX96749_MFP5), + GROUP_DESC(MAX96749_MFP6), + GROUP_DESC(MAX96749_MFP7), + + GROUP_DESC(MAX96749_MFP8), + GROUP_DESC(MAX96749_MFP9), + GROUP_DESC(MAX96749_MFP10), + GROUP_DESC(MAX96749_MFP11), + GROUP_DESC(MAX96749_MFP12), + GROUP_DESC(MAX96749_MFP13), + GROUP_DESC(MAX96749_MFP14), + GROUP_DESC(MAX96749_MFP15), + + GROUP_DESC(MAX96749_MFP16), + GROUP_DESC(MAX96749_MFP17), + GROUP_DESC(MAX96749_MFP18), + GROUP_DESC(MAX96749_MFP19), + GROUP_DESC(MAX96749_MFP20), + GROUP_DESC(MAX96749_MFP21), + GROUP_DESC(MAX96749_MFP22), + GROUP_DESC(MAX96749_MFP23), + + GROUP_DESC(MAX96749_MFP24), + GROUP_DESC(MAX96749_MFP25), + + GROUP_DESC(MAX96749_I2C), + GROUP_DESC(MAX96749_UART), +}; + +static struct function_desc max96749_functions_desc[] = { + FUNCTION_DESC_GPIO_INPUT_A(0), + FUNCTION_DESC_GPIO_INPUT_A(1), + FUNCTION_DESC_GPIO_INPUT_A(2), + FUNCTION_DESC_GPIO_INPUT_A(3), + FUNCTION_DESC_GPIO_INPUT_A(4), + FUNCTION_DESC_GPIO_INPUT_A(5), + FUNCTION_DESC_GPIO_INPUT_A(6), + FUNCTION_DESC_GPIO_INPUT_A(7), + + FUNCTION_DESC_GPIO_INPUT_A(8), + FUNCTION_DESC_GPIO_INPUT_A(9), + FUNCTION_DESC_GPIO_INPUT_A(10), + FUNCTION_DESC_GPIO_INPUT_A(11), + FUNCTION_DESC_GPIO_INPUT_A(12), + FUNCTION_DESC_GPIO_INPUT_A(13), + FUNCTION_DESC_GPIO_INPUT_A(14), + FUNCTION_DESC_GPIO_INPUT_A(15), + + FUNCTION_DESC_GPIO_INPUT_A(16), + FUNCTION_DESC_GPIO_INPUT_A(17), + FUNCTION_DESC_GPIO_INPUT_A(18), + FUNCTION_DESC_GPIO_INPUT_A(19), + FUNCTION_DESC_GPIO_INPUT_A(20), + FUNCTION_DESC_GPIO_INPUT_A(21), + FUNCTION_DESC_GPIO_INPUT_A(22), + FUNCTION_DESC_GPIO_INPUT_A(23), + + FUNCTION_DESC_GPIO_INPUT_A(24), + FUNCTION_DESC_GPIO_INPUT_A(25), + + FUNCTION_DESC_GPIO_OUTPUT_A(0), + FUNCTION_DESC_GPIO_OUTPUT_A(1), + FUNCTION_DESC_GPIO_OUTPUT_A(2), + FUNCTION_DESC_GPIO_OUTPUT_A(3), + FUNCTION_DESC_GPIO_OUTPUT_A(4), + FUNCTION_DESC_GPIO_OUTPUT_A(5), + FUNCTION_DESC_GPIO_OUTPUT_A(6), + FUNCTION_DESC_GPIO_OUTPUT_A(7), + + FUNCTION_DESC_GPIO_OUTPUT_A(8), + FUNCTION_DESC_GPIO_OUTPUT_A(9), + FUNCTION_DESC_GPIO_OUTPUT_A(10), + FUNCTION_DESC_GPIO_OUTPUT_A(11), + FUNCTION_DESC_GPIO_OUTPUT_A(12), + FUNCTION_DESC_GPIO_OUTPUT_A(13), + FUNCTION_DESC_GPIO_OUTPUT_A(14), + FUNCTION_DESC_GPIO_OUTPUT_A(15), + + FUNCTION_DESC_GPIO_OUTPUT_A(16), + FUNCTION_DESC_GPIO_OUTPUT_A(17), + FUNCTION_DESC_GPIO_OUTPUT_A(18), + FUNCTION_DESC_GPIO_OUTPUT_A(19), + FUNCTION_DESC_GPIO_OUTPUT_A(20), + FUNCTION_DESC_GPIO_OUTPUT_A(21), + FUNCTION_DESC_GPIO_OUTPUT_A(22), + FUNCTION_DESC_GPIO_OUTPUT_A(23), + + FUNCTION_DESC_GPIO_OUTPUT_A(24), + FUNCTION_DESC_GPIO_OUTPUT_A(25), + + FUNCTION_DESC_GPIO_INPUT_B(0), + FUNCTION_DESC_GPIO_INPUT_B(1), + FUNCTION_DESC_GPIO_INPUT_B(2), + FUNCTION_DESC_GPIO_INPUT_B(3), + FUNCTION_DESC_GPIO_INPUT_B(4), + FUNCTION_DESC_GPIO_INPUT_B(5), + FUNCTION_DESC_GPIO_INPUT_B(6), + FUNCTION_DESC_GPIO_INPUT_B(7), + + FUNCTION_DESC_GPIO_INPUT_B(8), + FUNCTION_DESC_GPIO_INPUT_B(9), + FUNCTION_DESC_GPIO_INPUT_B(10), + FUNCTION_DESC_GPIO_INPUT_B(11), + FUNCTION_DESC_GPIO_INPUT_B(12), + FUNCTION_DESC_GPIO_INPUT_B(13), + FUNCTION_DESC_GPIO_INPUT_B(14), + FUNCTION_DESC_GPIO_INPUT_B(15), + + FUNCTION_DESC_GPIO_INPUT_B(16), + FUNCTION_DESC_GPIO_INPUT_B(17), + FUNCTION_DESC_GPIO_INPUT_B(18), + FUNCTION_DESC_GPIO_INPUT_B(19), + FUNCTION_DESC_GPIO_INPUT_B(20), + FUNCTION_DESC_GPIO_INPUT_B(21), + FUNCTION_DESC_GPIO_INPUT_B(22), + FUNCTION_DESC_GPIO_INPUT_B(23), + + FUNCTION_DESC_GPIO_INPUT_B(24), + FUNCTION_DESC_GPIO_INPUT_B(25), + + FUNCTION_DESC_GPIO_OUTPUT_B(0), + FUNCTION_DESC_GPIO_OUTPUT_B(1), + FUNCTION_DESC_GPIO_OUTPUT_B(2), + FUNCTION_DESC_GPIO_OUTPUT_B(3), + FUNCTION_DESC_GPIO_OUTPUT_B(4), + FUNCTION_DESC_GPIO_OUTPUT_B(5), + FUNCTION_DESC_GPIO_OUTPUT_B(6), + FUNCTION_DESC_GPIO_OUTPUT_B(7), + + FUNCTION_DESC_GPIO_OUTPUT_B(8), + FUNCTION_DESC_GPIO_OUTPUT_B(9), + FUNCTION_DESC_GPIO_OUTPUT_B(10), + FUNCTION_DESC_GPIO_OUTPUT_B(11), + FUNCTION_DESC_GPIO_OUTPUT_B(12), + FUNCTION_DESC_GPIO_OUTPUT_B(13), + FUNCTION_DESC_GPIO_OUTPUT_B(14), + FUNCTION_DESC_GPIO_OUTPUT_B(15), + + FUNCTION_DESC_GPIO_OUTPUT_B(16), + FUNCTION_DESC_GPIO_OUTPUT_B(17), + FUNCTION_DESC_GPIO_OUTPUT_B(18), + FUNCTION_DESC_GPIO_OUTPUT_B(19), + FUNCTION_DESC_GPIO_OUTPUT_B(20), + FUNCTION_DESC_GPIO_OUTPUT_B(21), + FUNCTION_DESC_GPIO_OUTPUT_B(22), + FUNCTION_DESC_GPIO_OUTPUT_B(23), + + FUNCTION_DESC_GPIO_OUTPUT_B(24), + FUNCTION_DESC_GPIO_OUTPUT_B(25), + + FUNCTION_DESC_GPIO(), + + FUNCTION_DESC(MAX96749_I2C), + FUNCTION_DESC(MAX96749_UART), +}; + +static struct serdes_chip_pinctrl_info max96749_pinctrl_info = { + .pins = max96749_pins_desc, + .num_pins = ARRAY_SIZE(max96749_pins_desc), + .groups = max96749_groups_desc, + .num_groups = ARRAY_SIZE(max96749_groups_desc), + .functions = max96749_functions_desc, + .num_functions = ARRAY_SIZE(max96749_functions_desc), +}; + +static bool max96749_vid_tx_active(struct serdes *serdes) +{ + u32 val; + int i = 0, ret = 0; + + for (i = 0; i < 5; i++) { + ret = serdes_reg_read(serdes, 0x0107, &val); + if (!ret) + break; + + SERDES_DBG_CHIP("serdes %s: false val=%d i=%d ret=%d\n", __func__, val, i, ret); + msleep(20); + } + + if (ret) { + SERDES_DBG_CHIP("serdes %s: false val=%d ret=%d\n", __func__, val, ret); + return false; + } + + if (!FIELD_GET(VID_TX_ACTIVE_A | VID_TX_ACTIVE_B, val)) { + SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val); + return false; + } + + return true; +} + +static int max96749_bridge_init(struct serdes *serdes) +{ + if (max96749_vid_tx_active(serdes)) { + extcon_set_state(serdes->extcon, EXTCON_JACK_VIDEO_OUT, true); + pr_info("serdes %s, extcon is true state=%d\n", __func__, serdes->extcon->state); + } else { + pr_info("serdes %s, extcon is false\n", __func__); + } + + return 0; +} + +static bool max96749_bridge_link_locked(struct serdes *serdes) +{ + u32 val = 0, i; + + if (serdes->lock_gpio) { + for (i = 0; i < 3; i++) { + val = gpiod_get_value_cansleep(serdes->lock_gpio); + if (val) + break; + msleep(20); + } + + SERDES_DBG_CHIP("%s:%s-%s, gpio %s\n", __func__, dev_name(serdes->dev), + serdes->chip_data->name, (val) ? "locked" : "unlocked"); + if (val) + return true; + } + + if (serdes_reg_read(serdes, 0x0013, &val)) { + SERDES_DBG_CHIP("serdes %s: unlocked val=0x%x\n", __func__, val); + return false; + } + + if (!FIELD_GET(LOCKED, val)) { + SERDES_DBG_CHIP("serdes %s: unlocked val=0x%x\n", __func__, val); + return false; + } + + SERDES_DBG_CHIP("%s: serdes reg locked 0x%x\n", __func__, val); + + return true; +} + +static int max96749_select(struct serdes *serdes, int link) +{ + int ret; + u32 i, status; + struct serdes *deser; + struct drm_panel *panel; + struct serdes_panel *serdes_panel; + + /*0076 for linkA and 0086 for linkB*/ + if (link == SER_DUAL_LINK) { + panel = serdes->serdes_bridge->panel; + serdes_panel = container_of(panel, struct serdes_panel, panel); + deser = serdes_panel->parent; + + serdes_reg_write(deser, 0x10, 0x00); + serdes_set_bits(serdes, 0x45, DUAL_LINK_MODE, + FIELD_PREP(DUAL_LINK_MODE, 1)); + serdes_set_bits(serdes, 0x0076, DIS_REM_CC, + FIELD_PREP(DIS_REM_CC, 0)); + serdes_set_bits(serdes, 0x0086, DIS_REM_CC, + FIELD_PREP(DIS_REM_CC, 0)); + SERDES_DBG_CHIP("%s: serdes %s change to use dual link\n", + __func__, serdes->chip_data->name); + } else if (link == SER_LINKA) { + serdes_set_bits(serdes, 0x0076, DIS_REM_CC, + FIELD_PREP(DIS_REM_CC, 0)); + serdes_set_bits(serdes, 0x0086, DIS_REM_CC, + FIELD_PREP(DIS_REM_CC, 1)); + SERDES_DBG_CHIP("%s: only enable %s remote i2c of linkA\n", __func__, + serdes->chip_data->name); + } else if (link == SER_LINKB) { + serdes_set_bits(serdes, 0x0076, DIS_REM_CC, + FIELD_PREP(DIS_REM_CC, 1)); + serdes_set_bits(serdes, 0x0086, DIS_REM_CC, + FIELD_PREP(DIS_REM_CC, 0)); + SERDES_DBG_CHIP("%s: only enable %s remote i2c of linkB\n", __func__, + serdes->chip_data->name); + } else if (link == SER_SPLITTER_MODE) { + serdes_set_bits(serdes, 0x0076, DIS_REM_CC, + FIELD_PREP(DIS_REM_CC, 0)); + serdes_set_bits(serdes, 0x0086, DIS_REM_CC, + FIELD_PREP(DIS_REM_CC, 0)); + SERDES_DBG_CHIP("%s: enable %s remote i2c of linkA and linkB\n", __func__, + serdes->chip_data->name); + } + + for (i = 0; i < 80; i++) { + mdelay(5); + ret = serdes_reg_read(serdes, 0x0021, &status); + if (ret) + continue; + + if (serdes->dual_link && link != SER_DUAL_LINK) + return 0; + + switch (link) { + case SER_DUAL_LINK: + case SER_SPLITTER_MODE: + if ((status & LINKA_LOCKED) && + (status & LINKB_LOCKED)) + goto out; + break; + case SER_LINKA: + if (status & LINKA_LOCKED) + goto out; + break; + case SER_LINKB: + if (status & LINKB_LOCKED) + goto out; + break; + } + } + + dev_info(serdes->dev, "%s: link lock timeout, mode=%d val=0x%x\n", + __func__, link, status); + return -1; + +out: + dev_info(serdes->dev, "%s: link locked, mode=%d, val=0x%x\n", + __func__, link, status); + + return 0; +} + +static int max96749_deselect(struct serdes *serdes, int link) +{ + struct serdes *deser; + struct drm_panel *panel; + struct serdes_panel *serdes_panel; + struct serdes_bridge *serdes_bridge = serdes->serdes_bridge; + + if (link == SER_DUAL_LINK) { + panel = serdes_bridge->panel; + serdes_panel = container_of(panel, struct serdes_panel, panel); + deser = serdes_panel->parent; + + serdes_reg_write(deser, 0x10, 0x00); + serdes_set_bits(serdes, 0x45, DUAL_LINK_MODE, + FIELD_PREP(DUAL_LINK_MODE, 0)); + + SERDES_DBG_CHIP("%s: serdes %s disable dual link\n", __func__, + serdes->chip_data->name); + + } + + return 0; +} + +static struct serdes_chip_split_ops max96749_split_ops = { + .select = max96749_select, + .deselect = max96749_deselect, +}; + +static int max96749_bridge_attach(struct serdes *serdes) +{ + int ret; + enum drm_connector_status status; + + if (max96749_bridge_link_locked(serdes)) + status = connector_status_connected; + else { + status = connector_status_disconnected; + if (serdes->dual_link) { + dev_info(serdes->dev, "serdes disconnect, try to change dual link\n"); + + ret = max96749_select(serdes, SER_DUAL_LINK); + if (ret) { + dev_info(serdes->dev, "serdes disconnect, close dual link\n"); + max96749_deselect(serdes, SER_DUAL_LINK); + } else { + status = connector_status_connected; + } + } + } + + serdes->serdes_bridge->status = status; + + return 0; +} + +static enum drm_connector_status +max96749_bridge_detect(struct serdes *serdes) +{ + struct serdes_bridge *serdes_bridge = serdes->serdes_bridge; + enum drm_connector_status status = connector_status_connected; + + if (!drm_kms_helper_is_poll_worker()) + return serdes_bridge->status; + + if (!max96749_bridge_link_locked(serdes)) { + status = connector_status_disconnected; + goto out; + } + + if (extcon_get_state(serdes->extcon, EXTCON_JACK_VIDEO_OUT)) { + u32 dprx_trn_status2; + + if (atomic_cmpxchg(&serdes_bridge->triggered, 1, 0)) { + status = connector_status_disconnected; + SERDES_DBG_CHIP("1 status=%d state=%d\n", status, serdes->extcon->state); + goto out; + } + + if (serdes_reg_read(serdes, 0x641a, &dprx_trn_status2)) { + status = connector_status_disconnected; + SERDES_DBG_CHIP("2 status=%d state=%d\n", status, serdes->extcon->state); + goto out; + } + + if ((dprx_trn_status2 & DPRX_TRAIN_STATE) != DPRX_TRAIN_STATE) { + dev_err(serdes->dev, "Training State: 0x%lx\n", + FIELD_GET(DPRX_TRAIN_STATE, dprx_trn_status2)); + status = connector_status_disconnected; + SERDES_DBG_CHIP("3 status=%d state=%d\n", status, serdes->extcon->state); + goto out; + } + } else { + atomic_set(&serdes_bridge->triggered, 0); + SERDES_DBG_CHIP("4 status=%d state=%d\n", status, serdes->extcon->state); + } + + if (serdes_bridge->next_bridge && (serdes_bridge->next_bridge->ops & DRM_BRIDGE_OP_DETECT)) + return drm_bridge_detect(serdes_bridge->next_bridge); + +out: + serdes_bridge->status = status; + SERDES_DBG_CHIP("%s:%s %s, status=%d state=%d\n", __func__, dev_name(serdes->dev), + serdes->chip_data->name, + status, serdes->extcon->state); + return status; +} + +static int max96749_bridge_pre_enable(struct serdes *serdes) +{ + int ret = 0; + struct serdes_bridge *serdes_bridge = serdes->serdes_bridge; + + if (serdes->dual_link) { + ret = max96749_select(serdes, SER_DUAL_LINK); + if (ret) + atomic_set(&serdes_bridge->triggered, 1); + } + + SERDES_DBG_CHIP("%s: serdes chip %s ret=%d\n", __func__, serdes->chip_data->name, ret); + return ret; +} + +static int max96749_bridge_enable(struct serdes *serdes) +{ + int ret = 0; + + return ret; +} + +static int max96749_bridge_disable(struct serdes *serdes) +{ + int ret = 0; + + if (serdes->dual_link) + max96749_deselect(serdes, SER_DUAL_LINK); + + SERDES_DBG_CHIP("%s: serdes chip %s ret=%d\n", __func__, serdes->chip_data->name, ret); + return ret; +} + +static int max96749_bridge_post_disable(struct serdes *serdes) +{ + int ret = 0; + + return ret; +} + +static struct serdes_chip_bridge_ops max96749_bridge_ops = { + .init = max96749_bridge_init, + .attach = max96749_bridge_attach, + .detect = max96749_bridge_detect, + .pre_enable = max96749_bridge_pre_enable, + .enable = max96749_bridge_enable, + .disable = max96749_bridge_disable, + .post_disable = max96749_bridge_post_disable, +}; + +static int max96749_pinctrl_set_mux(struct serdes *serdes, + unsigned int function, unsigned int group) +{ + struct serdes_pinctrl *pinctrl = serdes->pinctrl; + struct function_desc *func; + struct group_desc *grp; + int i; + + func = pinmux_generic_get_function(pinctrl->pctl, function); + if (!func) + return -EINVAL; + + grp = pinctrl_generic_get_group(pinctrl->pctl, group); + if (!grp) + return -EINVAL; + + SERDES_DBG_CHIP("%s: serdes chip %s func=%s data=%p group=%s data=%p, num_pin=%d\n", + __func__, serdes->chip_data->name, + func->name, func->data, grp->name, grp->data, grp->num_pins); + + if (func->data) { + struct serdes_function_data *data = func->data; + + for (i = 0; i < grp->num_pins; i++) { + serdes_set_bits(serdes, + GPIO_A_REG(grp->pins[i] - pinctrl->pin_base), + GPIO_OUT_DIS, + FIELD_PREP(GPIO_OUT_DIS, data->gpio_out_dis)); + serdes_set_bits(serdes, + GPIO_B_REG(grp->pins[i] - pinctrl->pin_base), + OUT_TYPE, + FIELD_PREP(OUT_TYPE, 1)); + if (data->gpio_tx_en_a || data->gpio_tx_en_b) + serdes_set_bits(serdes, + GPIO_B_REG(grp->pins[i] - pinctrl->pin_base), + GPIO_TX_ID, + FIELD_PREP(GPIO_TX_ID, data->gpio_tx_id)); + if (data->gpio_rx_en_a || data->gpio_rx_en_b) + serdes_set_bits(serdes, + GPIO_C_REG(grp->pins[i] - pinctrl->pin_base), + GPIO_RX_ID, + FIELD_PREP(GPIO_RX_ID, data->gpio_rx_id)); + serdes_set_bits(serdes, + GPIO_D_REG(grp->pins[i] - pinctrl->pin_base), + GPIO_TX_EN_A | GPIO_TX_EN_B | GPIO_IO_RX_EN | + GPIO_RX_EN_A | GPIO_RX_EN_B, + FIELD_PREP(GPIO_TX_EN_A, data->gpio_tx_en_a) | + FIELD_PREP(GPIO_TX_EN_B, data->gpio_tx_en_b) | + FIELD_PREP(GPIO_RX_EN_A, data->gpio_rx_en_a) | + FIELD_PREP(GPIO_RX_EN_B, data->gpio_rx_en_b) | + FIELD_PREP(GPIO_IO_RX_EN, data->gpio_io_rx_en)); + } + } + + return 0; +} + +static int max96749_pinctrl_config_get(struct serdes *serdes, + unsigned int pin, unsigned long *config) +{ + enum pin_config_param param = pinconf_to_config_param(*config); + unsigned int gpio_a_reg, gpio_b_reg; + u16 arg = 0; + + serdes_reg_read(serdes, GPIO_A_REG(pin), &gpio_a_reg); + serdes_reg_read(serdes, GPIO_B_REG(pin), &gpio_b_reg); + + SERDES_DBG_CHIP("%s: serdes chip %s pin=%d param=%d\n", + __func__, serdes->chip_data->name, pin, param); + + switch (param) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (FIELD_GET(OUT_TYPE, gpio_b_reg)) + return -EINVAL; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + if (!FIELD_GET(OUT_TYPE, gpio_b_reg)) + return -EINVAL; + break; + case PIN_CONFIG_BIAS_DISABLE: + if (FIELD_GET(PULL_UPDN_SEL, gpio_b_reg) != 0) + return -EINVAL; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (FIELD_GET(PULL_UPDN_SEL, gpio_b_reg) != 1) + return -EINVAL; + switch (FIELD_GET(RES_CFG, gpio_a_reg)) { + case 0: + arg = 40000; + break; + case 1: + arg = 10000; + break; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (FIELD_GET(PULL_UPDN_SEL, gpio_b_reg) != 2) + return -EINVAL; + switch (FIELD_GET(RES_CFG, gpio_a_reg)) { + case 0: + arg = 40000; + break; + case 1: + arg = 10000; + break; + } + break; + case PIN_CONFIG_OUTPUT: + if (FIELD_GET(GPIO_OUT_DIS, gpio_a_reg)) + return -EINVAL; + + arg = FIELD_GET(GPIO_OUT, gpio_a_reg); + break; + default: + return -EOPNOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int max96749_pinctrl_config_set(struct serdes *serdes, + unsigned int pin, unsigned long *configs, + unsigned int num_configs) +{ + enum pin_config_param param; + u32 arg; + u8 res_cfg; + int i; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + SERDES_DBG_CHIP("%s: serdes chip %s pin=%d param=%d\n", __func__, + serdes->chip_data->name, pin, param); + + switch (param) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + serdes_set_bits(serdes, GPIO_B_REG(pin), + OUT_TYPE, FIELD_PREP(OUT_TYPE, 0)); + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + serdes_set_bits(serdes, GPIO_B_REG(pin), + OUT_TYPE, FIELD_PREP(OUT_TYPE, 1)); + break; + case PIN_CONFIG_BIAS_DISABLE: + serdes_set_bits(serdes, GPIO_C_REG(pin), + PULL_UPDN_SEL, + FIELD_PREP(PULL_UPDN_SEL, 0)); + break; + case PIN_CONFIG_BIAS_PULL_UP: + switch (arg) { + case 40000: + res_cfg = 0; + break; + case 1000000: + res_cfg = 1; + break; + default: + return -EINVAL; + } + + serdes_set_bits(serdes, GPIO_A_REG(pin), + RES_CFG, FIELD_PREP(RES_CFG, res_cfg)); + serdes_set_bits(serdes, GPIO_C_REG(pin), + PULL_UPDN_SEL, + FIELD_PREP(PULL_UPDN_SEL, 1)); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + switch (arg) { + case 40000: + res_cfg = 0; + break; + case 1000000: + res_cfg = 1; + break; + default: + return -EINVAL; + } + + serdes_set_bits(serdes, GPIO_A_REG(pin), + RES_CFG, FIELD_PREP(RES_CFG, res_cfg)); + serdes_set_bits(serdes, GPIO_C_REG(pin), + PULL_UPDN_SEL, + FIELD_PREP(PULL_UPDN_SEL, 2)); + break; + case PIN_CONFIG_OUTPUT: + serdes_set_bits(serdes, GPIO_A_REG(pin), + GPIO_OUT_DIS | GPIO_OUT, + FIELD_PREP(GPIO_OUT_DIS, 0) | + FIELD_PREP(GPIO_OUT, arg)); + break; + default: + return -EOPNOTSUPP; + } + } + + return 0; +} + +static struct serdes_chip_pinctrl_ops max96749_pinctrl_ops = { + .pin_config_get = max96749_pinctrl_config_get, + .pin_config_set = max96749_pinctrl_config_set, + .set_mux = max96749_pinctrl_set_mux, +}; + +static int max96749_gpio_direction_input(struct serdes *serdes, int gpio) +{ + return 0; +} + +static int max96749_gpio_direction_output(struct serdes *serdes, int gpio, int value) +{ + return 0; +} + +static int max96749_gpio_get_level(struct serdes *serdes, int gpio) +{ + return 0; +} + +static int max96749_gpio_set_level(struct serdes *serdes, int gpio, int value) +{ + return 0; +} + +static int max96749_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config) +{ + return 0; +} + +static int max96749_gpio_to_irq(struct serdes *serdes, int gpio) +{ + return 0; +} + +static struct serdes_chip_gpio_ops max96749_gpio_ops = { + .direction_input = max96749_gpio_direction_input, + .direction_output = max96749_gpio_direction_output, + .get_level = max96749_gpio_get_level, + .set_level = max96749_gpio_set_level, + .set_config = max96749_gpio_set_config, + .to_irq = max96749_gpio_to_irq, +}; + +static const struct check_reg_data max96749_improtant_reg[10] = { + { + "MAX96749 LINK LOCK", + { 0x0013, (1 << 3) }, + }, { + "MAX96749 LINKA LOCK", + { 0x002A, (1 << 0) }, + }, { + "MAX96749 LINKB LOCK", + { 0x0034, (1 << 0) }, + }, { + "MAX96749 X PCLK DET", + { 0x0102, (1 << 7) }, + }, { + "MAX96749 Y PCLK DET", + { 0x0112, (1 << 7) }, + }, +}; + +static int max96749_check_reg(struct serdes *serdes) +{ + int i = 0, ret = 0; + unsigned int val = 0; + + for (i = 0; i < ARRAY_SIZE(max96749_improtant_reg); i++) { + if (!max96749_improtant_reg[i].seq.reg) + break; + + ret = serdes_reg_read(serdes, max96749_improtant_reg[i].seq.reg, &val); + if (!ret && !(val & max96749_improtant_reg[i].seq.def) + && (!atomic_read(&serdes->flag_early_suspend))) + dev_info(serdes->dev, "warning %s %s reg[0x%x] = 0x%x\n", __func__, + max96749_improtant_reg[i].name, + max96749_improtant_reg[i].seq.reg, val); + } + + return 0; +} + +static struct serdes_check_reg_ops max96749_check_reg_ops = { + .check_reg = max96749_check_reg, +}; + +static int max96749_pm_suspend(struct serdes *serdes) +{ + return 0; +} + +static int max96749_pm_resume(struct serdes *serdes) +{ + return 0; +} + +static struct serdes_chip_pm_ops max96749_pm_ops = { + .suspend = max96749_pm_suspend, + .resume = max96749_pm_resume, +}; + +static int max96749_irq_lock_handle(struct serdes *serdes) +{ + return IRQ_HANDLED; +} + +static int max96749_irq_err_handle(struct serdes *serdes) +{ + return IRQ_HANDLED; +} + +static struct serdes_chip_irq_ops max96749_irq_ops = { + .lock_handle = max96749_irq_lock_handle, + .err_handle = max96749_irq_err_handle, +}; + +struct serdes_chip_data serdes_max96749_data = { + .name = "max96749", + .serdes_type = TYPE_SER, + .serdes_id = MAXIM_ID_MAX96749, + .connector_type = DRM_MODE_CONNECTOR_eDP, + .regmap_config = &max96749_regmap_config, + .pinctrl_info = &max96749_pinctrl_info, + .bridge_ops = &max96749_bridge_ops, + .pinctrl_ops = &max96749_pinctrl_ops, + .gpio_ops = &max96749_gpio_ops, + .split_ops = &max96749_split_ops, + .check_ops = &max96749_check_reg_ops, + .pm_ops = &max96749_pm_ops, + .irq_ops = &max96749_irq_ops, +}; +EXPORT_SYMBOL_GPL(serdes_max96749_data); + +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/display-serdes/maxim/maxim-max96749.h b/drivers/mfd/display-serdes/maxim/maxim-max96749.h new file mode 100644 index 000000000000..6351a61cb657 --- /dev/null +++ b/drivers/mfd/display-serdes/maxim/maxim-max96749.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * maxim-max96749.h -- register define for max96749 chip + * + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. + * + * Author: ZITONG CAI + * + */ + +#ifndef __MFD_SERDES_MAXIM_MAX96745_H__ +#define __MFD_SERDES_MAXIM_MAX96745_H__ + +#include + +#define GPIO_A_REG(gpio) (0x0200 + ((gpio) * 8)) +#define GPIO_B_REG(gpio) (0x0201 + ((gpio) * 8)) +#define GPIO_C_REG(gpio) (0x0202 + ((gpio) * 8)) +#define GPIO_D_REG(gpio) (0x0203 + ((gpio) * 8)) + +/* 0005h */ +#define PU_LF3 BIT(3) +#define PU_LF2 BIT(2) +#define PU_LF1 BIT(1) +#define PU_LF0 BIT(0) + +/* 0010h */ +#define RESET_ALL BIT(7) +#define SLEEP BIT(3) + +/* 0011h */ +#define CXTP_B BIT(2) +#define CXTP_A BIT(0) + +/* 0013h */ +#define LOCKED BIT(3) +#define ERROR BIT(2) + +/* 0021h */ +#define LINKA_LOCKED BIT(2) +#define LINKB_LOCKED BIT(3) + +/* 0026h */ +#define LF_0 GENMASK(2, 0) +#define LF_1 GENMASK(6, 4) + +/* 0027h */ +#define LF_2 GENMASK(2, 0) +#define LF_3 GENMASK(6, 4) + +/* 0028h, 0032h */ +#define LINK_EN BIT(7) +#define TX_RATE GENMASK(3, 2) + +/* 0029h, 0033h */ +#define RESET_LINK BIT(0) +#define RESET_ONESHOT BIT(1) + +/* 0045h */ +#define DUAL_LINK_MODE BIT(1) + +/* 002Ah, 0034h */ +#define LINK_LOCKED BIT(0) + +/* 0076h, 0086h */ +#define DIS_REM_CC BIT(7) + +/* 0100h */ +#define VID_LINK_SEL GENMASK(2, 1) +#define VID_TX_EN BIT(0) + +/* 0101h */ +#define BPP GENMASK(5, 0) + +/* 0102h */ +#define PCLKDET_A BIT(7) +#define DRIFT_ERR_A BIT(6) +#define OVERFLOW_A BIT(5) +#define FIFO_WARN_A BIT(4) +#define LIM_HEART BIT(2) + +/* 0107h */ +#define VID_TX_ACTIVE_B BIT(7) +#define VID_TX_ACTIVE_A BIT(6) + +/* 0108h */ +#define PCLKDET_B BIT(7) +#define DRIFT_ERR_B BIT(6) +#define OVERFLOW_B BIT(5) +#define FIFO_WARN_B BIT(4) + +/* 0200h */ +#define RES_CFG BIT(7) +#define TX_COM_EN BIT(5) +#define GPIO_OUT BIT(4) +#define GPIO_IN BIT(3) +#define GPIO_OUT_DIS BIT(0) + +/* 0201h */ +#define PULL_UPDN_SEL GENMASK(7, 6) +#define OUT_TYPE BIT(5) +#define GPIO_TX_ID GENMASK(4, 0) + +/* 0202h */ +#define OVR_RES_CFG BIT(7) +#define IO_EDGE_RATE GENMASK(6, 5) +#define GPIO_RX_ID GENMASK(4, 0) + +/* 0203h */ +#define GPIO_IO_RX_EN BIT(5) +#define GPIO_OUT_LGC BIT(4) +#define GPIO_RX_EN_B BIT(3) +#define GPIO_TX_EN_B BIT(2) +#define GPIO_RX_EN_A BIT(1) +#define GPIO_TX_EN_A BIT(0) + +/* 0750h */ +#define FRCZEROPAD GENMASK(7, 6) +#define FRCZPEN BIT(5) +#define FRCSDGAIN BIT(4) +#define FRCSDEN BIT(3) +#define FRCGAIN GENMASK(2, 1) +#define FRCEN BIT(0) + +/* 0751h */ +#define FRCDATAWIDTH BIT(3) +#define FRCASYNCEN BIT(2) +#define FRCHSPOL BIT(1) +#define FRCVSPOL BIT(0) + +/* 0752h */ +#define FRCDCMODE GENMASK(1, 0) + +/* 641Ah */ +#define DPRX_TRAIN_STATE GENMASK(7, 4) + +/* 7000h */ +#define LINK_ENABLE BIT(0) + +/* 7070h */ +#define MAX_LANE_COUNT GENMASK(7, 0) + +/* 7074h */ +#define MAX_LINK_RATE GENMASK(7, 0) + +#endif diff --git a/drivers/mfd/display-serdes/serdes-bridge-split.c b/drivers/mfd/display-serdes/serdes-bridge-split.c index 2a40cc37722a..e44c51736157 100644 --- a/drivers/mfd/display-serdes/serdes-bridge-split.c +++ b/drivers/mfd/display-serdes/serdes-bridge-split.c @@ -327,6 +327,7 @@ static const struct of_device_id serdes_bridge_split_of_match[] = { { .compatible = "rohm,bu18tl82-bridge-split", }, { .compatible = "rohm,bu18rl82-bridge-split", }, { .compatible = "maxim,max96745-bridge-split", }, + { .compatible = "maxim,max96749-bridge-split", }, { .compatible = "maxim,max96755-bridge-split", }, { .compatible = "maxim,max96752-bridge-split", }, { .compatible = "maxim,max96789-bridge-split", }, diff --git a/drivers/mfd/display-serdes/serdes-bridge.c b/drivers/mfd/display-serdes/serdes-bridge.c index 9a6f9bf8aef4..381c4085938a 100644 --- a/drivers/mfd/display-serdes/serdes-bridge.c +++ b/drivers/mfd/display-serdes/serdes-bridge.c @@ -326,6 +326,7 @@ static const struct of_device_id serdes_bridge_of_match[] = { { .compatible = "rohm,bu18tl82-bridge", }, { .compatible = "rohm,bu18rl82-bridge", }, { .compatible = "maxim,max96745-bridge", }, + { .compatible = "maxim,max96749-bridge", }, { .compatible = "maxim,max96755-bridge", }, { .compatible = "maxim,max96789-bridge", }, { .compatible = "rockchip,rkx111-bridge", }, diff --git a/drivers/mfd/display-serdes/serdes-core.c b/drivers/mfd/display-serdes/serdes-core.c index da45502f254f..cbd0cd02eb72 100644 --- a/drivers/mfd/display-serdes/serdes-core.c +++ b/drivers/mfd/display-serdes/serdes-core.c @@ -49,6 +49,21 @@ static const struct mfd_cell serdes_max96745_devs[] = { }, }; +static const struct mfd_cell serdes_max96749_devs[] = { + { + .name = "serdes-pinctrl", + .of_compatible = "maxim,max96749-pinctrl", + }, + { + .name = "serdes-bridge", + .of_compatible = "maxim,max96749-bridge", + }, + { + .name = "serdes-bridge-split", + .of_compatible = "maxim,max96749-bridge-split", + }, +}; + static const struct mfd_cell serdes_max96755_devs[] = { { .name = "serdes-pinctrl", @@ -364,6 +379,10 @@ int serdes_device_init(struct serdes *serdes) serdes_devs = serdes_max96745_devs; mfd_num = ARRAY_SIZE(serdes_max96745_devs); break; + case MAXIM_ID_MAX96749: + serdes_devs = serdes_max96749_devs; + mfd_num = ARRAY_SIZE(serdes_max96749_devs); + break; case MAXIM_ID_MAX96752: serdes_devs = serdes_max96752_devs; mfd_num = ARRAY_SIZE(serdes_max96752_devs); diff --git a/drivers/mfd/display-serdes/serdes-gpio.c b/drivers/mfd/display-serdes/serdes-gpio.c index 1c49cf55fc28..eaaeb60eac34 100644 --- a/drivers/mfd/display-serdes/serdes-gpio.c +++ b/drivers/mfd/display-serdes/serdes-gpio.c @@ -209,6 +209,7 @@ static const struct of_device_id serdes_gpio_of_match[] = { { .compatible = "rohm,bu18tl82-gpio", }, { .compatible = "rohm,bu18rl82-gpio", }, { .compatible = "maxim,max96745-gpio", }, + { .compatible = "maxim,max96749-gpio", }, { .compatible = "maxim,max96752-gpio", }, { .compatible = "maxim,max96755-gpio", }, { .compatible = "maxim,max96772-gpio", }, diff --git a/drivers/mfd/display-serdes/serdes-i2c.c b/drivers/mfd/display-serdes/serdes-i2c.c index feb2d8f3460c..dfe709332adb 100644 --- a/drivers/mfd/display-serdes/serdes-i2c.c +++ b/drivers/mfd/display-serdes/serdes-i2c.c @@ -310,6 +310,8 @@ static int serdes_get_init_seq(struct serdes *serdes) return err; } + serdes->dual_link = of_property_read_bool(dev->of_node, "dual-link"); + /* init ser register(not des register) more early if uboot logo disabled */ serdes->route_enable = of_property_read_bool(dev->of_node, "route-enable"); if ((!serdes->route_enable) && (serdes->chip_data->serdes_type == TYPE_SER)) { @@ -540,6 +542,9 @@ static const struct of_device_id serdes_of_match[] = { #if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745) { .compatible = "maxim,max96745", .data = &serdes_max96745_data }, #endif +#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96749) + { .compatible = "maxim,max96749", .data = &serdes_max96749_data }, +#endif #if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752) { .compatible = "maxim,max96752", .data = &serdes_max96752_data }, #endif diff --git a/drivers/mfd/display-serdes/serdes-pinctrl.c b/drivers/mfd/display-serdes/serdes-pinctrl.c index 27605732ff66..d16852ddd3c6 100644 --- a/drivers/mfd/display-serdes/serdes-pinctrl.c +++ b/drivers/mfd/display-serdes/serdes-pinctrl.c @@ -30,6 +30,13 @@ static const struct mfd_cell serdes_gpio_max96745_devs[] = { }, }; +static const struct mfd_cell serdes_gpio_max96749_devs[] = { + { + .name = "serdes-gpio", + .of_compatible = "maxim,max96749-gpio", + }, +}; + static const struct mfd_cell serdes_gpio_max96755_devs[] = { { .name = "serdes-gpio", @@ -173,6 +180,10 @@ static int serdes_pinctrl_gpio_init(struct serdes *serdes) serdes_devs = serdes_gpio_max96745_devs; mfd_num = ARRAY_SIZE(serdes_gpio_max96745_devs); break; + case MAXIM_ID_MAX96749: + serdes_devs = serdes_gpio_max96749_devs; + mfd_num = ARRAY_SIZE(serdes_gpio_max96749_devs); + break; case MAXIM_ID_MAX96752: serdes_devs = serdes_gpio_max96752_devs; mfd_num = ARRAY_SIZE(serdes_gpio_max96752_devs);