cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nxp-ptn3460.c (8813B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * NXP PTN3460 DP/LVDS bridge driver
      4 *
      5 * Copyright (C) 2013 Google, Inc.
      6 */
      7
      8#include <linux/delay.h>
      9#include <linux/gpio/consumer.h>
     10#include <linux/i2c.h>
     11#include <linux/module.h>
     12#include <linux/of.h>
     13#include <drm/drm_atomic_helper.h>
     14#include <drm/drm_bridge.h>
     15#include <drm/drm_crtc.h>
     16#include <drm/drm_edid.h>
     17#include <drm/drm_of.h>
     18#include <drm/drm_panel.h>
     19#include <drm/drm_print.h>
     20#include <drm/drm_probe_helper.h>
     21
     22#define PTN3460_EDID_ADDR			0x0
     23#define PTN3460_EDID_EMULATION_ADDR		0x84
     24#define PTN3460_EDID_ENABLE_EMULATION		0
     25#define PTN3460_EDID_EMULATION_SELECTION	1
     26#define PTN3460_EDID_SRAM_LOAD_ADDR		0x85
     27
     28struct ptn3460_bridge {
     29	struct drm_connector connector;
     30	struct i2c_client *client;
     31	struct drm_bridge bridge;
     32	struct drm_bridge *panel_bridge;
     33	struct gpio_desc *gpio_pd_n;
     34	struct gpio_desc *gpio_rst_n;
     35	u32 edid_emulation;
     36	bool enabled;
     37};
     38
     39static inline struct ptn3460_bridge *
     40		bridge_to_ptn3460(struct drm_bridge *bridge)
     41{
     42	return container_of(bridge, struct ptn3460_bridge, bridge);
     43}
     44
     45static inline struct ptn3460_bridge *
     46		connector_to_ptn3460(struct drm_connector *connector)
     47{
     48	return container_of(connector, struct ptn3460_bridge, connector);
     49}
     50
     51static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
     52		u8 *buf, int len)
     53{
     54	int ret;
     55
     56	ret = i2c_master_send(ptn_bridge->client, &addr, 1);
     57	if (ret <= 0) {
     58		DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
     59		return ret;
     60	}
     61
     62	ret = i2c_master_recv(ptn_bridge->client, buf, len);
     63	if (ret <= 0) {
     64		DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret);
     65		return ret;
     66	}
     67
     68	return 0;
     69}
     70
     71static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr,
     72		char val)
     73{
     74	int ret;
     75	char buf[2];
     76
     77	buf[0] = addr;
     78	buf[1] = val;
     79
     80	ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf));
     81	if (ret <= 0) {
     82		DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
     83		return ret;
     84	}
     85
     86	return 0;
     87}
     88
     89static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
     90{
     91	int ret;
     92	char val;
     93
     94	/* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */
     95	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
     96			ptn_bridge->edid_emulation);
     97	if (ret) {
     98		DRM_ERROR("Failed to transfer EDID to sram, ret=%d\n", ret);
     99		return ret;
    100	}
    101
    102	/* Enable EDID emulation and select the desired EDID */
    103	val = 1 << PTN3460_EDID_ENABLE_EMULATION |
    104		ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION;
    105
    106	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
    107	if (ret) {
    108		DRM_ERROR("Failed to write EDID value, ret=%d\n", ret);
    109		return ret;
    110	}
    111
    112	return 0;
    113}
    114
    115static void ptn3460_pre_enable(struct drm_bridge *bridge)
    116{
    117	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
    118	int ret;
    119
    120	if (ptn_bridge->enabled)
    121		return;
    122
    123	gpiod_set_value(ptn_bridge->gpio_pd_n, 1);
    124
    125	gpiod_set_value(ptn_bridge->gpio_rst_n, 0);
    126	usleep_range(10, 20);
    127	gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
    128
    129	/*
    130	 * There's a bug in the PTN chip where it falsely asserts hotplug before
    131	 * it is fully functional. We're forced to wait for the maximum start up
    132	 * time specified in the chip's datasheet to make sure we're really up.
    133	 */
    134	msleep(90);
    135
    136	ret = ptn3460_select_edid(ptn_bridge);
    137	if (ret)
    138		DRM_ERROR("Select EDID failed ret=%d\n", ret);
    139
    140	ptn_bridge->enabled = true;
    141}
    142
    143static void ptn3460_disable(struct drm_bridge *bridge)
    144{
    145	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
    146
    147	if (!ptn_bridge->enabled)
    148		return;
    149
    150	ptn_bridge->enabled = false;
    151
    152	gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
    153	gpiod_set_value(ptn_bridge->gpio_pd_n, 0);
    154}
    155
    156
    157static struct edid *ptn3460_get_edid(struct drm_bridge *bridge,
    158				     struct drm_connector *connector)
    159{
    160	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
    161	bool power_off;
    162	u8 *edid;
    163	int ret;
    164
    165	power_off = !ptn_bridge->enabled;
    166	ptn3460_pre_enable(&ptn_bridge->bridge);
    167
    168	edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
    169	if (!edid) {
    170		DRM_ERROR("Failed to allocate EDID\n");
    171		goto out;
    172	}
    173
    174	ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid,
    175				 EDID_LENGTH);
    176	if (ret) {
    177		kfree(edid);
    178		edid = NULL;
    179		goto out;
    180	}
    181
    182out:
    183	if (power_off)
    184		ptn3460_disable(&ptn_bridge->bridge);
    185
    186	return (struct edid *)edid;
    187}
    188
    189static int ptn3460_connector_get_modes(struct drm_connector *connector)
    190{
    191	struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
    192	struct edid *edid;
    193	int num_modes;
    194
    195	edid = ptn3460_get_edid(&ptn_bridge->bridge, connector);
    196	drm_connector_update_edid_property(connector, edid);
    197	num_modes = drm_add_edid_modes(connector, edid);
    198	kfree(edid);
    199
    200	return num_modes;
    201}
    202
    203static const struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
    204	.get_modes = ptn3460_connector_get_modes,
    205};
    206
    207static const struct drm_connector_funcs ptn3460_connector_funcs = {
    208	.fill_modes = drm_helper_probe_single_connector_modes,
    209	.destroy = drm_connector_cleanup,
    210	.reset = drm_atomic_helper_connector_reset,
    211	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
    212	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
    213};
    214
    215static int ptn3460_bridge_attach(struct drm_bridge *bridge,
    216				 enum drm_bridge_attach_flags flags)
    217{
    218	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
    219	int ret;
    220
    221	/* Let this driver create connector if requested */
    222	ret = drm_bridge_attach(bridge->encoder, ptn_bridge->panel_bridge,
    223				bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
    224	if (ret < 0)
    225		return ret;
    226
    227	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
    228		return 0;
    229
    230	if (!bridge->encoder) {
    231		DRM_ERROR("Parent encoder object not found");
    232		return -ENODEV;
    233	}
    234
    235	ptn_bridge->connector.polled = DRM_CONNECTOR_POLL_HPD;
    236	ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
    237			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
    238	if (ret) {
    239		DRM_ERROR("Failed to initialize connector with drm\n");
    240		return ret;
    241	}
    242	drm_connector_helper_add(&ptn_bridge->connector,
    243					&ptn3460_connector_helper_funcs);
    244	drm_connector_register(&ptn_bridge->connector);
    245	drm_connector_attach_encoder(&ptn_bridge->connector,
    246							bridge->encoder);
    247
    248	drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
    249
    250	return ret;
    251}
    252
    253static const struct drm_bridge_funcs ptn3460_bridge_funcs = {
    254	.pre_enable = ptn3460_pre_enable,
    255	.disable = ptn3460_disable,
    256	.attach = ptn3460_bridge_attach,
    257	.get_edid = ptn3460_get_edid,
    258};
    259
    260static int ptn3460_probe(struct i2c_client *client,
    261				const struct i2c_device_id *id)
    262{
    263	struct device *dev = &client->dev;
    264	struct ptn3460_bridge *ptn_bridge;
    265	struct drm_bridge *panel_bridge;
    266	int ret;
    267
    268	ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
    269	if (!ptn_bridge) {
    270		return -ENOMEM;
    271	}
    272
    273	panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
    274	if (IS_ERR(panel_bridge))
    275		return PTR_ERR(panel_bridge);
    276
    277	ptn_bridge->panel_bridge = panel_bridge;
    278	ptn_bridge->client = client;
    279
    280	ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown",
    281					       GPIOD_OUT_HIGH);
    282	if (IS_ERR(ptn_bridge->gpio_pd_n)) {
    283		ret = PTR_ERR(ptn_bridge->gpio_pd_n);
    284		dev_err(dev, "cannot get gpio_pd_n %d\n", ret);
    285		return ret;
    286	}
    287
    288	/*
    289	 * Request the reset pin low to avoid the bridge being
    290	 * initialized prematurely
    291	 */
    292	ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset",
    293						GPIOD_OUT_LOW);
    294	if (IS_ERR(ptn_bridge->gpio_rst_n)) {
    295		ret = PTR_ERR(ptn_bridge->gpio_rst_n);
    296		DRM_ERROR("cannot get gpio_rst_n %d\n", ret);
    297		return ret;
    298	}
    299
    300	ret = of_property_read_u32(dev->of_node, "edid-emulation",
    301			&ptn_bridge->edid_emulation);
    302	if (ret) {
    303		dev_err(dev, "Can't read EDID emulation value\n");
    304		return ret;
    305	}
    306
    307	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
    308	ptn_bridge->bridge.ops = DRM_BRIDGE_OP_EDID;
    309	ptn_bridge->bridge.type = DRM_MODE_CONNECTOR_LVDS;
    310	ptn_bridge->bridge.of_node = dev->of_node;
    311	drm_bridge_add(&ptn_bridge->bridge);
    312
    313	i2c_set_clientdata(client, ptn_bridge);
    314
    315	return 0;
    316}
    317
    318static int ptn3460_remove(struct i2c_client *client)
    319{
    320	struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client);
    321
    322	drm_bridge_remove(&ptn_bridge->bridge);
    323
    324	return 0;
    325}
    326
    327static const struct i2c_device_id ptn3460_i2c_table[] = {
    328	{"ptn3460", 0},
    329	{},
    330};
    331MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
    332
    333static const struct of_device_id ptn3460_match[] = {
    334	{ .compatible = "nxp,ptn3460" },
    335	{},
    336};
    337MODULE_DEVICE_TABLE(of, ptn3460_match);
    338
    339static struct i2c_driver ptn3460_driver = {
    340	.id_table	= ptn3460_i2c_table,
    341	.probe		= ptn3460_probe,
    342	.remove		= ptn3460_remove,
    343	.driver		= {
    344		.name	= "nxp,ptn3460",
    345		.of_match_table = ptn3460_match,
    346	},
    347};
    348module_i2c_driver(ptn3460_driver);
    349
    350MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>");
    351MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver");
    352MODULE_LICENSE("GPL v2");