mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
Merge git://git.denx.de/u-boot-video
This commit is contained in:
commit
2d5e6b4aac
21 changed files with 1025 additions and 209 deletions
|
@ -124,5 +124,8 @@ void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc,
|
|||
void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc,
|
||||
const struct display_timing *mode,
|
||||
bool ext_hvsync, bool is_composite);
|
||||
void lcdc_pll_set(struct sunxi_ccm_reg * const ccm, int tcon,
|
||||
int dotclock, int *clk_div, int *clk_double,
|
||||
bool is_composite);
|
||||
|
||||
#endif /* _LCDC_H */
|
||||
|
|
|
@ -606,7 +606,7 @@ config AXP_GPIO
|
|||
---help---
|
||||
Say Y here to enable support for the gpio pins of the axp PMIC ICs.
|
||||
|
||||
config VIDEO
|
||||
config VIDEO_SUNXI
|
||||
bool "Enable graphical uboot console on HDMI, LCD or VGA"
|
||||
depends on !MACH_SUN8I_A83T
|
||||
depends on !MACH_SUNXI_H3_H5
|
||||
|
@ -614,6 +614,8 @@ config VIDEO
|
|||
depends on !MACH_SUN8I_V3S
|
||||
depends on !MACH_SUN9I
|
||||
depends on !MACH_SUN50I
|
||||
select VIDEO
|
||||
imply VIDEO_DT_SIMPLEFB
|
||||
default y
|
||||
---help---
|
||||
Say Y here to add support for using a cfb console on the HDMI, LCD
|
||||
|
@ -622,21 +624,21 @@ config VIDEO
|
|||
|
||||
config VIDEO_HDMI
|
||||
bool "HDMI output support"
|
||||
depends on VIDEO && !MACH_SUN8I
|
||||
depends on VIDEO_SUNXI && !MACH_SUN8I
|
||||
default y
|
||||
---help---
|
||||
Say Y here to add support for outputting video over HDMI.
|
||||
|
||||
config VIDEO_VGA
|
||||
bool "VGA output support"
|
||||
depends on VIDEO && (MACH_SUN4I || MACH_SUN7I)
|
||||
depends on VIDEO_SUNXI && (MACH_SUN4I || MACH_SUN7I)
|
||||
default n
|
||||
---help---
|
||||
Say Y here to add support for outputting video over VGA.
|
||||
|
||||
config VIDEO_VGA_VIA_LCD
|
||||
bool "VGA via LCD controller support"
|
||||
depends on VIDEO && (MACH_SUN5I || MACH_SUN6I || MACH_SUN8I)
|
||||
depends on VIDEO_SUNXI && (MACH_SUN5I || MACH_SUN6I || MACH_SUN8I)
|
||||
default n
|
||||
---help---
|
||||
Say Y here to add support for external DACs connected to the parallel
|
||||
|
@ -663,14 +665,14 @@ config VIDEO_VGA_EXTERNAL_DAC_EN
|
|||
|
||||
config VIDEO_COMPOSITE
|
||||
bool "Composite video output support"
|
||||
depends on VIDEO && (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I)
|
||||
depends on VIDEO_SUNXI && (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I)
|
||||
default n
|
||||
---help---
|
||||
Say Y here to add support for outputting composite video.
|
||||
|
||||
config VIDEO_LCD_MODE
|
||||
string "LCD panel timing details"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI
|
||||
default ""
|
||||
---help---
|
||||
LCD panel timing details string, leave empty if there is no LCD panel.
|
||||
|
@ -680,14 +682,14 @@ config VIDEO_LCD_MODE
|
|||
|
||||
config VIDEO_LCD_DCLK_PHASE
|
||||
int "LCD panel display clock phase"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI || DM_VIDEO
|
||||
default 1
|
||||
---help---
|
||||
Select LCD panel display clock phase shift, range 0-3.
|
||||
|
||||
config VIDEO_LCD_POWER
|
||||
string "LCD panel power enable pin"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI
|
||||
default ""
|
||||
---help---
|
||||
Set the power enable pin for the LCD panel. This takes a string in the
|
||||
|
@ -695,7 +697,7 @@ config VIDEO_LCD_POWER
|
|||
|
||||
config VIDEO_LCD_RESET
|
||||
string "LCD panel reset pin"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI
|
||||
default ""
|
||||
---help---
|
||||
Set the reset pin for the LCD panel. This takes a string in the format
|
||||
|
@ -703,7 +705,7 @@ config VIDEO_LCD_RESET
|
|||
|
||||
config VIDEO_LCD_BL_EN
|
||||
string "LCD panel backlight enable pin"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI
|
||||
default ""
|
||||
---help---
|
||||
Set the backlight enable pin for the LCD panel. This takes a string in the
|
||||
|
@ -712,7 +714,7 @@ config VIDEO_LCD_BL_EN
|
|||
|
||||
config VIDEO_LCD_BL_PWM
|
||||
string "LCD panel backlight pwm pin"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI
|
||||
default ""
|
||||
---help---
|
||||
Set the backlight pwm pin for the LCD panel. This takes a string in the
|
||||
|
@ -720,14 +722,14 @@ config VIDEO_LCD_BL_PWM
|
|||
|
||||
config VIDEO_LCD_BL_PWM_ACTIVE_LOW
|
||||
bool "LCD panel backlight pwm is inverted"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI
|
||||
default y
|
||||
---help---
|
||||
Set this if the backlight pwm output is active low.
|
||||
|
||||
config VIDEO_LCD_PANEL_I2C
|
||||
bool "LCD panel needs to be configured via i2c"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI
|
||||
default n
|
||||
select CMD_I2C
|
||||
---help---
|
||||
|
@ -768,6 +770,7 @@ config VIDEO_DE2
|
|||
depends on SUNXI_DE2
|
||||
select DM_VIDEO
|
||||
select DISPLAY
|
||||
imply VIDEO_DT_SIMPLEFB
|
||||
default y
|
||||
---help---
|
||||
Say y here if you want to build DE2 video driver which is present on
|
||||
|
@ -776,7 +779,7 @@ config VIDEO_DE2
|
|||
|
||||
choice
|
||||
prompt "LCD panel support"
|
||||
depends on VIDEO
|
||||
depends on VIDEO_SUNXI
|
||||
---help---
|
||||
Select which type of LCD panel to support.
|
||||
|
||||
|
|
|
@ -650,4 +650,12 @@ config VIDEO_SIMPLE
|
|||
before u-boot starts, and u-boot will simply render to the pre-
|
||||
allocated frame buffer surface.
|
||||
|
||||
config VIDEO_DT_SIMPLEFB
|
||||
bool "Enable SimpleFB support for passing framebuffer to OS"
|
||||
help
|
||||
Enables the code to pass the framebuffer to the kernel as a
|
||||
simple framebuffer in the device tree.
|
||||
The video output is initialized by U-Boot, and kept by the
|
||||
kernel.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -12,61 +12,9 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <i2c.h>
|
||||
#include "anx98xx-edp.h"
|
||||
#include "anx9804.h"
|
||||
|
||||
/* Registers at i2c address 0x38 */
|
||||
|
||||
#define ANX9804_HDCP_CONTROL_0_REG 0x01
|
||||
|
||||
#define ANX9804_SYS_CTRL2_REG 0x81
|
||||
#define ANX9804_SYS_CTRL2_CHA_STA 0x04
|
||||
|
||||
#define ANX9804_SYS_CTRL3_REG 0x82
|
||||
#define ANX9804_SYS_CTRL3_VALID_CTRL BIT(0)
|
||||
#define ANX9804_SYS_CTRL3_F_VALID BIT(1)
|
||||
#define ANX9804_SYS_CTRL3_HPD_CTRL BIT(4)
|
||||
#define ANX9804_SYS_CTRL3_F_HPD BIT(5)
|
||||
|
||||
#define ANX9804_LINK_BW_SET_REG 0xa0
|
||||
#define ANX9804_LANE_COUNT_SET_REG 0xa1
|
||||
#define ANX9804_TRAINING_PTN_SET_REG 0xa2
|
||||
#define ANX9804_TRAINING_LANE0_SET_REG 0xa3
|
||||
#define ANX9804_TRAINING_LANE1_SET_REG 0xa4
|
||||
#define ANX9804_TRAINING_LANE2_SET_REG 0xa5
|
||||
#define ANX9804_TRAINING_LANE3_SET_REG 0xa6
|
||||
|
||||
#define ANX9804_LINK_TRAINING_CTRL_REG 0xa8
|
||||
#define ANX9804_LINK_TRAINING_CTRL_EN BIT(0)
|
||||
|
||||
#define ANX9804_LINK_DEBUG_REG 0xb8
|
||||
#define ANX9804_PLL_CTRL_REG 0xc7
|
||||
#define ANX9804_ANALOG_POWER_DOWN_REG 0xc8
|
||||
|
||||
/* Registers at i2c address 0x39 */
|
||||
|
||||
#define ANX9804_DEV_IDH_REG 0x03
|
||||
|
||||
#define ANX9804_POWERD_CTRL_REG 0x05
|
||||
#define ANX9804_POWERD_AUDIO BIT(4)
|
||||
|
||||
#define ANX9804_RST_CTRL_REG 0x06
|
||||
|
||||
#define ANX9804_RST_CTRL2_REG 0x07
|
||||
#define ANX9804_RST_CTRL2_AUX BIT(2)
|
||||
#define ANX9804_RST_CTRL2_AC_MODE BIT(6)
|
||||
|
||||
#define ANX9804_VID_CTRL1_REG 0x08
|
||||
#define ANX9804_VID_CTRL1_VID_EN BIT(7)
|
||||
#define ANX9804_VID_CTRL1_EDGE BIT(0)
|
||||
|
||||
#define ANX9804_VID_CTRL2_REG 0x09
|
||||
#define ANX9804_ANALOG_DEBUG_REG1 0xdc
|
||||
#define ANX9804_ANALOG_DEBUG_REG3 0xde
|
||||
#define ANX9804_PLL_FILTER_CTRL1 0xdf
|
||||
#define ANX9804_PLL_FILTER_CTRL3 0xe1
|
||||
#define ANX9804_PLL_FILTER_CTRL 0xe2
|
||||
#define ANX9804_PLL_CTRL3 0xe6
|
||||
|
||||
/**
|
||||
* anx9804_init() - Init anx9804 parallel lcd to edp bridge chip
|
||||
*
|
||||
|
|
98
drivers/video/anx98xx-edp.h
Normal file
98
drivers/video/anx98xx-edp.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
|
||||
* Copyright (C) 2017 Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/* Registers at i2c address 0x38 */
|
||||
|
||||
#define ANX9804_HDCP_CONTROL_0_REG 0x01
|
||||
|
||||
#define ANX9804_SYS_CTRL1_REG 0x80
|
||||
#define ANX9804_SYS_CTRL1_PD_IO 0x80
|
||||
#define ANX9804_SYS_CTRL1_PD_VID 0x40
|
||||
#define ANX9804_SYS_CTRL1_PD_LINK 0x20
|
||||
#define ANX9804_SYS_CTRL1_PD_TOTAL 0x10
|
||||
#define ANX9804_SYS_CTRL1_MODE_SEL 0x08
|
||||
#define ANX9804_SYS_CTRL1_DET_STA 0x04
|
||||
#define ANX9804_SYS_CTRL1_FORCE_DET 0x02
|
||||
#define ANX9804_SYS_CTRL1_DET_CTRL 0x01
|
||||
|
||||
#define ANX9804_SYS_CTRL2_REG 0x81
|
||||
#define ANX9804_SYS_CTRL2_CHA_STA 0x04
|
||||
|
||||
#define ANX9804_SYS_CTRL3_REG 0x82
|
||||
#define ANX9804_SYS_CTRL3_VALID_CTRL BIT(0)
|
||||
#define ANX9804_SYS_CTRL3_F_VALID BIT(1)
|
||||
#define ANX9804_SYS_CTRL3_HPD_CTRL BIT(4)
|
||||
#define ANX9804_SYS_CTRL3_F_HPD BIT(5)
|
||||
|
||||
#define ANX9804_LINK_BW_SET_REG 0xa0
|
||||
#define ANX9804_LANE_COUNT_SET_REG 0xa1
|
||||
#define ANX9804_TRAINING_PTN_SET_REG 0xa2
|
||||
#define ANX9804_TRAINING_LANE0_SET_REG 0xa3
|
||||
#define ANX9804_TRAINING_LANE1_SET_REG 0xa4
|
||||
#define ANX9804_TRAINING_LANE2_SET_REG 0xa5
|
||||
#define ANX9804_TRAINING_LANE3_SET_REG 0xa6
|
||||
|
||||
#define ANX9804_LINK_TRAINING_CTRL_REG 0xa8
|
||||
#define ANX9804_LINK_TRAINING_CTRL_EN BIT(0)
|
||||
|
||||
#define ANX9804_LINK_DEBUG_REG 0xb8
|
||||
#define ANX9804_PLL_CTRL_REG 0xc7
|
||||
#define ANX9804_ANALOG_POWER_DOWN_REG 0xc8
|
||||
|
||||
#define ANX9804_AUX_CH_STA 0xe0
|
||||
#define ANX9804_AUX_BUSY BIT(4)
|
||||
#define ANX9804_AUX_STATUS_MASK 0x0f
|
||||
|
||||
#define ANX9804_DP_AUX_RX_COMM 0xe3
|
||||
#define ANX9804_AUX_RX_COMM_I2C_DEFER BIT(3)
|
||||
#define ANX9804_AUX_RX_COMM_AUX_DEFER BIT(1)
|
||||
|
||||
#define ANX9804_DP_AUX_CH_CTL_1 0xe5
|
||||
#define ANX9804_AUX_LENGTH(x) (((x - 1) & 0x0f) << 4)
|
||||
#define ANX9804_AUX_TX_COMM_MASK 0x0f
|
||||
#define ANX9804_AUX_TX_COMM_DP_TRANSACTION BIT(3)
|
||||
#define ANX9804_AUX_TX_COMM_MOT BIT(2)
|
||||
#define ANX9804_AUX_TX_COMM_READ BIT(0)
|
||||
|
||||
#define ANX9804_DP_AUX_ADDR_7_0 0xe6
|
||||
#define ANX9804_DP_AUX_ADDR_15_8 0xe7
|
||||
#define ANX9804_DP_AUX_ADDR_19_16 0xe8
|
||||
|
||||
#define ANX9804_DP_AUX_CH_CTL_2 0xe9
|
||||
#define ANX9804_ADDR_ONLY BIT(1)
|
||||
#define ANX9804_AUX_EN BIT(0)
|
||||
|
||||
#define ANX9804_BUF_DATA_0 0xf0
|
||||
|
||||
/* Registers at i2c address 0x39 */
|
||||
|
||||
#define ANX9804_DEV_IDH_REG 0x03
|
||||
|
||||
#define ANX9804_POWERD_CTRL_REG 0x05
|
||||
#define ANX9804_POWERD_AUDIO BIT(4)
|
||||
|
||||
#define ANX9804_RST_CTRL_REG 0x06
|
||||
|
||||
#define ANX9804_RST_CTRL2_REG 0x07
|
||||
#define ANX9804_RST_CTRL2_AUX BIT(2)
|
||||
#define ANX9804_RST_CTRL2_AC_MODE BIT(6)
|
||||
|
||||
#define ANX9804_VID_CTRL1_REG 0x08
|
||||
#define ANX9804_VID_CTRL1_VID_EN BIT(7)
|
||||
#define ANX9804_VID_CTRL1_EDGE BIT(0)
|
||||
|
||||
#define ANX9804_VID_CTRL2_REG 0x09
|
||||
#define ANX9804_ANALOG_DEBUG_REG1 0xdc
|
||||
#define ANX9804_ANALOG_DEBUG_REG3 0xde
|
||||
#define ANX9804_PLL_FILTER_CTRL1 0xdf
|
||||
#define ANX9804_PLL_FILTER_CTRL3 0xe1
|
||||
#define ANX9804_PLL_FILTER_CTRL 0xe2
|
||||
#define ANX9804_PLL_CTRL3 0xe6
|
||||
|
||||
#define ANX9804_DP_INT_STA 0xf7
|
||||
#define ANX9804_RPLY_RECEIV BIT(1)
|
||||
#define ANX9804_AUX_ERR BIT(0)
|
|
@ -25,3 +25,11 @@ config VIDEO_BRIDGE_NXP_PTN3460
|
|||
signalling) converter. It enables an LVDS LCD panel to be connected
|
||||
to an eDP output device such as an SoC that lacks LVDS capability,
|
||||
or where LVDS requires too many signals to route on the PCB.
|
||||
|
||||
config VIDEO_BRIDGE_ANALOGIX_ANX6345
|
||||
bool "Support Analogix ANX6345 RGB->DP bridge"
|
||||
depends on VIDEO_BRIDGE
|
||||
select DM_I2C
|
||||
help
|
||||
The Analogix ANX6345 is RGB-to-DP converter. It enables an eDP LCD
|
||||
panel to be connected to an parallel LCD interface.
|
||||
|
|
|
@ -7,3 +7,4 @@
|
|||
obj-$(CONFIG_VIDEO_BRIDGE) += video-bridge-uclass.o
|
||||
obj-$(CONFIG_VIDEO_BRIDGE_PARADE_PS862X) += ps862x.o
|
||||
obj-$(CONFIG_VIDEO_BRIDGE_NXP_PTN3460) += ptn3460.o
|
||||
obj-$(CONFIG_VIDEO_BRIDGE_ANALOGIX_ANX6345) += anx6345.o
|
||||
|
|
426
drivers/video/bridge/anx6345.c
Normal file
426
drivers/video/bridge/anx6345.c
Normal file
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <i2c.h>
|
||||
#include <edid.h>
|
||||
#include <video_bridge.h>
|
||||
#include "../anx98xx-edp.h"
|
||||
|
||||
#define DP_MAX_LINK_RATE 0x001
|
||||
#define DP_MAX_LANE_COUNT 0x002
|
||||
#define DP_MAX_LANE_COUNT_MASK 0x1f
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct anx6345_priv {
|
||||
u8 edid[EDID_SIZE];
|
||||
};
|
||||
|
||||
static int anx6345_write(struct udevice *dev, unsigned int addr_off,
|
||||
unsigned char reg_addr, unsigned char value)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
|
||||
msg.addr = addr_off;
|
||||
msg.flags = 0;
|
||||
buf[0] = reg_addr;
|
||||
buf[1] = value;
|
||||
msg.buf = buf;
|
||||
msg.len = 2;
|
||||
ret = dm_i2c_xfer(dev, &msg, 1);
|
||||
if (ret) {
|
||||
debug("%s: write failed, reg=%#x, value=%#x, ret=%d\n",
|
||||
__func__, reg_addr, value, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anx6345_read(struct udevice *dev, unsigned int addr_off,
|
||||
unsigned char reg_addr, unsigned char *value)
|
||||
{
|
||||
uint8_t addr, val;
|
||||
struct i2c_msg msg[2];
|
||||
int ret;
|
||||
|
||||
msg[0].addr = addr_off;
|
||||
msg[0].flags = 0;
|
||||
addr = reg_addr;
|
||||
msg[0].buf = &addr;
|
||||
msg[0].len = 1;
|
||||
msg[1].addr = addr_off;
|
||||
msg[1].flags = I2C_M_RD;
|
||||
msg[1].buf = &val;
|
||||
msg[1].len = 1;
|
||||
ret = dm_i2c_xfer(dev, msg, 2);
|
||||
if (ret) {
|
||||
debug("%s: read failed, reg=%.2x, value=%p, ret=%d\n",
|
||||
__func__, (int)reg_addr, value, ret);
|
||||
return ret;
|
||||
}
|
||||
*value = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anx6345_write_r0(struct udevice *dev, unsigned char reg_addr,
|
||||
unsigned char value)
|
||||
{
|
||||
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
|
||||
|
||||
return anx6345_write(dev, chip->chip_addr, reg_addr, value);
|
||||
}
|
||||
|
||||
static int anx6345_read_r0(struct udevice *dev, unsigned char reg_addr,
|
||||
unsigned char *value)
|
||||
{
|
||||
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
|
||||
|
||||
return anx6345_read(dev, chip->chip_addr, reg_addr, value);
|
||||
}
|
||||
|
||||
static int anx6345_write_r1(struct udevice *dev, unsigned char reg_addr,
|
||||
unsigned char value)
|
||||
{
|
||||
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
|
||||
|
||||
return anx6345_write(dev, chip->chip_addr + 1, reg_addr, value);
|
||||
}
|
||||
|
||||
static int anx6345_read_r1(struct udevice *dev, unsigned char reg_addr,
|
||||
unsigned char *value)
|
||||
{
|
||||
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
|
||||
|
||||
return anx6345_read(dev, chip->chip_addr + 1, reg_addr, value);
|
||||
}
|
||||
|
||||
static int anx6345_set_backlight(struct udevice *dev, int percent)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int anx6345_aux_wait(struct udevice *dev)
|
||||
{
|
||||
int ret = -ETIMEDOUT;
|
||||
u8 v;
|
||||
int retries = 1000;
|
||||
|
||||
do {
|
||||
anx6345_read_r0(dev, ANX9804_DP_AUX_CH_CTL_2, &v);
|
||||
if (!(v & ANX9804_AUX_EN)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
udelay(100);
|
||||
} while (retries--);
|
||||
|
||||
if (ret) {
|
||||
debug("%s: timed out waiting for AUX_EN to clear\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = -ETIMEDOUT;
|
||||
retries = 1000;
|
||||
do {
|
||||
anx6345_read_r1(dev, ANX9804_DP_INT_STA, &v);
|
||||
if (v & ANX9804_RPLY_RECEIV) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
udelay(100);
|
||||
} while (retries--);
|
||||
|
||||
if (ret) {
|
||||
debug("%s: timed out waiting to receive reply\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Clear RPLY_RECEIV bit */
|
||||
anx6345_write_r1(dev, ANX9804_DP_INT_STA, v);
|
||||
|
||||
anx6345_read_r0(dev, ANX9804_AUX_CH_STA, &v);
|
||||
if ((v & ANX9804_AUX_STATUS_MASK) != 0) {
|
||||
debug("AUX status: %d\n", v & ANX9804_AUX_STATUS_MASK);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void anx6345_aux_addr(struct udevice *dev, u32 addr)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
val = addr & 0xff;
|
||||
anx6345_write_r0(dev, ANX9804_DP_AUX_ADDR_7_0, val);
|
||||
val = (addr >> 8) & 0xff;
|
||||
anx6345_write_r0(dev, ANX9804_DP_AUX_ADDR_15_8, val);
|
||||
val = (addr >> 16) & 0x0f;
|
||||
anx6345_write_r0(dev, ANX9804_DP_AUX_ADDR_19_16, val);
|
||||
}
|
||||
|
||||
static int anx6345_aux_transfer(struct udevice *dev, u8 req,
|
||||
u32 addr, u8 *buf, size_t len)
|
||||
{
|
||||
int i, ret;
|
||||
u8 ctrl1 = req;
|
||||
u8 ctrl2 = ANX9804_AUX_EN;
|
||||
|
||||
if (len > 16)
|
||||
return -E2BIG;
|
||||
|
||||
if (len)
|
||||
ctrl1 |= ANX9804_AUX_LENGTH(len);
|
||||
else
|
||||
ctrl2 |= ANX9804_ADDR_ONLY;
|
||||
|
||||
if (len && !(req & ANX9804_AUX_TX_COMM_READ)) {
|
||||
for (i = 0; i < len; i++)
|
||||
anx6345_write_r0(dev, ANX9804_BUF_DATA_0 + i, buf[i]);
|
||||
}
|
||||
|
||||
anx6345_aux_addr(dev, addr);
|
||||
anx6345_write_r0(dev, ANX9804_DP_AUX_CH_CTL_1, ctrl1);
|
||||
anx6345_write_r0(dev, ANX9804_DP_AUX_CH_CTL_2, ctrl2);
|
||||
ret = anx6345_aux_wait(dev);
|
||||
if (ret) {
|
||||
debug("AUX transaction timed out\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (len && (req & ANX9804_AUX_TX_COMM_READ)) {
|
||||
for (i = 0; i < len; i++)
|
||||
anx6345_read_r0(dev, ANX9804_BUF_DATA_0 + i, &buf[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anx6345_read_aux_i2c(struct udevice *dev, u8 chip_addr,
|
||||
u8 offset, size_t count, u8 *buf)
|
||||
{
|
||||
int i, ret;
|
||||
size_t cur_cnt;
|
||||
u8 cur_offset;
|
||||
|
||||
for (i = 0; i < count; i += 16) {
|
||||
cur_cnt = (count - i) > 16 ? 16 : count - i;
|
||||
cur_offset = offset + i;
|
||||
ret = anx6345_aux_transfer(dev, ANX9804_AUX_TX_COMM_MOT,
|
||||
chip_addr, &cur_offset, 1);
|
||||
if (ret) {
|
||||
debug("%s: failed to set i2c offset: %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
ret = anx6345_aux_transfer(dev, ANX9804_AUX_TX_COMM_READ,
|
||||
chip_addr, buf + i, cur_cnt);
|
||||
if (ret) {
|
||||
debug("%s: failed to read from i2c device: %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anx6345_read_dpcd(struct udevice *dev, u32 reg, u8 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = anx6345_aux_transfer(dev,
|
||||
ANX9804_AUX_TX_COMM_READ |
|
||||
ANX9804_AUX_TX_COMM_DP_TRANSACTION,
|
||||
reg, val, 1);
|
||||
if (ret) {
|
||||
debug("Failed to read DPCD\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anx6345_read_edid(struct udevice *dev, u8 *buf, int size)
|
||||
{
|
||||
struct anx6345_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (size > EDID_SIZE)
|
||||
size = EDID_SIZE;
|
||||
memcpy(buf, priv->edid, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int anx6345_attach(struct udevice *dev)
|
||||
{
|
||||
/* No-op */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anx6345_enable(struct udevice *dev)
|
||||
{
|
||||
u8 chipid, colordepth, lanes, data_rate, c;
|
||||
int ret, i, bpp;
|
||||
struct display_timing timing;
|
||||
struct anx6345_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* Deassert reset and enable power */
|
||||
ret = video_bridge_set_active(dev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Reset */
|
||||
anx6345_write_r1(dev, ANX9804_RST_CTRL_REG, 1);
|
||||
mdelay(100);
|
||||
anx6345_write_r1(dev, ANX9804_RST_CTRL_REG, 0);
|
||||
|
||||
/* Write 0 to the powerdown reg (powerup everything) */
|
||||
anx6345_write_r1(dev, ANX9804_POWERD_CTRL_REG, 0);
|
||||
|
||||
ret = anx6345_read_r1(dev, ANX9804_DEV_IDH_REG, &chipid);
|
||||
if (ret)
|
||||
debug("%s: read id failed: %d\n", __func__, ret);
|
||||
|
||||
switch (chipid) {
|
||||
case 0x63:
|
||||
debug("ANX63xx detected.\n");
|
||||
break;
|
||||
default:
|
||||
debug("Error anx6345 chipid mismatch: %.2x\n", (int)chipid);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
anx6345_read_r0(dev, ANX9804_SYS_CTRL2_REG, &c);
|
||||
anx6345_write_r0(dev, ANX9804_SYS_CTRL2_REG, c);
|
||||
anx6345_read_r0(dev, ANX9804_SYS_CTRL2_REG, &c);
|
||||
if ((c & ANX9804_SYS_CTRL2_CHA_STA) == 0)
|
||||
break;
|
||||
|
||||
mdelay(5);
|
||||
}
|
||||
if (i == 100)
|
||||
debug("Error anx6345 clock is not stable\n");
|
||||
|
||||
/* Set a bunch of analog related register values */
|
||||
anx6345_write_r0(dev, ANX9804_PLL_CTRL_REG, 0x00);
|
||||
anx6345_write_r1(dev, ANX9804_ANALOG_DEBUG_REG1, 0x70);
|
||||
anx6345_write_r0(dev, ANX9804_LINK_DEBUG_REG, 0x30);
|
||||
|
||||
/* Force HPD */
|
||||
anx6345_write_r0(dev, ANX9804_SYS_CTRL3_REG,
|
||||
ANX9804_SYS_CTRL3_F_HPD | ANX9804_SYS_CTRL3_HPD_CTRL);
|
||||
|
||||
/* Power up and configure lanes */
|
||||
anx6345_write_r0(dev, ANX9804_ANALOG_POWER_DOWN_REG, 0x00);
|
||||
anx6345_write_r0(dev, ANX9804_TRAINING_LANE0_SET_REG, 0x00);
|
||||
anx6345_write_r0(dev, ANX9804_TRAINING_LANE1_SET_REG, 0x00);
|
||||
anx6345_write_r0(dev, ANX9804_TRAINING_LANE2_SET_REG, 0x00);
|
||||
anx6345_write_r0(dev, ANX9804_TRAINING_LANE3_SET_REG, 0x00);
|
||||
|
||||
/* Reset AUX CH */
|
||||
anx6345_write_r1(dev, ANX9804_RST_CTRL2_REG,
|
||||
ANX9804_RST_CTRL2_AUX);
|
||||
anx6345_write_r1(dev, ANX9804_RST_CTRL2_REG, 0);
|
||||
|
||||
/* Powerdown audio and some other unused bits */
|
||||
anx6345_write_r1(dev, ANX9804_POWERD_CTRL_REG, ANX9804_POWERD_AUDIO);
|
||||
anx6345_write_r0(dev, ANX9804_HDCP_CONTROL_0_REG, 0x00);
|
||||
anx6345_write_r0(dev, 0xa7, 0x00);
|
||||
|
||||
anx6345_read_aux_i2c(dev, 0x50, 0x0, EDID_SIZE, priv->edid);
|
||||
if (edid_get_timing(priv->edid, EDID_SIZE, &timing, &bpp) != 0) {
|
||||
debug("Failed to parse EDID\n");
|
||||
return -EIO;
|
||||
}
|
||||
debug("%s: panel found: %dx%d, bpp %d\n", __func__,
|
||||
timing.hactive.typ, timing.vactive.typ, bpp);
|
||||
if (bpp == 6)
|
||||
colordepth = 0x00; /* 6 bit */
|
||||
else
|
||||
colordepth = 0x10; /* 8 bit */
|
||||
anx6345_write_r1(dev, ANX9804_VID_CTRL2_REG, colordepth);
|
||||
|
||||
if (anx6345_read_dpcd(dev, DP_MAX_LINK_RATE, &data_rate)) {
|
||||
debug("%s: Failed to DP_MAX_LINK_RATE\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
debug("%s: data_rate: %d\n", __func__, (int)data_rate);
|
||||
if (anx6345_read_dpcd(dev, DP_MAX_LANE_COUNT, &lanes)) {
|
||||
debug("%s: Failed to read DP_MAX_LANE_COUNT\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
lanes &= DP_MAX_LANE_COUNT_MASK;
|
||||
debug("%s: lanes: %d\n", __func__, (int)lanes);
|
||||
|
||||
/* Set data-rate / lanes */
|
||||
anx6345_write_r0(dev, ANX9804_LINK_BW_SET_REG, data_rate);
|
||||
anx6345_write_r0(dev, ANX9804_LANE_COUNT_SET_REG, lanes);
|
||||
|
||||
/* Link training */
|
||||
anx6345_write_r0(dev, ANX9804_LINK_TRAINING_CTRL_REG,
|
||||
ANX9804_LINK_TRAINING_CTRL_EN);
|
||||
mdelay(5);
|
||||
for (i = 0; i < 100; i++) {
|
||||
anx6345_read_r0(dev, ANX9804_LINK_TRAINING_CTRL_REG, &c);
|
||||
if ((chipid == 0x63) && (c & 0x80) == 0)
|
||||
break;
|
||||
|
||||
mdelay(5);
|
||||
}
|
||||
if (i == 100) {
|
||||
debug("Error anx6345 link training timeout\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Enable */
|
||||
anx6345_write_r1(dev, ANX9804_VID_CTRL1_REG,
|
||||
ANX9804_VID_CTRL1_VID_EN | ANX9804_VID_CTRL1_EDGE);
|
||||
/* Force stream valid */
|
||||
anx6345_write_r0(dev, ANX9804_SYS_CTRL3_REG,
|
||||
ANX9804_SYS_CTRL3_F_HPD |
|
||||
ANX9804_SYS_CTRL3_HPD_CTRL |
|
||||
ANX9804_SYS_CTRL3_F_VALID |
|
||||
ANX9804_SYS_CTRL3_VALID_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anx6345_probe(struct udevice *dev)
|
||||
{
|
||||
if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
|
||||
return -EPROTONOSUPPORT;
|
||||
|
||||
return anx6345_enable(dev);
|
||||
}
|
||||
|
||||
struct video_bridge_ops anx6345_ops = {
|
||||
.attach = anx6345_attach,
|
||||
.set_backlight = anx6345_set_backlight,
|
||||
.read_edid = anx6345_read_edid,
|
||||
};
|
||||
|
||||
static const struct udevice_id anx6345_ids[] = {
|
||||
{ .compatible = "analogix,anx6345", },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(analogix_anx6345) = {
|
||||
.name = "analogix_anx6345",
|
||||
.id = UCLASS_VIDEO_BRIDGE,
|
||||
.of_match = anx6345_ids,
|
||||
.probe = anx6345_probe,
|
||||
.ops = &anx6345_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct anx6345_priv),
|
||||
};
|
|
@ -8,6 +8,7 @@
|
|||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <edid.h>
|
||||
#include <video_bridge.h>
|
||||
|
||||
int video_bridge_set_backlight(struct udevice *dev, int percent)
|
||||
|
@ -45,6 +46,15 @@ int video_bridge_check_attached(struct udevice *dev)
|
|||
return ops->check_attached(dev);
|
||||
}
|
||||
|
||||
int video_bridge_read_edid(struct udevice *dev, u8 *buf, int buf_size)
|
||||
{
|
||||
struct video_bridge_ops *ops = video_bridge_get_ops(dev);
|
||||
|
||||
if (!ops || !ops->read_edid)
|
||||
return -ENOSYS;
|
||||
return ops->read_edid(dev, buf, buf_size);
|
||||
}
|
||||
|
||||
static int video_bridge_pre_probe(struct udevice *dev)
|
||||
{
|
||||
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <memalign.h>
|
||||
#include <video_fb.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fb.h>
|
||||
|
@ -924,7 +924,7 @@ void *video_hw_init(void)
|
|||
da8xx_lcd_cfg->bpp);
|
||||
|
||||
size = sizeof(struct fb_info) + sizeof(struct da8xx_fb_par);
|
||||
da8xx_fb_info = malloc(size);
|
||||
da8xx_fb_info = malloc_cache_aligned(size);
|
||||
debug("da8xx_fb_info at %x\n", (unsigned int)da8xx_fb_info);
|
||||
|
||||
if (!da8xx_fb_info) {
|
||||
|
@ -949,7 +949,7 @@ void *video_hw_init(void)
|
|||
da8xx_lcd_cfg->bpp;
|
||||
par->vram_size = par->vram_size * LCD_NUM_BUFFERS / 8;
|
||||
|
||||
par->vram_virt = malloc(par->vram_size);
|
||||
par->vram_virt = malloc_cache_aligned(par->vram_size);
|
||||
|
||||
par->vram_phys = (dma_addr_t) par->vram_virt;
|
||||
debug("Requesting 0x%x bytes for framebuffer at 0x%x\n",
|
||||
|
@ -972,7 +972,7 @@ void *video_hw_init(void)
|
|||
da8xx_fb_fix.line_length - 1;
|
||||
|
||||
/* allocate palette buffer */
|
||||
par->v_palette_base = malloc(PALETTE_SIZE);
|
||||
par->v_palette_base = malloc_cache_aligned(PALETTE_SIZE);
|
||||
if (!par->v_palette_base) {
|
||||
printf("GLCD: malloc for palette buffer failed\n");
|
||||
goto err_release_fb_mem;
|
||||
|
|
|
@ -1075,7 +1075,7 @@ static const struct udevice_id exynos_dp_ids[] = {
|
|||
};
|
||||
|
||||
U_BOOT_DRIVER(exynos_dp) = {
|
||||
.name = "eexynos_dp",
|
||||
.name = "exynos_dp",
|
||||
.id = UCLASS_DISPLAY,
|
||||
.of_match = exynos_dp_ids,
|
||||
.ops = &exynos_dp_ops,
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o tve_common.o ../videomodes.o
|
||||
obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o lcdc.o ../dw_hdmi.o
|
||||
obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o
|
||||
obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o ../dw_hdmi.o sunxi_lcd.o
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <common.h>
|
||||
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/lcdc.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
@ -100,7 +101,7 @@ void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc,
|
|||
writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
|
||||
SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
|
||||
|
||||
#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
|
||||
#if defined(CONFIG_VIDEO_LCD_IF_PARALLEL) || defined(CONFIG_VIDEO_DE2)
|
||||
writel(SUNXI_LCDC_X(mode->hsync_len.typ) |
|
||||
SUNXI_LCDC_Y(mode->vsync_len.typ), &lcdc->tcon0_timing_sync);
|
||||
|
||||
|
@ -207,3 +208,122 @@ void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc,
|
|||
SUNXI_LCDC_MUX_CTRL_SRC0(1));
|
||||
#endif
|
||||
}
|
||||
|
||||
void lcdc_pll_set(struct sunxi_ccm_reg *ccm, int tcon, int dotclock,
|
||||
int *clk_div, int *clk_double, bool is_composite)
|
||||
{
|
||||
int value, n, m, min_m, max_m, diff;
|
||||
int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
|
||||
int best_double = 0;
|
||||
bool use_mipi_pll = false;
|
||||
|
||||
if (tcon == 0) {
|
||||
#if defined(CONFIG_VIDEO_LCD_IF_PARALLEL) || defined(CONFIG_SUNXI_DE2)
|
||||
min_m = 6;
|
||||
max_m = 127;
|
||||
#endif
|
||||
#ifdef CONFIG_VIDEO_LCD_IF_LVDS
|
||||
min_m = 7;
|
||||
max_m = 7;
|
||||
#endif
|
||||
} else {
|
||||
min_m = 1;
|
||||
max_m = 15;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the lowest divider resulting in a matching clock, if there
|
||||
* is no match, pick the closest lower clock, as monitors tend to
|
||||
* not sync to higher frequencies.
|
||||
*/
|
||||
for (m = min_m; m <= max_m; m++) {
|
||||
#ifndef CONFIG_SUNXI_DE2
|
||||
n = (m * dotclock) / 3000;
|
||||
|
||||
if ((n >= 9) && (n <= 127)) {
|
||||
value = (3000 * n) / m;
|
||||
diff = dotclock - value;
|
||||
if (diff < best_diff) {
|
||||
best_diff = diff;
|
||||
best_m = m;
|
||||
best_n = n;
|
||||
best_double = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* These are just duplicates */
|
||||
if (!(m & 1))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* No double clock on DE2 */
|
||||
n = (m * dotclock) / 6000;
|
||||
if ((n >= 9) && (n <= 127)) {
|
||||
value = (6000 * n) / m;
|
||||
diff = dotclock - value;
|
||||
if (diff < best_diff) {
|
||||
best_diff = diff;
|
||||
best_m = m;
|
||||
best_n = n;
|
||||
best_double = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MACH_SUN6I
|
||||
/*
|
||||
* Use the MIPI pll if we've been unable to find any matching setting
|
||||
* for PLL3, this happens with high dotclocks because of min_m = 6.
|
||||
*/
|
||||
if (tcon == 0 && best_n == 0) {
|
||||
use_mipi_pll = true;
|
||||
best_m = 6; /* Minimum m for tcon0 */
|
||||
}
|
||||
|
||||
if (use_mipi_pll) {
|
||||
clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
|
||||
clock_set_mipi_pll(best_m * dotclock * 1000);
|
||||
debug("dotclock: %dkHz = %dkHz via mipi pll\n",
|
||||
dotclock, clock_get_mipi_pll() / best_m / 1000);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
clock_set_pll3(best_n * 3000000);
|
||||
debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
|
||||
dotclock,
|
||||
(best_double + 1) * clock_get_pll3() / best_m / 1000,
|
||||
best_double + 1, best_n, best_m);
|
||||
}
|
||||
|
||||
if (tcon == 0) {
|
||||
u32 pll;
|
||||
|
||||
if (use_mipi_pll)
|
||||
pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
|
||||
else if (best_double)
|
||||
pll = CCM_LCD_CH0_CTRL_PLL3_2X;
|
||||
else
|
||||
pll = CCM_LCD_CH0_CTRL_PLL3;
|
||||
#ifndef CONFIG_SUNXI_DE2
|
||||
writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
|
||||
&ccm->lcd0_ch0_clk_cfg);
|
||||
#else
|
||||
writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
|
||||
&ccm->lcd0_clk_cfg);
|
||||
#endif
|
||||
}
|
||||
#ifndef CONFIG_SUNXI_DE2
|
||||
else {
|
||||
writel(CCM_LCD_CH1_CTRL_GATE |
|
||||
(best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
|
||||
CCM_LCD_CH1_CTRL_PLL3) |
|
||||
CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
|
||||
if (is_composite)
|
||||
setbits_le32(&ccm->lcd0_ch1_clk_cfg,
|
||||
CCM_LCD_CH1_CTRL_HALF_SCLK1);
|
||||
}
|
||||
#endif
|
||||
|
||||
*clk_div = best_m;
|
||||
*clk_double = best_double;
|
||||
}
|
||||
|
|
30
drivers/video/sunxi/simplefb_common.c
Normal file
30
drivers/video/sunxi/simplefb_common.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Common code for Allwinner SimpleFB with pipeline.
|
||||
*
|
||||
* (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
|
||||
* (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
|
||||
* (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <fdtdec.h>
|
||||
|
||||
int sunxi_simplefb_fdt_match(void *blob, const char *pipeline)
|
||||
{
|
||||
int offset, ret;
|
||||
|
||||
/* Find a prefilled simpefb node, matching out pipeline config */
|
||||
offset = fdt_node_offset_by_compatible(blob, -1,
|
||||
"allwinner,simple-framebuffer");
|
||||
while (offset >= 0) {
|
||||
ret = fdt_stringlist_search(blob, offset, "allwinner,pipeline",
|
||||
pipeline);
|
||||
if (ret == 0)
|
||||
break;
|
||||
offset = fdt_node_offset_by_compatible(blob, offset,
|
||||
"allwinner,simple-framebuffer");
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
22
drivers/video/sunxi/simplefb_common.h
Normal file
22
drivers/video/sunxi/simplefb_common.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __SIMPLEFB_COMMON_H
|
||||
#define __SIMPLEFB_COMMON_H
|
||||
|
||||
/**
|
||||
* sunxi_simplefb_fdt_match() - match a sunxi simplefb node
|
||||
*
|
||||
* Match a sunxi simplefb device node with a specified pipeline, and
|
||||
* return its offset.
|
||||
*
|
||||
* @blob: device tree blob
|
||||
* @pipeline: display pipeline
|
||||
* @return device node offset in blob, or negative values if failed
|
||||
*/
|
||||
int sunxi_simplefb_fdt_match(void *blob, const char *pipeline);
|
||||
|
||||
#endif
|
|
@ -10,6 +10,8 @@
|
|||
#include <display.h>
|
||||
#include <dm.h>
|
||||
#include <edid.h>
|
||||
#include <fdtdec.h>
|
||||
#include <fdt_support.h>
|
||||
#include <video.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/io.h>
|
||||
|
@ -17,6 +19,7 @@
|
|||
#include <asm/arch/display2.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
#include "simplefb_common.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
|
@ -232,6 +235,23 @@ static int sunxi_de2_probe(struct udevice *dev)
|
|||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return 0;
|
||||
|
||||
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
|
||||
"sunxi_lcd", &disp);
|
||||
if (!ret) {
|
||||
int mux;
|
||||
|
||||
mux = 0;
|
||||
|
||||
ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
|
||||
false);
|
||||
if (!ret) {
|
||||
video_set_flush_dcache(dev, 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
|
||||
|
||||
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
|
||||
"sunxi_dw_hdmi", &disp);
|
||||
if (!ret) {
|
||||
|
@ -292,3 +312,72 @@ U_BOOT_DRIVER(sunxi_de2) = {
|
|||
U_BOOT_DEVICE(sunxi_de2) = {
|
||||
.name = "sunxi_de2"
|
||||
};
|
||||
|
||||
/*
|
||||
* Simplefb support.
|
||||
*/
|
||||
#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
|
||||
int sunxi_simplefb_setup(void *blob)
|
||||
{
|
||||
struct udevice *de2, *hdmi;
|
||||
struct video_priv *de2_priv;
|
||||
struct video_uc_platdata *de2_plat;
|
||||
int mux;
|
||||
int offset, ret;
|
||||
u64 start, size;
|
||||
const char *pipeline = NULL;
|
||||
|
||||
debug("Setting up simplefb\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
|
||||
mux = 0;
|
||||
else
|
||||
mux = 1;
|
||||
|
||||
/* Skip simplefb setting if DE2 / HDMI is not present */
|
||||
ret = uclass_find_device_by_name(UCLASS_VIDEO,
|
||||
"sunxi_de2", &de2);
|
||||
if (ret) {
|
||||
debug("DE2 not present\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
|
||||
"sunxi_dw_hdmi", &hdmi);
|
||||
if (ret) {
|
||||
debug("HDMI not present\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mux == 0)
|
||||
pipeline = "mixer0-lcd0-hdmi";
|
||||
else
|
||||
pipeline = "mixer1-lcd1-hdmi";
|
||||
|
||||
de2_priv = dev_get_uclass_priv(de2);
|
||||
de2_plat = dev_get_uclass_platdata(de2);
|
||||
|
||||
offset = sunxi_simplefb_fdt_match(blob, pipeline);
|
||||
if (offset < 0) {
|
||||
eprintf("Cannot setup simplefb: node not found\n");
|
||||
return 0; /* Keep older kernels working */
|
||||
}
|
||||
|
||||
start = gd->bd->bi_dram[0].start;
|
||||
size = de2_plat->base - start;
|
||||
ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
|
||||
if (ret) {
|
||||
eprintf("Cannot setup simplefb: Error reserving memory\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fdt_setup_simplefb_node(blob, offset, de2_plat->base,
|
||||
de2_priv->xsize, de2_priv->ysize,
|
||||
VNBYTES(de2_priv->bpix) * de2_priv->xsize,
|
||||
"x8r8g8b8");
|
||||
if (ret)
|
||||
eprintf("Cannot setup simplefb: Error setting properties\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../anx9804.h"
|
||||
#include "../hitachi_tx18d42vm_lcd.h"
|
||||
#include "../ssd2828.h"
|
||||
#include "simplefb_common.h"
|
||||
|
||||
#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
|
||||
#define PWM_ON 0
|
||||
|
@ -515,119 +516,6 @@ static void sunxi_composer_enable(void)
|
|||
setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
|
||||
}
|
||||
|
||||
/*
|
||||
* LCDC, what allwinner calls a CRTC, so timing controller and serializer.
|
||||
*/
|
||||
static void sunxi_lcdc_pll_set(int tcon, int dotclock,
|
||||
int *clk_div, int *clk_double)
|
||||
{
|
||||
struct sunxi_ccm_reg * const ccm =
|
||||
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
int value, n, m, min_m, max_m, diff;
|
||||
int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
|
||||
int best_double = 0;
|
||||
bool use_mipi_pll = false;
|
||||
|
||||
if (tcon == 0) {
|
||||
#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
|
||||
min_m = 6;
|
||||
max_m = 127;
|
||||
#endif
|
||||
#ifdef CONFIG_VIDEO_LCD_IF_LVDS
|
||||
min_m = max_m = 7;
|
||||
#endif
|
||||
} else {
|
||||
min_m = 1;
|
||||
max_m = 15;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the lowest divider resulting in a matching clock, if there
|
||||
* is no match, pick the closest lower clock, as monitors tend to
|
||||
* not sync to higher frequencies.
|
||||
*/
|
||||
for (m = min_m; m <= max_m; m++) {
|
||||
n = (m * dotclock) / 3000;
|
||||
|
||||
if ((n >= 9) && (n <= 127)) {
|
||||
value = (3000 * n) / m;
|
||||
diff = dotclock - value;
|
||||
if (diff < best_diff) {
|
||||
best_diff = diff;
|
||||
best_m = m;
|
||||
best_n = n;
|
||||
best_double = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* These are just duplicates */
|
||||
if (!(m & 1))
|
||||
continue;
|
||||
|
||||
n = (m * dotclock) / 6000;
|
||||
if ((n >= 9) && (n <= 127)) {
|
||||
value = (6000 * n) / m;
|
||||
diff = dotclock - value;
|
||||
if (diff < best_diff) {
|
||||
best_diff = diff;
|
||||
best_m = m;
|
||||
best_n = n;
|
||||
best_double = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MACH_SUN6I
|
||||
/*
|
||||
* Use the MIPI pll if we've been unable to find any matching setting
|
||||
* for PLL3, this happens with high dotclocks because of min_m = 6.
|
||||
*/
|
||||
if (tcon == 0 && best_n == 0) {
|
||||
use_mipi_pll = true;
|
||||
best_m = 6; /* Minimum m for tcon0 */
|
||||
}
|
||||
|
||||
if (use_mipi_pll) {
|
||||
clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
|
||||
clock_set_mipi_pll(best_m * dotclock * 1000);
|
||||
debug("dotclock: %dkHz = %dkHz via mipi pll\n",
|
||||
dotclock, clock_get_mipi_pll() / best_m / 1000);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
clock_set_pll3(best_n * 3000000);
|
||||
debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
|
||||
dotclock,
|
||||
(best_double + 1) * clock_get_pll3() / best_m / 1000,
|
||||
best_double + 1, best_n, best_m);
|
||||
}
|
||||
|
||||
if (tcon == 0) {
|
||||
u32 pll;
|
||||
|
||||
if (use_mipi_pll)
|
||||
pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
|
||||
else if (best_double)
|
||||
pll = CCM_LCD_CH0_CTRL_PLL3_2X;
|
||||
else
|
||||
pll = CCM_LCD_CH0_CTRL_PLL3;
|
||||
|
||||
writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
|
||||
&ccm->lcd0_ch0_clk_cfg);
|
||||
} else {
|
||||
writel(CCM_LCD_CH1_CTRL_GATE |
|
||||
(best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
|
||||
CCM_LCD_CH1_CTRL_PLL3) |
|
||||
CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
|
||||
if (sunxi_is_composite())
|
||||
setbits_le32(&ccm->lcd0_ch1_clk_cfg,
|
||||
CCM_LCD_CH1_CTRL_HALF_SCLK1);
|
||||
}
|
||||
|
||||
*clk_div = best_m;
|
||||
*clk_double = best_double;
|
||||
}
|
||||
|
||||
static void sunxi_lcdc_init(void)
|
||||
{
|
||||
struct sunxi_ccm_reg * const ccm =
|
||||
|
@ -754,6 +642,8 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
|
|||
{
|
||||
struct sunxi_lcdc_reg * const lcdc =
|
||||
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
|
||||
struct sunxi_ccm_reg * const ccm =
|
||||
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
int clk_div, clk_double, pin;
|
||||
struct display_timing timing;
|
||||
|
||||
|
@ -773,7 +663,8 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
|
|||
#endif
|
||||
}
|
||||
|
||||
sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
|
||||
lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
|
||||
sunxi_is_composite());
|
||||
|
||||
sunxi_ctfb_mode_to_display_timing(mode, &timing);
|
||||
lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
|
||||
|
@ -787,6 +678,8 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
|
|||
{
|
||||
struct sunxi_lcdc_reg * const lcdc =
|
||||
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
|
||||
struct sunxi_ccm_reg * const ccm =
|
||||
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
struct display_timing timing;
|
||||
|
||||
sunxi_ctfb_mode_to_display_timing(mode, &timing);
|
||||
|
@ -798,7 +691,8 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
|
|||
sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
|
||||
}
|
||||
|
||||
sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
|
||||
lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
|
||||
sunxi_is_composite());
|
||||
}
|
||||
#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
|
||||
|
||||
|
@ -1377,17 +1271,7 @@ int sunxi_simplefb_setup(void *blob)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Find a prefilled simpefb node, matching out pipeline config */
|
||||
offset = fdt_node_offset_by_compatible(blob, -1,
|
||||
"allwinner,simple-framebuffer");
|
||||
while (offset >= 0) {
|
||||
ret = fdt_stringlist_search(blob, offset, "allwinner,pipeline",
|
||||
pipeline);
|
||||
if (ret == 0)
|
||||
break;
|
||||
offset = fdt_node_offset_by_compatible(blob, offset,
|
||||
"allwinner,simple-framebuffer");
|
||||
}
|
||||
offset = sunxi_simplefb_fdt_match(blob, pipeline);
|
||||
if (offset < 0) {
|
||||
eprintf("Cannot setup simplefb: node not found\n");
|
||||
return 0; /* Keep older kernels working */
|
||||
|
|
152
drivers/video/sunxi/sunxi_lcd.c
Normal file
152
drivers/video/sunxi/sunxi_lcd.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Allwinner LCD driver
|
||||
*
|
||||
* (C) Copyright 2017 Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <display.h>
|
||||
#include <video_bridge.h>
|
||||
#include <backlight.h>
|
||||
#include <dm.h>
|
||||
#include <edid.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/lcdc.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
struct sunxi_lcd_priv {
|
||||
struct display_timing timing;
|
||||
int panel_bpp;
|
||||
};
|
||||
|
||||
static void sunxi_lcdc_config_pinmux(void)
|
||||
{
|
||||
#ifdef CONFIG_MACH_SUN50I
|
||||
int pin;
|
||||
|
||||
for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(21); pin++) {
|
||||
sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
|
||||
sunxi_gpio_set_drv(pin, 3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int sunxi_lcd_enable(struct udevice *dev, int bpp,
|
||||
const struct display_timing *edid)
|
||||
{
|
||||
struct sunxi_ccm_reg * const ccm =
|
||||
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
struct sunxi_lcdc_reg * const lcdc =
|
||||
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
|
||||
struct sunxi_lcd_priv *priv = dev_get_priv(dev);
|
||||
struct udevice *backlight;
|
||||
int clk_div, clk_double, ret;
|
||||
|
||||
/* Reset off */
|
||||
setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
|
||||
/* Clock on */
|
||||
setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
|
||||
|
||||
lcdc_init(lcdc);
|
||||
sunxi_lcdc_config_pinmux();
|
||||
lcdc_pll_set(ccm, 0, edid->pixelclock.typ / 1000,
|
||||
&clk_div, &clk_double, false);
|
||||
lcdc_tcon0_mode_set(lcdc, edid, clk_div, false,
|
||||
priv->panel_bpp, CONFIG_VIDEO_LCD_DCLK_PHASE);
|
||||
lcdc_enable(lcdc, priv->panel_bpp);
|
||||
|
||||
ret = uclass_get_device(UCLASS_PANEL_BACKLIGHT, 0, &backlight);
|
||||
if (!ret)
|
||||
backlight_enable(backlight);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_lcd_read_timing(struct udevice *dev,
|
||||
struct display_timing *timing)
|
||||
{
|
||||
struct sunxi_lcd_priv *priv = dev_get_priv(dev);
|
||||
|
||||
memcpy(timing, &priv->timing, sizeof(struct display_timing));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_lcd_probe(struct udevice *dev)
|
||||
{
|
||||
struct udevice *cdev;
|
||||
struct sunxi_lcd_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
int node, timing_node, val;
|
||||
|
||||
#ifdef CONFIG_VIDEO_BRIDGE
|
||||
/* Try to get timings from bridge first */
|
||||
ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &cdev);
|
||||
if (!ret) {
|
||||
u8 edid[EDID_SIZE];
|
||||
int channel_bpp;
|
||||
|
||||
ret = video_bridge_attach(cdev);
|
||||
if (ret) {
|
||||
debug("video bridge attach failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = video_bridge_read_edid(cdev, edid, EDID_SIZE);
|
||||
if (ret > 0) {
|
||||
ret = edid_get_timing(edid, ret,
|
||||
&priv->timing, &channel_bpp);
|
||||
priv->panel_bpp = channel_bpp * 3;
|
||||
if (!ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fallback to timings from DT if there's no bridge or
|
||||
* if reading EDID failed
|
||||
*/
|
||||
ret = uclass_get_device(UCLASS_PANEL, 0, &cdev);
|
||||
if (ret) {
|
||||
debug("video panel not found: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fdtdec_decode_display_timing(gd->fdt_blob, dev_of_offset(cdev),
|
||||
0, &priv->timing)) {
|
||||
debug("%s: Failed to decode display timing\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
timing_node = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(cdev),
|
||||
"display-timings");
|
||||
node = fdt_first_subnode(gd->fdt_blob, timing_node);
|
||||
val = fdtdec_get_int(gd->fdt_blob, node, "bits-per-pixel", -1);
|
||||
if (val != -1)
|
||||
priv->panel_bpp = val;
|
||||
else
|
||||
priv->panel_bpp = 18;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_display_ops sunxi_lcd_ops = {
|
||||
.read_timing = sunxi_lcd_read_timing,
|
||||
.enable = sunxi_lcd_enable,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sunxi_lcd) = {
|
||||
.name = "sunxi_lcd",
|
||||
.id = UCLASS_DISPLAY,
|
||||
.ops = &sunxi_lcd_ops,
|
||||
.probe = sunxi_lcd_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct sunxi_lcd_priv),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MACH_SUN50I
|
||||
U_BOOT_DEVICE(sunxi_lcd) = {
|
||||
.name = "sunxi_lcd"
|
||||
};
|
||||
#endif
|
|
@ -268,18 +268,13 @@ extern int soft_i2c_gpio_scl;
|
|||
/* GPIO */
|
||||
#define CONFIG_SUNXI_GPIO
|
||||
|
||||
#ifdef CONFIG_VIDEO
|
||||
#ifdef CONFIG_VIDEO_SUNXI
|
||||
/*
|
||||
* The amount of RAM to keep free at the top of RAM when relocating u-boot,
|
||||
* to use as framebuffer. This must be a multiple of 4096.
|
||||
*/
|
||||
#define CONFIG_SUNXI_MAX_FB_SIZE (16 << 20)
|
||||
|
||||
/* Do we want to initialize a simple FB? */
|
||||
#define CONFIG_VIDEO_DT_SIMPLEFB
|
||||
|
||||
#define CONFIG_VIDEO_SUNXI
|
||||
|
||||
#define CONFIG_VIDEO_LOGO
|
||||
#define CONFIG_VIDEO_STD_TIMINGS
|
||||
#define CONFIG_I2C_EDID
|
||||
|
@ -288,7 +283,7 @@ extern int soft_i2c_gpio_scl;
|
|||
/* allow both serial and cfb console. */
|
||||
/* stop x86 thinking in cfbconsole from trying to init a pc keyboard */
|
||||
|
||||
#endif /* CONFIG_VIDEO */
|
||||
#endif /* CONFIG_VIDEO_SUNXI */
|
||||
|
||||
/* Ethernet support */
|
||||
#ifdef CONFIG_SUNXI_EMAC
|
||||
|
|
|
@ -53,6 +53,16 @@ struct video_bridge_ops {
|
|||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*set_backlight)(struct udevice *dev, int percent);
|
||||
|
||||
/**
|
||||
* read_edid() - Read information from EDID
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @buf: Buffer to read into
|
||||
* @buf_size: Buffer size
|
||||
* @return number of bytes read, <=0 for error
|
||||
*/
|
||||
int (*read_edid)(struct udevice *dev, u8 *buf, int buf_size);
|
||||
};
|
||||
|
||||
#define video_bridge_get_ops(dev) \
|
||||
|
@ -89,4 +99,14 @@ int video_bridge_set_active(struct udevice *dev, bool active);
|
|||
*/
|
||||
int video_bridge_check_attached(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* video_bridge_read_edid() - Read information from EDID
|
||||
*
|
||||
* @dev: Device to read from
|
||||
* @buf: Buffer to read into
|
||||
* @buf_size: Buffer size
|
||||
* @return number of bytes read, <=0 for error
|
||||
*/
|
||||
int video_bridge_read_edid(struct udevice *dev, u8 *buf, int buf_size);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5065,7 +5065,6 @@ CONFIG_VIDEO_MXS
|
|||
CONFIG_VIDEO_MXS_MODE_SYSTEM
|
||||
CONFIG_VIDEO_OMAP3
|
||||
CONFIG_VIDEO_STD_TIMINGS
|
||||
CONFIG_VIDEO_SUNXI
|
||||
CONFIG_VIDEO_VCXK
|
||||
CONFIG_VID_FLS_ENV
|
||||
CONFIG_VM86
|
||||
|
|
Loading…
Reference in a new issue