Path: blob/master/drivers/gpu/drm/bridge/chrontel-ch7033.c
26494 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Chrontel CH7033 Video Encoder Driver3*4* Copyright (C) 2019,2020 Lubomir Rintel5*/67#include <linux/gpio/consumer.h>8#include <linux/i2c.h>9#include <linux/module.h>10#include <linux/regmap.h>1112#include <drm/drm_atomic_helper.h>13#include <drm/drm_bridge.h>14#include <drm/drm_edid.h>15#include <drm/drm_of.h>16#include <drm/drm_print.h>17#include <drm/drm_probe_helper.h>1819/* Page 0, Register 0x07 */20enum {21DRI_PD = BIT(3),22IO_PD = BIT(5),23};2425/* Page 0, Register 0x08 */26enum {27DRI_PDDRI = GENMASK(7, 4),28PDDAC = GENMASK(3, 1),29PANEN = BIT(0),30};3132/* Page 0, Register 0x09 */33enum {34DPD = BIT(7),35GCKOFF = BIT(6),36TV_BP = BIT(5),37SCLPD = BIT(4),38SDPD = BIT(3),39VGA_PD = BIT(2),40HDBKPD = BIT(1),41HDMI_PD = BIT(0),42};4344/* Page 0, Register 0x0a */45enum {46MEMINIT = BIT(7),47MEMIDLE = BIT(6),48MEMPD = BIT(5),49STOP = BIT(4),50LVDS_PD = BIT(3),51HD_DVIB = BIT(2),52HDCP_PD = BIT(1),53MCU_PD = BIT(0),54};5556/* Page 0, Register 0x18 */57enum {58IDF = GENMASK(7, 4),59INTEN = BIT(3),60SWAP = GENMASK(2, 0),61};6263enum {64BYTE_SWAP_RGB = 0,65BYTE_SWAP_RBG = 1,66BYTE_SWAP_GRB = 2,67BYTE_SWAP_GBR = 3,68BYTE_SWAP_BRG = 4,69BYTE_SWAP_BGR = 5,70};7172/* Page 0, Register 0x19 */73enum {74HPO_I = BIT(5),75VPO_I = BIT(4),76DEPO_I = BIT(3),77CRYS_EN = BIT(2),78GCLKFREQ = GENMASK(2, 0),79};8081/* Page 0, Register 0x2e */82enum {83HFLIP = BIT(7),84VFLIP = BIT(6),85DEPO_O = BIT(5),86HPO_O = BIT(4),87VPO_O = BIT(3),88TE = GENMASK(2, 0),89};9091/* Page 0, Register 0x2b */92enum {93SWAPS = GENMASK(7, 4),94VFMT = GENMASK(3, 0),95};9697/* Page 0, Register 0x54 */98enum {99COMP_BP = BIT(7),100DAC_EN_T = BIT(6),101HWO_HDMI_HI = GENMASK(5, 3),102HOO_HDMI_HI = GENMASK(2, 0),103};104105/* Page 0, Register 0x57 */106enum {107FLDSEN = BIT(7),108VWO_HDMI_HI = GENMASK(5, 3),109VOO_HDMI_HI = GENMASK(2, 0),110};111112/* Page 0, Register 0x7e */113enum {114HDMI_LVDS_SEL = BIT(7),115DE_GEN = BIT(6),116PWM_INDEX_HI = BIT(5),117USE_DE = BIT(4),118R_INT = GENMASK(3, 0),119};120121/* Page 1, Register 0x07 */122enum {123BPCKSEL = BIT(7),124DRI_CMFB_EN = BIT(6),125CEC_PUEN = BIT(5),126CEC_T = BIT(3),127CKINV = BIT(2),128CK_TVINV = BIT(1),129DRI_CKS2 = BIT(0),130};131132/* Page 1, Register 0x08 */133enum {134DACG = BIT(6),135DACKTST = BIT(5),136DEDGEB = BIT(4),137SYO = BIT(3),138DRI_IT_LVDS = GENMASK(2, 1),139DISPON = BIT(0),140};141142/* Page 1, Register 0x0c */143enum {144DRI_PLL_CP = GENMASK(7, 6),145DRI_PLL_DIVSEL = BIT(5),146DRI_PLL_N1_1 = BIT(4),147DRI_PLL_N1_0 = BIT(3),148DRI_PLL_N3_1 = BIT(2),149DRI_PLL_N3_0 = BIT(1),150DRI_PLL_CKTSTEN = BIT(0),151};152153/* Page 1, Register 0x6b */154enum {155VCO3CS = GENMASK(7, 6),156ICPGBK2_0 = GENMASK(5, 3),157DRI_VCO357SC = BIT(2),158PDPLL2 = BIT(1),159DRI_PD_SER = BIT(0),160};161162/* Page 1, Register 0x6c */163enum {164PLL2N11 = GENMASK(7, 4),165PLL2N5_4 = BIT(3),166PLL2N5_TOP = BIT(2),167DRI_PLL_PD = BIT(1),168PD_I2CM = BIT(0),169};170171/* Page 3, Register 0x28 */172enum {173DIFF_EN = GENMASK(7, 6),174CORREC_EN = GENMASK(5, 4),175VGACLK_BP = BIT(3),176HM_LV_SEL = BIT(2),177HD_VGA_SEL = BIT(1),178};179180/* Page 3, Register 0x2a */181enum {182LVDSCLK_BP = BIT(7),183HDTVCLK_BP = BIT(6),184HDMICLK_BP = BIT(5),185HDTV_BP = BIT(4),186HDMI_BP = BIT(3),187THRWL = GENMASK(2, 0),188};189190/* Page 4, Register 0x52 */191enum {192PGM_ARSTB = BIT(7),193MCU_ARSTB = BIT(6),194MCU_RETB = BIT(2),195RESETIB = BIT(1),196RESETDB = BIT(0),197};198199struct ch7033_priv {200struct regmap *regmap;201struct drm_bridge *next_bridge;202struct drm_bridge bridge;203struct drm_connector connector;204};205206#define conn_to_ch7033_priv(x) \207container_of(x, struct ch7033_priv, connector)208#define bridge_to_ch7033_priv(x) \209container_of(x, struct ch7033_priv, bridge)210211212static enum drm_connector_status ch7033_connector_detect(213struct drm_connector *connector, bool force)214{215struct ch7033_priv *priv = conn_to_ch7033_priv(connector);216217return drm_bridge_detect(priv->next_bridge, connector);218}219220static const struct drm_connector_funcs ch7033_connector_funcs = {221.reset = drm_atomic_helper_connector_reset,222.fill_modes = drm_helper_probe_single_connector_modes,223.detect = ch7033_connector_detect,224.destroy = drm_connector_cleanup,225.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,226.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,227};228229static int ch7033_connector_get_modes(struct drm_connector *connector)230{231struct ch7033_priv *priv = conn_to_ch7033_priv(connector);232const struct drm_edid *drm_edid;233int ret;234235drm_edid = drm_bridge_edid_read(priv->next_bridge, connector);236drm_edid_connector_update(connector, drm_edid);237if (drm_edid) {238ret = drm_edid_connector_add_modes(connector);239drm_edid_free(drm_edid);240} else {241ret = drm_add_modes_noedid(connector, 1920, 1080);242drm_set_preferred_mode(connector, 1024, 768);243}244245return ret;246}247248static struct drm_encoder *ch7033_connector_best_encoder(249struct drm_connector *connector)250{251struct ch7033_priv *priv = conn_to_ch7033_priv(connector);252253return priv->bridge.encoder;254}255256static const struct drm_connector_helper_funcs ch7033_connector_helper_funcs = {257.get_modes = ch7033_connector_get_modes,258.best_encoder = ch7033_connector_best_encoder,259};260261static void ch7033_hpd_event(void *arg, enum drm_connector_status status)262{263struct ch7033_priv *priv = arg;264265if (priv->bridge.dev)266drm_helper_hpd_irq_event(priv->connector.dev);267}268269static int ch7033_bridge_attach(struct drm_bridge *bridge,270struct drm_encoder *encoder,271enum drm_bridge_attach_flags flags)272{273struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);274struct drm_connector *connector = &priv->connector;275int ret;276277ret = drm_bridge_attach(encoder, priv->next_bridge, bridge,278DRM_BRIDGE_ATTACH_NO_CONNECTOR);279if (ret)280return ret;281282if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)283return 0;284285if (priv->next_bridge->ops & DRM_BRIDGE_OP_DETECT) {286connector->polled = DRM_CONNECTOR_POLL_HPD;287} else {288connector->polled = DRM_CONNECTOR_POLL_CONNECT |289DRM_CONNECTOR_POLL_DISCONNECT;290}291292if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD) {293drm_bridge_hpd_enable(priv->next_bridge, ch7033_hpd_event,294priv);295}296297drm_connector_helper_add(connector,298&ch7033_connector_helper_funcs);299ret = drm_connector_init_with_ddc(bridge->dev, &priv->connector,300&ch7033_connector_funcs,301priv->next_bridge->type,302priv->next_bridge->ddc);303if (ret) {304DRM_ERROR("Failed to initialize connector\n");305return ret;306}307308return drm_connector_attach_encoder(&priv->connector, encoder);309}310311static void ch7033_bridge_detach(struct drm_bridge *bridge)312{313struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);314315if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD)316drm_bridge_hpd_disable(priv->next_bridge);317drm_connector_cleanup(&priv->connector);318}319320static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge,321const struct drm_display_info *info,322const struct drm_display_mode *mode)323{324if (mode->clock > 165000)325return MODE_CLOCK_HIGH;326if (mode->hdisplay >= 1920)327return MODE_BAD_HVALUE;328if (mode->vdisplay >= 1080)329return MODE_BAD_VVALUE;330return MODE_OK;331}332333static void ch7033_bridge_disable(struct drm_bridge *bridge)334{335struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);336337regmap_write(priv->regmap, 0x03, 0x04);338regmap_update_bits(priv->regmap, 0x52, RESETDB, 0x00);339}340341static void ch7033_bridge_enable(struct drm_bridge *bridge)342{343struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);344345regmap_write(priv->regmap, 0x03, 0x04);346regmap_update_bits(priv->regmap, 0x52, RESETDB, RESETDB);347}348349static void ch7033_bridge_mode_set(struct drm_bridge *bridge,350const struct drm_display_mode *mode,351const struct drm_display_mode *adjusted_mode)352{353struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);354int hbporch = mode->hsync_start - mode->hdisplay;355int hsynclen = mode->hsync_end - mode->hsync_start;356int vbporch = mode->vsync_start - mode->vdisplay;357int vsynclen = mode->vsync_end - mode->vsync_start;358359/*360* Page 4361*/362regmap_write(priv->regmap, 0x03, 0x04);363364/* Turn everything off to set all the registers to their defaults. */365regmap_write(priv->regmap, 0x52, 0x00);366/* Bring I/O block up. */367regmap_write(priv->regmap, 0x52, RESETIB);368369/*370* Page 0371*/372regmap_write(priv->regmap, 0x03, 0x00);373374/* Bring up parts we need from the power down. */375regmap_update_bits(priv->regmap, 0x07, DRI_PD | IO_PD, 0);376regmap_update_bits(priv->regmap, 0x08, DRI_PDDRI | PDDAC | PANEN, 0);377regmap_update_bits(priv->regmap, 0x09, DPD | GCKOFF |378HDMI_PD | VGA_PD, 0);379regmap_update_bits(priv->regmap, 0x0a, HD_DVIB, 0);380381/* Horizontal input timing. */382regmap_write(priv->regmap, 0x0b, (mode->htotal >> 8) << 3 |383(mode->hdisplay >> 8));384regmap_write(priv->regmap, 0x0c, mode->hdisplay);385regmap_write(priv->regmap, 0x0d, mode->htotal);386regmap_write(priv->regmap, 0x0e, (hsynclen >> 8) << 3 |387(hbporch >> 8));388regmap_write(priv->regmap, 0x0f, hbporch);389regmap_write(priv->regmap, 0x10, hsynclen);390391/* Vertical input timing. */392regmap_write(priv->regmap, 0x11, (mode->vtotal >> 8) << 3 |393(mode->vdisplay >> 8));394regmap_write(priv->regmap, 0x12, mode->vdisplay);395regmap_write(priv->regmap, 0x13, mode->vtotal);396regmap_write(priv->regmap, 0x14, ((vsynclen >> 8) << 3) |397(vbporch >> 8));398regmap_write(priv->regmap, 0x15, vbporch);399regmap_write(priv->regmap, 0x16, vsynclen);400401/* Input color swap. */402regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR);403404/* Input clock and sync polarity. */405regmap_update_bits(priv->regmap, 0x19, 0x1, mode->clock >> 16);406regmap_update_bits(priv->regmap, 0x19, HPO_I | VPO_I | GCLKFREQ,407(mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_I : 0 |408(mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_I : 0 |409mode->clock >> 16);410regmap_write(priv->regmap, 0x1a, mode->clock >> 8);411regmap_write(priv->regmap, 0x1b, mode->clock);412413/* Horizontal output timing. */414regmap_write(priv->regmap, 0x1f, (mode->htotal >> 8) << 3 |415(mode->hdisplay >> 8));416regmap_write(priv->regmap, 0x20, mode->hdisplay);417regmap_write(priv->regmap, 0x21, mode->htotal);418419/* Vertical output timing. */420regmap_write(priv->regmap, 0x25, (mode->vtotal >> 8) << 3 |421(mode->vdisplay >> 8));422regmap_write(priv->regmap, 0x26, mode->vdisplay);423regmap_write(priv->regmap, 0x27, mode->vtotal);424425/* VGA channel bypass */426regmap_update_bits(priv->regmap, 0x2b, VFMT, 9);427428/* Output sync polarity. */429regmap_update_bits(priv->regmap, 0x2e, HPO_O | VPO_O,430(mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_O : 0 |431(mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_O : 0);432433/* HDMI horizontal output timing. */434regmap_update_bits(priv->regmap, 0x54, HWO_HDMI_HI | HOO_HDMI_HI,435(hsynclen >> 8) << 3 |436(hbporch >> 8));437regmap_write(priv->regmap, 0x55, hbporch);438regmap_write(priv->regmap, 0x56, hsynclen);439440/* HDMI vertical output timing. */441regmap_update_bits(priv->regmap, 0x57, VWO_HDMI_HI | VOO_HDMI_HI,442(vsynclen >> 8) << 3 |443(vbporch >> 8));444regmap_write(priv->regmap, 0x58, vbporch);445regmap_write(priv->regmap, 0x59, vsynclen);446447/* Pick HDMI, not LVDS. */448regmap_update_bits(priv->regmap, 0x7e, HDMI_LVDS_SEL, HDMI_LVDS_SEL);449450/*451* Page 1452*/453regmap_write(priv->regmap, 0x03, 0x01);454455/* No idea what these do, but VGA is wobbly and blinky without them. */456regmap_update_bits(priv->regmap, 0x07, CKINV, CKINV);457regmap_update_bits(priv->regmap, 0x08, DISPON, DISPON);458459/* DRI PLL */460regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_DIVSEL, DRI_PLL_DIVSEL);461if (mode->clock <= 40000) {462regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |463DRI_PLL_N1_0 |464DRI_PLL_N3_1 |465DRI_PLL_N3_0,4660);467} else if (mode->clock < 80000) {468regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |469DRI_PLL_N1_0 |470DRI_PLL_N3_1 |471DRI_PLL_N3_0,472DRI_PLL_N3_0 |473DRI_PLL_N1_0);474} else {475regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |476DRI_PLL_N1_0 |477DRI_PLL_N3_1 |478DRI_PLL_N3_0,479DRI_PLL_N3_1 |480DRI_PLL_N1_1);481}482483/* This seems to be color calibration for VGA. */484regmap_write(priv->regmap, 0x64, 0x29); /* LSB Blue */485regmap_write(priv->regmap, 0x65, 0x29); /* LSB Green */486regmap_write(priv->regmap, 0x66, 0x29); /* LSB Red */487regmap_write(priv->regmap, 0x67, 0x00); /* MSB Blue */488regmap_write(priv->regmap, 0x68, 0x00); /* MSB Green */489regmap_write(priv->regmap, 0x69, 0x00); /* MSB Red */490491regmap_update_bits(priv->regmap, 0x6b, DRI_PD_SER, 0x00);492regmap_update_bits(priv->regmap, 0x6c, DRI_PLL_PD, 0x00);493494/*495* Page 3496*/497regmap_write(priv->regmap, 0x03, 0x03);498499/* More bypasses and apparently another HDMI/LVDS selector. */500regmap_update_bits(priv->regmap, 0x28, VGACLK_BP | HM_LV_SEL,501VGACLK_BP | HM_LV_SEL);502regmap_update_bits(priv->regmap, 0x2a, HDMICLK_BP | HDMI_BP,503HDMICLK_BP | HDMI_BP);504505/*506* Page 4507*/508regmap_write(priv->regmap, 0x03, 0x04);509510/* Output clock. */511regmap_write(priv->regmap, 0x10, mode->clock >> 16);512regmap_write(priv->regmap, 0x11, mode->clock >> 8);513regmap_write(priv->regmap, 0x12, mode->clock);514}515516static const struct drm_bridge_funcs ch7033_bridge_funcs = {517.attach = ch7033_bridge_attach,518.detach = ch7033_bridge_detach,519.mode_valid = ch7033_bridge_mode_valid,520.disable = ch7033_bridge_disable,521.enable = ch7033_bridge_enable,522.mode_set = ch7033_bridge_mode_set,523};524525static const struct regmap_config ch7033_regmap_config = {526.reg_bits = 8,527.val_bits = 8,528.max_register = 0x7f,529};530531static int ch7033_probe(struct i2c_client *client)532{533struct device *dev = &client->dev;534struct ch7033_priv *priv;535unsigned int val;536int ret;537538priv = devm_drm_bridge_alloc(dev, struct ch7033_priv, bridge,539&ch7033_bridge_funcs);540if (IS_ERR(priv))541return PTR_ERR(priv);542543dev_set_drvdata(dev, priv);544545ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,546&priv->next_bridge);547if (ret)548return ret;549550priv->regmap = devm_regmap_init_i2c(client, &ch7033_regmap_config);551if (IS_ERR(priv->regmap)) {552dev_err(&client->dev, "regmap init failed\n");553return PTR_ERR(priv->regmap);554}555556ret = regmap_read(priv->regmap, 0x00, &val);557if (ret < 0) {558dev_err(&client->dev, "error reading the model id: %d\n", ret);559return ret;560}561if ((val & 0xf7) != 0x56) {562dev_err(&client->dev, "the device is not a ch7033\n");563return -ENODEV;564}565566regmap_write(priv->regmap, 0x03, 0x04);567ret = regmap_read(priv->regmap, 0x51, &val);568if (ret < 0) {569dev_err(&client->dev, "error reading the model id: %d\n", ret);570return ret;571}572if ((val & 0x0f) != 3) {573dev_err(&client->dev, "unknown revision %u\n", val);574return -ENODEV;575}576577INIT_LIST_HEAD(&priv->bridge.list);578priv->bridge.of_node = dev->of_node;579drm_bridge_add(&priv->bridge);580581dev_info(dev, "Chrontel CH7033 Video Encoder\n");582return 0;583}584585static void ch7033_remove(struct i2c_client *client)586{587struct device *dev = &client->dev;588struct ch7033_priv *priv = dev_get_drvdata(dev);589590drm_bridge_remove(&priv->bridge);591}592593static const struct of_device_id ch7033_dt_ids[] = {594{ .compatible = "chrontel,ch7033", },595{ }596};597MODULE_DEVICE_TABLE(of, ch7033_dt_ids);598599static const struct i2c_device_id ch7033_ids[] = {600{ "ch7033" },601{ }602};603MODULE_DEVICE_TABLE(i2c, ch7033_ids);604605static struct i2c_driver ch7033_driver = {606.probe = ch7033_probe,607.remove = ch7033_remove,608.driver = {609.name = "ch7033",610.of_match_table = ch7033_dt_ids,611},612.id_table = ch7033_ids,613};614615module_i2c_driver(ch7033_driver);616617MODULE_AUTHOR("Lubomir Rintel <[email protected]>");618MODULE_DESCRIPTION("Chrontel CH7033 Video Encoder Driver");619MODULE_LICENSE("GPL v2");620621622