Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/bridge: ti-sn65dsi86: Add support for DisplayPort mode with HPD

Add support for DisplayPort to the bridge, which entails the following:
- Get and use an interrupt for HPD;
- Properly clear all status bits in the interrupt handler;

Signed-off-by: John Ripple <john.ripple@keysight.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Link: https://lore.kernel.org/r/20250915174543.2564994-1-john.ripple@keysight.com

authored by

John Ripple and committed by
Douglas Anderson
9133bc3f 48bc0faa

+112
+112
drivers/gpu/drm/bridge/ti-sn65dsi86.c
··· 106 106 #define SN_PWM_EN_INV_REG 0xA5 107 107 #define SN_PWM_INV_MASK BIT(0) 108 108 #define SN_PWM_EN_MASK BIT(1) 109 + 110 + #define SN_IRQ_EN_REG 0xE0 111 + #define IRQ_EN BIT(0) 112 + 113 + #define SN_IRQ_EVENTS_EN_REG 0xE6 114 + #define HPD_INSERTION_EN BIT(1) 115 + #define HPD_REMOVAL_EN BIT(2) 116 + 109 117 #define SN_AUX_CMD_STATUS_REG 0xF4 110 118 #define AUX_IRQ_STATUS_AUX_RPLY_TOUT BIT(3) 111 119 #define AUX_IRQ_STATUS_AUX_SHORT BIT(5) 112 120 #define AUX_IRQ_STATUS_NAT_I2C_FAIL BIT(6) 121 + #define SN_IRQ_STATUS_REG 0xF5 122 + #define HPD_REMOVAL_STATUS BIT(2) 123 + #define HPD_INSERTION_STATUS BIT(1) 113 124 114 125 #define MIN_DSI_CLK_FREQ_MHZ 40 115 126 ··· 163 152 * @ln_assign: Value to program to the LN_ASSIGN register. 164 153 * @ln_polrs: Value for the 4-bit LN_POLRS field of SN_ENH_FRAME_REG. 165 154 * @comms_enabled: If true then communication over the aux channel is enabled. 155 + * @hpd_enabled: If true then HPD events are enabled. 166 156 * @comms_mutex: Protects modification of comms_enabled. 157 + * @hpd_mutex: Protects modification of hpd_enabled. 167 158 * 168 159 * @gchip: If we expose our GPIOs, this is used. 169 160 * @gchip_output: A cache of whether we've set GPIOs to output. This ··· 203 190 u8 ln_assign; 204 191 u8 ln_polrs; 205 192 bool comms_enabled; 193 + bool hpd_enabled; 206 194 struct mutex comms_mutex; 195 + struct mutex hpd_mutex; 207 196 208 197 #if defined(CONFIG_OF_GPIO) 209 198 struct gpio_chip gchip; ··· 235 220 .cache_type = REGCACHE_NONE, 236 221 .max_register = 0xFF, 237 222 }; 223 + 224 + static int ti_sn65dsi86_read_u8(struct ti_sn65dsi86 *pdata, unsigned int reg, 225 + u8 *val) 226 + { 227 + int ret; 228 + unsigned int reg_val; 229 + 230 + ret = regmap_read(pdata->regmap, reg, &reg_val); 231 + if (ret) { 232 + dev_err(pdata->dev, "fail to read raw reg %#x: %d\n", 233 + reg, ret); 234 + return ret; 235 + } 236 + *val = (u8)reg_val; 237 + 238 + return 0; 239 + } 238 240 239 241 static int __maybe_unused ti_sn65dsi86_read_u16(struct ti_sn65dsi86 *pdata, 240 242 unsigned int reg, u16 *val) ··· 411 379 static int __maybe_unused ti_sn65dsi86_resume(struct device *dev) 412 380 { 413 381 struct ti_sn65dsi86 *pdata = dev_get_drvdata(dev); 382 + const struct i2c_client *client = to_i2c_client(pdata->dev); 414 383 int ret; 415 384 416 385 ret = regulator_bulk_enable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies); ··· 445 412 */ 446 413 if (pdata->refclk) 447 414 ti_sn65dsi86_enable_comms(pdata, NULL); 415 + 416 + if (client->irq) { 417 + ret = regmap_update_bits(pdata->regmap, SN_IRQ_EN_REG, IRQ_EN, 418 + IRQ_EN); 419 + if (ret) 420 + dev_err(pdata->dev, "Failed to enable IRQ events: %d\n", ret); 421 + } 448 422 449 423 return ret; 450 424 } ··· 1251 1211 static void ti_sn_bridge_hpd_enable(struct drm_bridge *bridge) 1252 1212 { 1253 1213 struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); 1214 + const struct i2c_client *client = to_i2c_client(pdata->dev); 1215 + int ret; 1254 1216 1255 1217 /* 1256 1218 * Device needs to be powered on before reading the HPD state ··· 1261 1219 */ 1262 1220 1263 1221 pm_runtime_get_sync(pdata->dev); 1222 + 1223 + mutex_lock(&pdata->hpd_mutex); 1224 + pdata->hpd_enabled = true; 1225 + mutex_unlock(&pdata->hpd_mutex); 1226 + 1227 + if (client->irq) { 1228 + ret = regmap_set_bits(pdata->regmap, SN_IRQ_EVENTS_EN_REG, 1229 + HPD_REMOVAL_EN | HPD_INSERTION_EN); 1230 + if (ret) 1231 + dev_err(pdata->dev, "Failed to enable HPD events: %d\n", ret); 1232 + } 1264 1233 } 1265 1234 1266 1235 static void ti_sn_bridge_hpd_disable(struct drm_bridge *bridge) 1267 1236 { 1268 1237 struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); 1238 + const struct i2c_client *client = to_i2c_client(pdata->dev); 1239 + int ret; 1240 + 1241 + if (client->irq) { 1242 + ret = regmap_clear_bits(pdata->regmap, SN_IRQ_EVENTS_EN_REG, 1243 + HPD_REMOVAL_EN | HPD_INSERTION_EN); 1244 + if (ret) 1245 + dev_err(pdata->dev, "Failed to disable HPD events: %d\n", ret); 1246 + } 1247 + 1248 + mutex_lock(&pdata->hpd_mutex); 1249 + pdata->hpd_enabled = false; 1250 + mutex_unlock(&pdata->hpd_mutex); 1269 1251 1270 1252 pm_runtime_put_autosuspend(pdata->dev); 1271 1253 } ··· 1373 1307 } 1374 1308 1375 1309 return 0; 1310 + } 1311 + 1312 + static irqreturn_t ti_sn_bridge_interrupt(int irq, void *private) 1313 + { 1314 + struct ti_sn65dsi86 *pdata = private; 1315 + struct drm_device *dev = pdata->bridge.dev; 1316 + u8 status; 1317 + int ret; 1318 + bool hpd_event; 1319 + 1320 + ret = ti_sn65dsi86_read_u8(pdata, SN_IRQ_STATUS_REG, &status); 1321 + if (ret) { 1322 + dev_err(pdata->dev, "Failed to read IRQ status: %d\n", ret); 1323 + return IRQ_NONE; 1324 + } 1325 + 1326 + hpd_event = status & (HPD_REMOVAL_STATUS | HPD_INSERTION_STATUS); 1327 + 1328 + dev_dbg(pdata->dev, "(SN_IRQ_STATUS_REG = %#x)\n", status); 1329 + if (!status) 1330 + return IRQ_NONE; 1331 + 1332 + ret = regmap_write(pdata->regmap, SN_IRQ_STATUS_REG, status); 1333 + if (ret) { 1334 + dev_err(pdata->dev, "Failed to clear IRQ status: %d\n", ret); 1335 + return IRQ_NONE; 1336 + } 1337 + 1338 + /* Only send the HPD event if we are bound with a device. */ 1339 + mutex_lock(&pdata->hpd_mutex); 1340 + if (pdata->hpd_enabled && hpd_event) 1341 + drm_kms_helper_hotplug_event(dev); 1342 + mutex_unlock(&pdata->hpd_mutex); 1343 + 1344 + return IRQ_HANDLED; 1376 1345 } 1377 1346 1378 1347 static int ti_sn_bridge_probe(struct auxiliary_device *adev, ··· 2032 1931 dev_set_drvdata(dev, pdata); 2033 1932 pdata->dev = dev; 2034 1933 1934 + mutex_init(&pdata->hpd_mutex); 2035 1935 mutex_init(&pdata->comms_mutex); 2036 1936 2037 1937 pdata->regmap = devm_regmap_init_i2c(client, ··· 2072 1970 /* The ID string is stored backwards */ 2073 1971 if (strncmp(id_buf, "68ISD ", ARRAY_SIZE(id_buf))) 2074 1972 return dev_err_probe(dev, -EOPNOTSUPP, "unsupported device id\n"); 1973 + 1974 + if (client->irq) { 1975 + ret = devm_request_threaded_irq(pdata->dev, client->irq, NULL, 1976 + ti_sn_bridge_interrupt, 1977 + IRQF_ONESHOT, 1978 + dev_name(pdata->dev), pdata); 1979 + 1980 + if (ret) 1981 + return dev_err_probe(dev, ret, "failed to request interrupt\n"); 1982 + } 2075 1983 2076 1984 /* 2077 1985 * Break ourselves up into a collection of aux devices. The only real