blob: 851156fea0f521c56e75e9dd9a3f024cbffad141 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Uwe Poeche11a34ec2019-10-28 11:28:50 +01003
4
5#include <console/console.h>
6#include <device/i2c_bus.h>
7#include <types.h>
8
9#include "ptn3460.h"
10
11/**
12 * \brief This function selects one of 7 EDID-tables inside PTN3460
13 * which should be emulated on display port and turn emulation ON
14 * @param *dev Pointer to the relevant I2C controller
15 * @param edid_num Number of EDID to emulate (0..6)
16 * @return PTN_SUCCESS or error code
17 */
18static int ptn_select_edid(struct device *dev, uint8_t edid_num)
19{
20 int status = 0;
21 u8 val;
22
23 if (edid_num > PTN_MAX_EDID_NUM)
24 return PTN_INVALID_EDID;
25 val = (edid_num << 1) | PTN_ENABLE_EMULATION;
26 status = i2c_dev_writeb_at(dev, PTN_CONFIG_OFF + 4, val);
27 return status ? (PTN_BUS_ERROR | status) : PTN_SUCCESS;
28}
29
30/**
31 * \brief This function writes one EDID data structure to PTN3460
32 * @param *dev Pointer to the relevant I2C controller
33 * @param edid_num Number of EDID that must be written (0..6)
34 * @param *data Pointer to a buffer where data to write is stored in
35 * @return PTN_SUCCESS on success or error code
36 */
37static int ptn3460_write_edid(struct device *dev, u8 edid_num, u8 *data)
38{
39 int status;
40 int i;
41
42 if (edid_num > PTN_MAX_EDID_NUM)
43 return PTN_INVALID_EDID;
44
45 /* First enable access to the desired EDID table */
46 status = i2c_dev_writeb_at(dev, PTN_CONFIG_OFF + 5, edid_num);
47 if (status)
48 return (PTN_BUS_ERROR | status);
49
50 /* Now we can simply write EDID data to ptn3460 */
51 for (i = 0; i < PTN_EDID_LEN; i++) {
52 status = i2c_dev_writeb_at(dev, PTN_EDID_OFF + i, data[i]);
53 if (status)
54 return (PTN_BUS_ERROR | status);
55 }
56 return PTN_SUCCESS;
57}
58
59/**
60 * \brief This function sets up the DP2LVDS-converter to be used with the
61 * appropriate EDID data
62 * @param *dev Pointer to the I2C controller where PTN3460 is attached
63 */
64static void ptn3460_init(struct device *dev)
65{
66 struct ptn_3460_config cfg;
67 uint8_t edid_data[PTN_EDID_LEN], edid_tab, *ptr = (uint8_t *) &cfg;
68 int i, val;
69
70 /* Mainboard provides EDID data. */
71 if (mb_get_edid(edid_data) != CB_SUCCESS) {
72 printk(BIOS_ERR, "PTN3460 error: Unable to get EDID data from mainboard.\n");
73 return;
74 }
75
76 /* Mainboard decides which EDID table has to be used. */
77 edid_tab = mb_select_edid_table();
78 if (edid_tab > PTN_MAX_EDID_NUM) {
79 printk(BIOS_ERR, "PTN3460 error: invalid EDID table (%d) selected.\n",
80 edid_tab);
81 return;
82 }
83 /* Write EDID data into PTN. */
84 val = ptn3460_write_edid(dev, edid_tab, edid_data);
85 if (val != PTN_SUCCESS) {
86 printk(BIOS_ERR, "PTN3460 error: writing EDID data into device failed.\n");
87 return;
88 }
89 /* Activate the selected EDID block. */
90 ptn_select_edid(dev, edid_tab);
91 /* Read out PTN configuration data. */
92 for (i = 0; i < sizeof(struct ptn_3460_config); i++) {
93 val = i2c_dev_readb_at(dev, PTN_CONFIG_OFF + i);
94 if (val < 0) {
95 printk(BIOS_ERR,
96 "PTN3460 error: Unable to read config data from device.\n");
97 return;
98 }
99 *ptr++ = (uint8_t)val; /* fill config structure via ptr */
100 }
101 /* Mainboard can modify the configuration data.
102 Write back configuration data to PTN3460 if modified by mainboard */
103 if (mb_adjust_cfg(&cfg) == PTN_CFG_MODIFIED) {
104 ptr = (uint8_t *) &cfg;
105 for (i = 0; i < sizeof(struct ptn_3460_config); i++) {
106 val = i2c_dev_writeb_at(dev, PTN_CONFIG_OFF + i, *ptr++);
107 if (val < 0) {
108 printk(BIOS_ERR,
109 "PTN3460 error: Unable to write config data.\n");
110 return;
111 }
112 }
113 }
114}
115
116__weak enum cb_err mb_get_edid(uint8_t edid_data[0x80])
117{
118 return CB_ERR;
119}
120__weak uint8_t mb_select_edid_table(void)
121{
122 return 0;
123}
124__weak int mb_adjust_cfg(struct ptn_3460_config *cfg_ptr)
125{
126 return 0;
127}
128
129static struct device_operations ptn3460_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +0200130 .read_resources = noop_read_resources,
131 .set_resources = noop_set_resources,
Uwe Poeche11a34ec2019-10-28 11:28:50 +0100132 .init = ptn3460_init,
Uwe Poeche11a34ec2019-10-28 11:28:50 +0100133};
134
135static void ptn3460_enable(struct device *dev)
136{
137 dev->ops = &ptn3460_ops;
138}
139
140struct chip_operations drivers_i2c_ptn3460_ops = {
141 CHIP_NAME("PTN3460")
142 .enable_dev = ptn3460_enable
143};