diff options
Diffstat (limited to 'src/drivers')
-rw-r--r-- | src/drivers/i2c/ptn3460/Kconfig | 5 | ||||
-rw-r--r-- | src/drivers/i2c/ptn3460/Makefile.inc | 1 | ||||
-rw-r--r-- | src/drivers/i2c/ptn3460/chip.h | 3 | ||||
-rw-r--r-- | src/drivers/i2c/ptn3460/ptn3460.c | 157 | ||||
-rw-r--r-- | src/drivers/i2c/ptn3460/ptn3460.h | 73 |
5 files changed, 239 insertions, 0 deletions
diff --git a/src/drivers/i2c/ptn3460/Kconfig b/src/drivers/i2c/ptn3460/Kconfig new file mode 100644 index 0000000000..6dcdbc0915 --- /dev/null +++ b/src/drivers/i2c/ptn3460/Kconfig @@ -0,0 +1,5 @@ +config DRIVERS_I2C_PTN3460 + bool + default n + help + Enable support for external display bridge (eDP to LVDS) PTN3460. diff --git a/src/drivers/i2c/ptn3460/Makefile.inc b/src/drivers/i2c/ptn3460/Makefile.inc new file mode 100644 index 0000000000..abe9a0560b --- /dev/null +++ b/src/drivers/i2c/ptn3460/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_DRIVERS_I2C_PTN3460) += ptn3460.c diff --git a/src/drivers/i2c/ptn3460/chip.h b/src/drivers/i2c/ptn3460/chip.h new file mode 100644 index 0000000000..8bd6d9e7d1 --- /dev/null +++ b/src/drivers/i2c/ptn3460/chip.h @@ -0,0 +1,3 @@ +struct drivers_i2c_ptn3460_config { + +}; diff --git a/src/drivers/i2c/ptn3460/ptn3460.c b/src/drivers/i2c/ptn3460/ptn3460.c new file mode 100644 index 0000000000..ef25745ed1 --- /dev/null +++ b/src/drivers/i2c/ptn3460/ptn3460.c @@ -0,0 +1,157 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#include <console/console.h> +#include <device/i2c_bus.h> +#include <types.h> + +#include "ptn3460.h" + +/** + * \brief This function selects one of 7 EDID-tables inside PTN3460 + * which should be emulated on display port and turn emulation ON + * @param *dev Pointer to the relevant I2C controller + * @param edid_num Number of EDID to emulate (0..6) + * @return PTN_SUCCESS or error code + */ +static int ptn_select_edid(struct device *dev, uint8_t edid_num) +{ + int status = 0; + u8 val; + + if (edid_num > PTN_MAX_EDID_NUM) + return PTN_INVALID_EDID; + val = (edid_num << 1) | PTN_ENABLE_EMULATION; + status = i2c_dev_writeb_at(dev, PTN_CONFIG_OFF + 4, val); + return status ? (PTN_BUS_ERROR | status) : PTN_SUCCESS; +} + +/** + * \brief This function writes one EDID data structure to PTN3460 + * @param *dev Pointer to the relevant I2C controller + * @param edid_num Number of EDID that must be written (0..6) + * @param *data Pointer to a buffer where data to write is stored in + * @return PTN_SUCCESS on success or error code + */ +static int ptn3460_write_edid(struct device *dev, u8 edid_num, u8 *data) +{ + int status; + int i; + + if (edid_num > PTN_MAX_EDID_NUM) + return PTN_INVALID_EDID; + + /* First enable access to the desired EDID table */ + status = i2c_dev_writeb_at(dev, PTN_CONFIG_OFF + 5, edid_num); + if (status) + return (PTN_BUS_ERROR | status); + + /* Now we can simply write EDID data to ptn3460 */ + for (i = 0; i < PTN_EDID_LEN; i++) { + status = i2c_dev_writeb_at(dev, PTN_EDID_OFF + i, data[i]); + if (status) + return (PTN_BUS_ERROR | status); + } + return PTN_SUCCESS; +} + +/** + * \brief This function sets up the DP2LVDS-converter to be used with the + * appropriate EDID data + * @param *dev Pointer to the I2C controller where PTN3460 is attached + */ +static void ptn3460_init(struct device *dev) +{ + struct ptn_3460_config cfg; + uint8_t edid_data[PTN_EDID_LEN], edid_tab, *ptr = (uint8_t *) &cfg; + int i, val; + + /* Mainboard provides EDID data. */ + if (mb_get_edid(edid_data) != CB_SUCCESS) { + printk(BIOS_ERR, "PTN3460 error: Unable to get EDID data from mainboard.\n"); + return; + } + + /* Mainboard decides which EDID table has to be used. */ + edid_tab = mb_select_edid_table(); + if (edid_tab > PTN_MAX_EDID_NUM) { + printk(BIOS_ERR, "PTN3460 error: invalid EDID table (%d) selected.\n", + edid_tab); + return; + } + /* Write EDID data into PTN. */ + val = ptn3460_write_edid(dev, edid_tab, edid_data); + if (val != PTN_SUCCESS) { + printk(BIOS_ERR, "PTN3460 error: writing EDID data into device failed.\n"); + return; + } + /* Activate the selected EDID block. */ + ptn_select_edid(dev, edid_tab); + /* Read out PTN configuration data. */ + for (i = 0; i < sizeof(struct ptn_3460_config); i++) { + val = i2c_dev_readb_at(dev, PTN_CONFIG_OFF + i); + if (val < 0) { + printk(BIOS_ERR, + "PTN3460 error: Unable to read config data from device.\n"); + return; + } + *ptr++ = (uint8_t)val; /* fill config structure via ptr */ + } + /* Mainboard can modify the configuration data. + Write back configuration data to PTN3460 if modified by mainboard */ + if (mb_adjust_cfg(&cfg) == PTN_CFG_MODIFIED) { + ptr = (uint8_t *) &cfg; + for (i = 0; i < sizeof(struct ptn_3460_config); i++) { + val = i2c_dev_writeb_at(dev, PTN_CONFIG_OFF + i, *ptr++); + if (val < 0) { + printk(BIOS_ERR, + "PTN3460 error: Unable to write config data.\n"); + return; + } + } + } +} + +__weak enum cb_err mb_get_edid(uint8_t edid_data[0x80]) +{ + return CB_ERR; +} +__weak uint8_t mb_select_edid_table(void) +{ + return 0; +} +__weak int mb_adjust_cfg(struct ptn_3460_config *cfg_ptr) +{ + return 0; +} + +static struct device_operations ptn3460_ops = { + .read_resources = DEVICE_NOOP, + .set_resources = DEVICE_NOOP, + .enable_resources = DEVICE_NOOP, + .init = ptn3460_init, + .final = DEVICE_NOOP +}; + +static void ptn3460_enable(struct device *dev) +{ + dev->ops = &ptn3460_ops; +} + +struct chip_operations drivers_i2c_ptn3460_ops = { + CHIP_NAME("PTN3460") + .enable_dev = ptn3460_enable +}; diff --git a/src/drivers/i2c/ptn3460/ptn3460.h b/src/drivers/i2c/ptn3460/ptn3460.h new file mode 100644 index 0000000000..4b9834eb9d --- /dev/null +++ b/src/drivers/i2c/ptn3460/ptn3460.h @@ -0,0 +1,73 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _I2C_PTN3460_H_ +#define _I2C_PTN3460_H_ + +#include <stdint.h> + +#define PTN_EDID_OFF 0x00 +#define PTN_EDID_LEN 0x80 +#define PTN_CONFIG_OFF 0x80 +#define PTN_CONFIG_LEN 0x19 +#define PTN_FLASH_CFG_OFF 0xE8 +#define PTN_FLASH_CFG_LEN 0x04 +#define PTN_MAX_EDID_NUM 6 +#define PTN_ENABLE_EMULATION (1 << 0) + +/* Define some error codes that can be used */ +#define PTN_SUCCESS 0x00000000 +#define PTN_CFG_MODIFIED 0x00000001 +#define PTN_BUS_ERROR 0x10000000 +#define PTN_INVALID_EDID 0x20000000 +#define PTN_INVALID_EDID_BLOCK 0x30000000 +#define PTN_ERROR 0x40000000 + +struct ptn_3460_config { + u8 dp_interface_ctrl; /* DisplayPort interface control */ + u8 lvds_interface_ctrl1; /* LVDS interface control register 1 */ + u8 lvds_interface_ctrl2; /* LVDS interface control register 2 */ + u8 lvds_interface_ctrl3; /* LVDS interface control register 3 */ + u8 edid_rom_emulation; /* select which EDID-block is emulated */ + u8 edid_rom_access_ctrl; /* select which EDID block to map to 0..0x7F */ + u8 pwm_min[3]; /* smallest PWM frequency for back light */ + u8 pwm_max[3]; /* biggest PWM frequency for back light */ + u8 fast_link_ctrl; /* Fast link training control register */ + u8 pin_cfg_ctrl1; /* Pin configuration control register 1 */ + u8 pin_cfg_ctrl2; /* Pin configuration control register 2 */ + u8 pwm_default; /* Default PWM bit count in DPCD register */ + u16 pwm_value; /* Current PWM bit count in DPCD register */ + u8 pwm_default_freq; /* Default PWM frequency in DPCD register */ + u8 t3_timing; /* Panel T3 timing value */ + u8 t12_timing; /* Panel T12 timing value */ + u8 backlight_ctrl; /* Back light control register */ + u8 t2_delay; /* Panel T2 delay */ + u8 t4_timing; /* Panel T4 timing value */ + u8 t5_delay; /* Panel T5 delay */ +} __packed; + +struct ptn_3460_flash { + u8 cmd; /* Flash command (erase or erase and flash) */ + u16 magic; /* Magic number needed by the flash algorithm */ + u8 trigger; /* Trigger for starting flash operation */ +} __packed; + +/* We need functions which we can call to get mainboard specific data */ +/* These functions can be implemented somewhere else but must exist. */ +extern enum cb_err mb_get_edid(uint8_t edid_data[0x80]); +extern uint8_t mb_select_edid_table(void); +extern int mb_adjust_cfg(struct ptn_3460_config *cfg_ptr); + +#endif /* _I2C_PTN3460_H_ */ |