diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/extcon/extcon-qcom-spmi-misc.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-truly-r63350.c | 726 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/core.c | 57 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/pm_helpers.c | 46 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-usb-hs.c | 36 | ||||
-rw-r--r-- | drivers/usb/chipidea/ci.h | 3 | ||||
-rw-r--r-- | drivers/usb/chipidea/core.c | 19 | ||||
-rw-r--r-- | drivers/usb/chipidea/host.c | 7 | ||||
-rw-r--r-- | drivers/usb/chipidea/udc.c | 6 |
11 files changed, 903 insertions, 10 deletions
diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c index eb02cb962b5e..f72e90ceca53 100644 --- a/drivers/extcon/extcon-qcom-spmi-misc.c +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -123,7 +123,7 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev) if (ret) return ret; - info->id_irq = platform_get_irq_byname(pdev, "usb_id"); + info->id_irq = platform_get_irq_byname_optional(pdev, "usb_id"); if (info->id_irq > 0) { ret = devm_request_threaded_irq(dev, info->id_irq, NULL, qcom_usb_irq_handler, @@ -136,7 +136,7 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev) } } - info->vbus_irq = platform_get_irq_byname(pdev, "usb_vbus"); + info->vbus_irq = platform_get_irq_byname_optional(pdev, "usb_vbus"); if (info->vbus_irq > 0) { ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL, qcom_usb_irq_handler, diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index fd1d7e6f536b..2245fa9ca1ea 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -709,6 +709,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI Video Mode panel +config DRM_PANEL_TRULY_R65530 + tristate "Truly panel with R65530 driver IC" + depends on OF + depends on DRM_MIPI_DSI + help + Say Y here if you want to enable support for Truly DSI panel with + R65530 driver IC. + config DRM_PANEL_VISIONOX_RM69299 tristate "Visionox RM69299" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 1966404fcf7a..8733169357c7 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o +obj-$(CONFIG_DRM_PANEL_TRULY_R65530) += panel-truly-r63350.o obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o obj-$(CONFIG_DRM_PANEL_VISIONOX_VTDR6130) += panel-visionox-vtdr6130.o obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o diff --git a/drivers/gpu/drm/panel/panel-truly-r63350.c b/drivers/gpu/drm/panel/panel-truly-r63350.c new file mode 100644 index 000000000000..7d70781f6e1d --- /dev/null +++ b/drivers/gpu/drm/panel/panel-truly-r63350.c @@ -0,0 +1,726 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/pinctrl/consumer.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +static const char * const regulator_names[] = { + "iovcc", + "avdd", + "avee", +}; + +enum panel_vendor { + NOT_INITIALIZE = -1, + TRULY, + AUO, +}; + +struct cmd_set { + const u8 *payload; + size_t size; + int wait_ms; +}; + +struct truly_data { + const struct cmd_set *panel_oncmds; + unsigned int num_oncmds; + const struct cmd_set *panel_offcmds; + unsigned int num_offcmds; +}; + +struct truly_panel { + struct drm_panel panel; + struct device *dev; + struct mipi_dsi_device *dsi; + const struct truly_data *data; + + struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)]; + struct gpio_desc *reset_gpio; + + bool prepared; + bool enabled; +}; + +/* Panel vendor/type provided by bootloader */ +static enum panel_vendor vendor_from_bl = NOT_INITIALIZE; + +static int __init panel_setup(char *str) +{ + if (strstr(str, "truly_r63350")) + vendor_from_bl = TRULY; + else if (strstr(str, "auo_r63350")) + vendor_from_bl = AUO; + + return 1; +} +__setup("mdss_mdp.panel=", panel_setup); + +static inline struct truly_panel *panel_to_truly(struct drm_panel *panel) +{ + return container_of(panel, struct truly_panel, panel); +} + +static int truly_r63350_power_off(struct truly_panel *truly) +{ + gpiod_set_value(truly->reset_gpio, 1); + return regulator_bulk_disable(ARRAY_SIZE(truly->supplies), + truly->supplies); +} + +static int truly_r63350_power_on(struct truly_panel *truly) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(truly->supplies), + truly->supplies); + if (ret) + return ret; + + if (vendor_from_bl != NOT_INITIALIZE) { + /* + * If bootloader already configures the panel, we are + * done and skip panel reset below. + */ + return 0; + } + + /* Reset panel */ + gpiod_set_value(truly->reset_gpio, 0); + usleep_range(20000, 30000); + + gpiod_set_value(truly->reset_gpio, 1); + usleep_range(10000, 20000); + + gpiod_set_value(truly->reset_gpio, 0); + usleep_range(20000, 30000); + + return 0; +} + +static int truly_r63350_unprepare(struct drm_panel *panel) +{ + struct truly_panel *truly = panel_to_truly(panel); + const struct truly_data *data = truly->data; + const struct cmd_set *cmds = data->panel_offcmds; + unsigned int num_cmds = data->num_offcmds; + struct mipi_dsi_device *dsi = truly->dsi; + struct device *dev = truly->dev; + int ret; + int i; + + if (!truly->prepared) + return 0; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); + if (ret < 0) { + DRM_DEV_ERROR(dev, "set_display_off cmd failed: %d\n", ret); + return ret; + } + + /* 120ms delay required here as per DCS spec */ + msleep(120); + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); + if (ret < 0) { + DRM_DEV_ERROR(dev, "enter_sleep cmd failed: %d\n", ret); + return ret; + } + + /* Panel-off magic commands */ + for (i = 0; i < num_cmds; i++) { + ret = mipi_dsi_dcs_write_buffer(dsi, cmds[i].payload, + cmds[i].size); + if (ret < 0) { + DRM_DEV_ERROR(dev, "off cmd tx%d failed: %d\n", i, ret); + return ret; + } + + if (cmds[i].wait_ms) + msleep(cmds[i].wait_ms); + else + usleep_range(80, 100); + } + + ret = truly_r63350_power_off(truly); + if (ret < 0) { + DRM_DEV_ERROR(dev, "power_off failed: %d\n", ret); + return ret; + } + + truly->prepared = false; + + return 0; +} + +static int truly_r63350_prepare(struct drm_panel *panel) +{ + struct truly_panel *truly = panel_to_truly(panel); + const struct truly_data *data = truly->data; + const struct cmd_set *cmds = data->panel_oncmds; + unsigned int num_cmds = data->num_oncmds; + struct mipi_dsi_device *dsi = truly->dsi; + struct device *dev = truly->dev; + int ret; + int i; + + if (truly->prepared) + return 0; + + ret = truly_r63350_power_on(truly); + if (ret < 0) { + DRM_DEV_ERROR(dev, "failed to power on: %d\n", ret); + return ret; + } + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_soft_reset(dsi); + if (ret < 0) + return ret; + + usleep_range(10000, 20000); + + /* Panel-on magic commands */ + for (i = 0; i < num_cmds; i++) { + ret = mipi_dsi_dcs_write_buffer(dsi, cmds[i].payload, + cmds[i].size); + if (ret < 0) { + DRM_DEV_ERROR(dev, "on cmd tx%d failed: %d\n", i, ret); + goto power_off; + } + + if (cmds[i].wait_ms) + msleep(cmds[i].wait_ms); + else + usleep_range(80, 100); + } + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (ret < 0) { + DRM_DEV_ERROR(dev, "exit_sleep_mode cmd failed: %d\n", ret); + goto power_off; + } + + /* Per DSI spec wait 120ms after sending exit sleep DCS command */ + msleep(120); + + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); + if (ret < 0) { + DRM_DEV_ERROR(dev, "set_display_on cmd failed: %d\n", ret); + goto power_off; + } + + /* Per DSI spec wait 120ms after sending set_display_on DCS command */ + msleep(120); + + truly->prepared = true; + + return 0; + +power_off: + truly_r63350_power_off(truly); + return ret; +} + +static const struct drm_display_mode truly_fhd_mode = { + .clock = 144981, + .hdisplay = 1080, + .hsync_start = 1080 + 92, + .hsync_end = 1080 + 92 + 20, + .htotal = 1080 + 92 + 20 + 60, + .vdisplay = 1920, + .vsync_start = 1920 + 4, + .vsync_end = 1920 + 4 + 1, + .vtotal = 1920 + 4 + 1 + 5, + .flags = 0, +}; + +static int truly_r63350_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct truly_panel *truly = panel_to_truly(panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &truly_fhd_mode); + if (!mode) { + DRM_DEV_ERROR(truly->dev, + "failed to add display mode\n"); + return -ENOMEM; + } + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = 68; + connector->display_info.height_mm = 121; + + return 1; +} + +static const struct drm_panel_funcs truly_r63350_drm_funcs = { + .prepare = truly_r63350_prepare, + .unprepare = truly_r63350_unprepare, + .get_modes = truly_r63350_get_modes, +}; + +static int truly_r63350_panel_add(struct truly_panel *truly) +{ + struct device *dev = truly->dev; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(truly->supplies); i++) + truly->supplies[i].supply = regulator_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(truly->supplies), + truly->supplies); + if (ret) { + dev_err(dev, "failed to get regulator: %d\n", ret); + return ret; + } + + truly->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(truly->reset_gpio)) { + DRM_DEV_ERROR(dev, "failed to get reset gpio %ld\n", + PTR_ERR(truly->reset_gpio)); + return PTR_ERR(truly->reset_gpio); + } + + drm_panel_init(&truly->panel, dev, &truly_r63350_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&truly->panel); + if (ret) { + DRM_DEV_ERROR(dev, "failed to find backlight: %d\n", ret); + return ret; + } + + drm_panel_add(&truly->panel); + + return 0; +} + +static const u8 truly_oncmd0[] = { + 0xb0, 0x00, +}; + +static const u8 truly_oncmd1[] = { + 0xd6, 0x01, +}; + +static const u8 truly_oncmd2[] = { + 0xb3, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 truly_oncmd3[] = { + 0xb4, 0x0c, 0x00, +}; + +static const u8 truly_oncmd4[] = { + 0xb6, 0x4b, 0xdb, 0x16, +}; + +static const u8 truly_oncmd5[] = { + 0xbe, 0x00, 0x04, +}; + +static const u8 truly_oncmd6[] = { + 0xc0, 0x66, +}; + +static const u8 truly_oncmd7[] = { + 0xc1, 0x04, 0x60, 0x00, 0x20, 0xa9, 0x30, 0x20, + 0x63, 0xf0, 0xff, 0xff, 0x9b, 0x7b, 0xcf, 0xb5, + 0xff, 0xff, 0x87, 0x8c, 0x41, 0x22, 0x54, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x33, 0x03, + 0x22, 0x00, 0xff, +}; + +static const u8 truly_oncmd8[] = { + 0xc2, 0x31, 0xf7, 0x80, 0x06, 0x04, 0x00, 0x00, + 0x08, +}; + +static const u8 truly_oncmd9[] = { + 0xc3, 0x00, 0x00, 0x00, +}; + +static const u8 truly_oncmd10[] = { + 0xc4, 0x70, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x00, 0x02, +}; + +static const u8 truly_oncmd11[] = { + 0xc5, 0x00, +}; + +static const u8 truly_oncmd12[] = { + 0xc6, 0xc8, 0x3c, 0x3c, 0x07, 0x01, 0x07, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1a, 0x07, 0xc8, +}; + +static const u8 truly_oncmd13[] = { + 0xc7, 0x03, 0x15, 0x1f, 0x2a, 0x39, 0x46, 0x4e, + 0x5b, 0x3d, 0x45, 0x52, 0x5f, 0x68, 0x6d, 0x72, + 0x01, 0x15, 0x1f, 0x2a, 0x39, 0x46, 0x4e, 0x5b, + 0x3d, 0x45, 0x52, 0x5f, 0x68, 0x6d, 0x78, +}; + +static const u8 truly_oncmd14[] = { + 0xcb, 0xff, 0xe1, 0x87, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xe1, 0x87, 0xff, 0xe8, 0x00, 0x00, +}; + +static const u8 truly_oncmd15[] = { + 0xcc, 0x34, +}; + +static const u8 truly_oncmd16[] = { + 0xd0, 0x11, 0x00, 0x00, 0x56, 0xd5, 0x40, 0x19, + 0x19, 0x09, 0x00, +}; + +static const u8 truly_oncmd17[] = { + 0xd1, 0x00, 0x48, 0x16, 0x0f, +}; + +static const u8 truly_oncmd18[] = { + 0xd2, 0x5c, 0x00, 0x00, +}; + +static const u8 truly_oncmd19[] = { + 0xd3, 0x1b, 0x33, 0xbb, 0xbb, 0xb3, 0x33, 0x33, + 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0, + 0x0c, 0x4d, 0x4d, 0x33, 0x33, 0x72, 0x12, 0x8a, + 0x57, 0x3d, 0xbc, +}; + +static const u8 truly_oncmd20[] = { + 0xd5, 0x06, 0x00, 0x00, 0x01, 0x39, 0x01, 0x39, +}; + +static const u8 truly_oncmd21[] = { + 0xd8, 0x00, 0x00, 0x00, +}; + +static const u8 truly_oncmd22[] = { + 0xd9, 0x00, 0x00, 0x00, +}; + +static const u8 truly_oncmd23[] = { + 0xfd, 0x00, 0x00, 0x00, 0x30, +}; + +static const u8 truly_oncmd24[] = { + 0x35, 0x00, +}; + +static const u8 truly_oncmd25[] = { + 0x29, +}; + +static const u8 truly_oncmd26[] = { + 0x11, +}; + +static const struct cmd_set truly_oncmds[] = { + { truly_oncmd0, ARRAY_SIZE(truly_oncmd0), }, + { truly_oncmd1, ARRAY_SIZE(truly_oncmd1), }, + { truly_oncmd2, ARRAY_SIZE(truly_oncmd2), }, + { truly_oncmd3, ARRAY_SIZE(truly_oncmd3), }, + { truly_oncmd4, ARRAY_SIZE(truly_oncmd4), }, + { truly_oncmd5, ARRAY_SIZE(truly_oncmd5), }, + { truly_oncmd6, ARRAY_SIZE(truly_oncmd6), }, + { truly_oncmd7, ARRAY_SIZE(truly_oncmd7), }, + { truly_oncmd8, ARRAY_SIZE(truly_oncmd8), }, + { truly_oncmd9, ARRAY_SIZE(truly_oncmd9), }, + { truly_oncmd10, ARRAY_SIZE(truly_oncmd10), }, + { truly_oncmd11, ARRAY_SIZE(truly_oncmd11), }, + { truly_oncmd12, ARRAY_SIZE(truly_oncmd12), }, + { truly_oncmd13, ARRAY_SIZE(truly_oncmd13), }, + { truly_oncmd14, ARRAY_SIZE(truly_oncmd14), }, + { truly_oncmd15, ARRAY_SIZE(truly_oncmd15), }, + { truly_oncmd16, ARRAY_SIZE(truly_oncmd16), }, + { truly_oncmd17, ARRAY_SIZE(truly_oncmd17), }, + { truly_oncmd18, ARRAY_SIZE(truly_oncmd18), }, + { truly_oncmd19, ARRAY_SIZE(truly_oncmd19), }, + { truly_oncmd20, ARRAY_SIZE(truly_oncmd20), }, + { truly_oncmd21, ARRAY_SIZE(truly_oncmd21), }, + { truly_oncmd22, ARRAY_SIZE(truly_oncmd22), }, + { truly_oncmd23, ARRAY_SIZE(truly_oncmd23), }, + { truly_oncmd24, ARRAY_SIZE(truly_oncmd24), }, + { truly_oncmd25, ARRAY_SIZE(truly_oncmd25), 50, }, + { truly_oncmd26, ARRAY_SIZE(truly_oncmd26), 120, }, +}; + +static const u8 truly_offcmd0[] = { + 0x28, +}; + +static const u8 truly_offcmd1[] = { + 0xb0, 0x04, +}; + +static const u8 truly_offcmd2[] = { + 0xd3, 0x13, 0x33, 0xbb, 0xb3, 0xb3, 0x33, 0x33, + 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0, + 0x0c, 0x4d, 0x4d, 0x33, 0x33, 0x72, 0x12, 0x8a, + 0x57, 0x3d, 0xbc, +}; + +static const u8 truly_offcmd3[] = { + 0x10, +}; + +static const u8 truly_offcmd4[] = { + 0xb0, 0x00, +}; + +static const u8 truly_offcmd5[] = { + 0xb1, 0x01, +}; + +static const struct cmd_set truly_offcmds[] = { + { truly_offcmd0, ARRAY_SIZE(truly_offcmd0), 20, }, + { truly_offcmd1, ARRAY_SIZE(truly_offcmd1), }, + { truly_offcmd2, ARRAY_SIZE(truly_offcmd2), 27, }, + { truly_offcmd3, ARRAY_SIZE(truly_offcmd3), 120, }, + { truly_offcmd4, ARRAY_SIZE(truly_offcmd4), }, + { truly_offcmd5, ARRAY_SIZE(truly_offcmd5), }, +}; + +static const struct truly_data truly_fhd_data = { + .panel_oncmds = truly_oncmds, + .num_oncmds = ARRAY_SIZE(truly_oncmds), + .panel_offcmds = truly_offcmds, + .num_offcmds = ARRAY_SIZE(truly_offcmds), +}; + +static const u8 auo_oncmd0[] = { + 0xb0, 0x04, +}; + +static const u8 auo_oncmd1[] = { + 0xd6, 0x01, +}; + +static const u8 auo_oncmd2[] = { + 0xb3, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 auo_oncmd3[] = { + 0xb4, 0x0c, 0x00, +}; + +static const u8 auo_oncmd4[] = { + 0xb6, 0x4b, 0xdb, 0x00, +}; + +static const u8 auo_oncmd5[] = { + 0xc0, 0x66, +}; + +static const u8 auo_oncmd6[] = { + 0xc1, 0x04, 0x60, 0x00, 0x20, 0x29, 0x41, 0x22, + 0xfb, 0xf0, 0xff, 0xff, 0x9b, 0x7b, 0xcf, 0xb5, + 0xff, 0xff, 0x87, 0x8c, 0xc5, 0x11, 0x54, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x11, 0x02, + 0x21, 0x00, 0xff, 0x11, +}; + +static const u8 auo_oncmd7[] = { + 0xc2, 0x31, 0xf7, 0x80, 0x06, 0x04, 0x00, 0x00, + 0x08, +}; + +static const u8 auo_oncmd8[] = { + 0xc4, 0x70, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x00, 0x02, +}; + +static const u8 auo_oncmd9[] = { + 0xc6, 0xc8, 0x3c, 0x3c, 0x07, 0x01, 0x07, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1a, 0x07, 0xc8, +}; + +static const u8 auo_oncmd10[] = { + 0xc7, 0x0a, 0x18, 0x20, 0x29, 0x37, 0x43, 0x4d, + 0x5b, 0x3f, 0x46, 0x52, 0x5f, 0x67, 0x70, 0x7c, + 0x0a, 0x18, 0x20, 0x29, 0x37, 0x43, 0x4d, 0x5b, + 0x3f, 0x46, 0x52, 0x5f, 0x67, 0x70, 0x7c, +}; + +static const u8 auo_oncmd11[] = { + 0xcb, 0x7f, 0xe1, 0x87, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, +}; + +static const u8 auo_oncmd12[] = { + 0xcc, 0x32, +}; + +static const u8 auo_oncmd13[] = { + 0xd0, 0x11, 0x00, 0x00, 0x56, 0xd7, 0x40, 0x19, + 0x19, 0x09, 0x00, +}; + +static const u8 auo_oncmd14[] = { + 0xd1, 0x00, 0x48, 0x16, 0x0f, +}; + +static const u8 auo_oncmd15[] = { + 0xd3, 0x1b, 0x33, 0xbb, 0xbb, 0xb3, 0x33, 0x33, + 0x33, 0x33, 0x00, 0x01, 0x00, 0x00, 0xd8, 0xa0, + 0x0c, 0x37, 0x37, 0x33, 0x33, 0x72, 0x12, 0x8a, + 0x57, 0x3d, 0xbc, +}; + +static const u8 auo_oncmd16[] = { + 0xd5, 0x06, 0x00, 0x00, 0x01, 0x35, 0x01, 0x35, +}; + +static const u8 auo_oncmd17[] = { + 0x29, +}; + +static const u8 auo_oncmd18[] = { + 0x11, +}; + +static const struct cmd_set auo_oncmds[] = { + { auo_oncmd0, ARRAY_SIZE(auo_oncmd0), }, + { auo_oncmd1, ARRAY_SIZE(auo_oncmd1), }, + { auo_oncmd2, ARRAY_SIZE(auo_oncmd2), }, + { auo_oncmd3, ARRAY_SIZE(auo_oncmd3), }, + { auo_oncmd4, ARRAY_SIZE(auo_oncmd4), }, + { auo_oncmd5, ARRAY_SIZE(auo_oncmd5), }, + { auo_oncmd6, ARRAY_SIZE(auo_oncmd6), }, + { auo_oncmd7, ARRAY_SIZE(auo_oncmd7), }, + { auo_oncmd8, ARRAY_SIZE(auo_oncmd8), }, + { auo_oncmd9, ARRAY_SIZE(auo_oncmd9), }, + { auo_oncmd10, ARRAY_SIZE(auo_oncmd10), }, + { auo_oncmd11, ARRAY_SIZE(auo_oncmd11), }, + { auo_oncmd12, ARRAY_SIZE(auo_oncmd12), }, + { auo_oncmd13, ARRAY_SIZE(auo_oncmd13), }, + { auo_oncmd14, ARRAY_SIZE(auo_oncmd14), }, + { auo_oncmd15, ARRAY_SIZE(auo_oncmd15), }, + { auo_oncmd16, ARRAY_SIZE(auo_oncmd16), }, + { auo_oncmd17, ARRAY_SIZE(auo_oncmd17), 100, }, + { auo_oncmd18, ARRAY_SIZE(auo_oncmd18), 120, }, +}; + +static const u8 auo_offcmd0[] = { + 0x28, +}; + +static const u8 auo_offcmd1[] = { + 0xb0, 0x04, +}; + +static const struct cmd_set auo_offcmds[] = { + { auo_offcmd0, ARRAY_SIZE(auo_offcmd0), 10, }, + { auo_offcmd1, ARRAY_SIZE(auo_offcmd1), 120, }, +}; + +static const struct truly_data auo_fhd_data = { + .panel_oncmds = auo_oncmds, + .num_oncmds = ARRAY_SIZE(auo_oncmds), + .panel_offcmds = auo_offcmds, + .num_offcmds = ARRAY_SIZE(auo_offcmds), +}; + +static int truly_r63350_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct truly_panel *truly; + int ret; + + truly = devm_kzalloc(dev, sizeof(*truly), GFP_KERNEL); + if (!truly) + return -ENOMEM; + + truly->data = of_device_get_match_data(dev); + if (!truly->data) + return -ENODEV; + + /* Override data if bootloader provides the panel type */ + if (vendor_from_bl == TRULY) + truly->data = &truly_fhd_data; + else if (vendor_from_bl == AUO) + truly->data = &auo_fhd_data; + + truly->dev = dev; + + ret = truly_r63350_panel_add(truly); + if (ret) + return ret; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + truly->dsi = dsi; + + ret = mipi_dsi_attach(dsi); + if (ret) { + DRM_DEV_ERROR(dev, "failed to attach DSI device: %d\n", ret); + goto rm_panel; + } + + mipi_dsi_set_drvdata(dsi, truly); + + return 0; + +rm_panel: + drm_panel_remove(&truly->panel); + return ret; +} + +static void truly_r63350_remove(struct mipi_dsi_device *dsi) +{ + struct truly_panel *truly = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(truly->dsi); + drm_panel_remove(&truly->panel); + + return; +} + +static const struct of_device_id truly_r63350_of_match[] = { + { .compatible = "truly,r63350-fhd", .data = &truly_fhd_data, }, + { .compatible = "auo,r63350-fhd", .data = &auo_fhd_data, }, + { } +}; +MODULE_DEVICE_TABLE(of, truly_r63350_of_match); + +static struct mipi_dsi_driver truly_r63350_driver = { + .driver = { + .name = "panel-truly-r63350", + .of_match_table = truly_r63350_of_match, + }, + .probe = truly_r63350_probe, + .remove = truly_r63350_remove, +}; +module_mipi_dsi_driver(truly_r63350_driver); + +MODULE_DESCRIPTION("Truly R63350 DSI Panel Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 990a1519f968..4c78648ad1d1 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -553,6 +553,62 @@ static const struct venus_resources msm8916_res = { .fwname = "qcom/venus-1.8/venus.mdt", }; +static const struct freq_tbl msm8939_freq_table[] = { + { 489600, 266670000 }, /* HEVC 1080p 60fps */ + { 244800, 133330000 }, /* HEVC 1080p 30fps */ + { 220800, 133330000 }, /* HEVC 720p 60fps */ + { 108000, 133330000 }, /* HEVC 720p 30fps */ + { 72000, 133330000 }, /* HEVC VGA 60fps */ + { 36000, 133330000 }, /* HEVC VGA 30 fps */ +}; + +static const struct reg_val msm8939_reg_preset[] = { + { 0xe0020, 0x0aaaaaaa }, + { 0xe0024, 0x0aaaaaaa }, + { 0x80124, 0x00000003 }, +}; + +static const struct bw_tbl msm8939_bw_table_enc[] = { + { 1387725, 2577408, 0, 0, 0 }, /* HEVC 1080p 60fps */ + { 693863, 644403, 0, 0, 0 }, /* HEVC 1080p 30fps */ + { 612250, 1288704, 0, 0, 0 }, /* HEVC 720p 60fps */ + { 306074, 644403, 0, 0, 0 }, /* HEVC 720p 30fps */ + { 204083, 1288704, 0, 0, 0 }, /* HEVC VGA 60fps */ + { 101991, 644403, 0, 0, 0 }, /* HEVC VGA 30 fps */ +}; + +static const struct bw_tbl msm8939_bw_table_dec[] = { + { 1306624, 2291405, 0, 0, 0 }, /* HEVC 1080p 60fps */ + { 653312, 572826, 0, 0, 0 }, /* HEVC 1080p 30fps */ + { 576410, 1145754, 0, 0, 0 }, /* HEVC 720p 60fps */ + { 288256, 572826, 0, 0, 0 }, /* HEVC 720p 30fps */ + { 192103, 1145754, 0, 0, 0 }, /* HEVC VGA 60fps */ + { 96051, 572826, 0, 0, 0 }, /* HEVC VGA 30 fps */ +}; + +static const struct venus_resources msm8939_res = { + .freq_tbl = msm8939_freq_table, + .freq_tbl_size = ARRAY_SIZE(msm8939_freq_table), + .reg_tbl = msm8939_reg_preset, + .reg_tbl_size = ARRAY_SIZE(msm8939_reg_preset), + .bw_tbl_enc = msm8939_bw_table_enc, + .bw_tbl_enc_size = ARRAY_SIZE(msm8939_bw_table_enc), + .bw_tbl_dec = msm8939_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(msm8939_bw_table_dec), + .clks = { "core", "iface", "bus", }, + .clks_num = 3, + .vcodec0_clks = { "vcodec0_core" }, + .vcodec1_clks = { "vcodec1_core" }, + .vcodec_clks_num = 1, + .max_load = 489600, /* 1080p @ 30 + 1080p @ 30 */ + .hfi_version = HFI_VERSION_1XX, + .vmem_id = VIDC_RESOURCE_NONE, + .vmem_size = 0, + .vmem_addr = 0, + .dma_mask = 0xddc00000 - 1, + .fwname = "qcom/venus-1.8/venus.mdt", +}; + static const struct freq_tbl msm8996_freq_table[] = { { 1944000, 520000000 }, /* 4k UHD @ 60 (decode only) */ { 972000, 520000000 }, /* 4k UHD @ 30 */ @@ -878,6 +934,7 @@ static const struct venus_resources sc7280_res = { static const struct of_device_id venus_dt_match[] = { { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, + { .compatible = "qcom,msm8939-venus", .data = &msm8939_res, }, { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, { .compatible = "qcom,sdm660-venus", .data = &sdm660_res, }, { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 48c9084bb4db..0ef5251099c3 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -322,10 +322,56 @@ static int core_power_v1(struct venus_core *core, int on) return ret; } +static int vdec_get_v1(struct device *dev) +{ + struct venus_core *core = dev_get_drvdata(dev); + + return vcodec_clks_get(core, dev, core->vcodec0_clks, + core->res->vcodec0_clks); +} + +static int vdec_power_v1(struct device *dev, int on) +{ + struct venus_core *core = dev_get_drvdata(dev); + int ret = 0; + + if (on == POWER_ON) + ret = vcodec_clks_enable(core, core->vcodec0_clks); + else + vcodec_clks_disable(core, core->vcodec0_clks); + + return ret; +} + +static int venc_get_v1(struct device *dev) +{ + struct venus_core *core = dev_get_drvdata(dev); + + return vcodec_clks_get(core, dev, core->vcodec1_clks, + core->res->vcodec1_clks); +} + +static int venc_power_v1(struct device *dev, int on) +{ + struct venus_core *core = dev_get_drvdata(dev); + int ret = 0; + + if (on == POWER_ON) + ret = vcodec_clks_enable(core, core->vcodec1_clks); + else + vcodec_clks_disable(core, core->vcodec1_clks); + + return ret; +} + static const struct venus_pm_ops pm_ops_v1 = { .core_get = core_get_v1, .core_put = core_put_v1, .core_power = core_power_v1, + .vdec_get = vdec_get_v1, + .vdec_power = vdec_power_v1, + .venc_get = venc_get_v1, + .venc_power = venc_power_v1, .load_scale = load_scale_v1, }; diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c index 53e46c220a3a..793197512ff2 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c @@ -37,6 +37,7 @@ struct qcom_usb_hs_phy { struct ulpi_seq *init_seq; struct extcon_dev *vbus_edev; struct notifier_block vbus_notify; + u8 enable_vbus_pullup:1; }; static int qcom_usb_hs_phy_set_mode(struct phy *phy, @@ -105,6 +106,23 @@ qcom_usb_hs_phy_vbus_notifier(struct notifier_block *nb, unsigned long event, return ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXT); } +static int qcom_usb_hs_phy_enable_vbus_pullup(struct ulpi *ulpi, bool enable) +{ + u8 addr; + int ret; + + if (enable) + addr = ULPI_SET(ULPI_MISC_A); + else + addr = ULPI_CLR(ULPI_MISC_A); + + ret = ulpi_write(ulpi, addr, ULPI_MISC_A_VBUSVLDEXTSEL); + if (ret) + return ret; + + return ulpi_write(ulpi, addr, ULPI_MISC_A_VBUSVLDEXT); +} + static int qcom_usb_hs_phy_power_on(struct phy *phy) { struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); @@ -154,6 +172,12 @@ static int qcom_usb_hs_phy_power_on(struct phy *phy) goto err_ulpi; } + if (uphy->enable_vbus_pullup) { + ret = qcom_usb_hs_phy_enable_vbus_pullup(ulpi, true); + if (ret) + goto err_ulpi; + } + if (uphy->vbus_edev) { state = extcon_get_state(uphy->vbus_edev, EXTCON_USB); /* setup initial state */ @@ -180,10 +204,19 @@ err_sleep: static int qcom_usb_hs_phy_power_off(struct phy *phy) { struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + struct ulpi *ulpi = uphy->ulpi; + int ret; if (uphy->vbus_edev) extcon_unregister_notifier(uphy->vbus_edev, EXTCON_USB, &uphy->vbus_notify); + + if (uphy->enable_vbus_pullup) { + ret = qcom_usb_hs_phy_enable_vbus_pullup(ulpi, false); + if (ret) + return ret; + } + regulator_disable(uphy->v3p3); regulator_disable(uphy->v1p8); clk_disable_unprepare(uphy->sleep_clk); @@ -229,6 +262,9 @@ static int qcom_usb_hs_phy_probe(struct ulpi *ulpi) /* NUL terminate */ uphy->init_seq[size / 2].addr = uphy->init_seq[size / 2].val = 0; + if (of_property_read_bool(ulpi->dev.of_node, "qcom,enable-vbus-pullup")) + uphy->enable_vbus_pullup = 1; + uphy->ref_clk = clk = devm_clk_get(&ulpi->dev, "ref"); if (IS_ERR(clk)) return PTR_ERR(clk); diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 005c67cb3afb..73fddb69459b 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -471,4 +471,7 @@ void ci_platform_configure(struct ci_hdrc *ci); void dbg_create_files(struct ci_hdrc *ci); void dbg_remove_files(struct ci_hdrc *ci); + +void ci_platform_set_pin_state(struct ci_hdrc *ci, struct pinctrl_state *pins); + #endif /* __DRIVERS_USB_CHIPIDEA_CI_H */ diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 27c601296130..7fc964a0b169 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -185,6 +185,22 @@ u8 hw_port_test_get(struct ci_hdrc *ci) return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC); } +/** + * ci_platform_set_pin_state: set target pinctrl state with optional delay + * + * @ci: the controller + * @pins: the target pin-state + * + * This function returns nothing + */ +void ci_platform_set_pin_state(struct ci_hdrc *ci, struct pinctrl_state *pins) +{ + pinctrl_select_state(ci->platdata->pctl, pins); + if (ci->platdata->pin_switch_delay_us) + usleep_range(ci->platdata->pin_switch_delay_us, + ci->platdata->pin_switch_delay_us + 50); +} + static void hw_wait_phy_stable(void) { /* @@ -816,6 +832,9 @@ static int ci_get_platdata(struct device *dev, if (!platdata->enter_lpm) platdata->enter_lpm = ci_hdrc_enter_lpm_common; + of_property_read_u32(dev->of_node, "pin-switch-delay-us", + &platdata->pin_switch_delay_us); + return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index ebe7400243b1..7740c0e93317 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -170,8 +170,7 @@ static int host_start(struct ci_hdrc *ci) } if (ci->platdata->pins_host) - pinctrl_select_state(ci->platdata->pctl, - ci->platdata->pins_host); + ci_platform_set_pin_state(ci, ci->platdata->pins_host); ci->hcd = hcd; @@ -225,8 +224,8 @@ static void host_stop(struct ci_hdrc *ci) ci->otg.host = NULL; if (ci->platdata->pins_host && ci->platdata->pins_default) - pinctrl_select_state(ci->platdata->pctl, - ci->platdata->pins_default); + ci_platform_set_pin_state(ci, ci->platdata->pins_default); + } diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 54c09245ad05..fdf4661fd039 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -2154,8 +2154,7 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) static int udc_id_switch_for_device(struct ci_hdrc *ci) { if (ci->platdata->pins_device) - pinctrl_select_state(ci->platdata->pctl, - ci->platdata->pins_device); + ci_platform_set_pin_state(ci, ci->platdata->pins_device); if (ci->is_otg) /* Clear and enable BSV irq */ @@ -2177,8 +2176,7 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci) ci->vbus_active = 0; if (ci->platdata->pins_device && ci->platdata->pins_default) - pinctrl_select_state(ci->platdata->pctl, - ci->platdata->pins_default); + ci_platform_set_pin_state(ci, ci->platdata->pins_default); } #ifdef CONFIG_PM_SLEEP |