Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OS
U-Boot.Mirror
提交
2d5e6b4a
U
U-Boot.Mirror
项目概览
OS
/
U-Boot.Mirror
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
U-Boot.Mirror
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2d5e6b4a
编写于
10月 29, 2017
作者:
T
Tom Rini
浏览文件
操作
浏览文件
下载
差异文件
Merge
git://git.denx.de/u-boot-video
上级
40583564
9b73bcc6
变更
21
隐藏空白更改
内联
并排
Showing
21 changed file
with
1025 addition
and
209 deletion
+1025
-209
arch/arm/include/asm/arch-sunxi/lcdc.h
arch/arm/include/asm/arch-sunxi/lcdc.h
+3
-0
arch/arm/mach-sunxi/Kconfig
arch/arm/mach-sunxi/Kconfig
+17
-14
drivers/video/Kconfig
drivers/video/Kconfig
+8
-0
drivers/video/anx9804.c
drivers/video/anx9804.c
+1
-53
drivers/video/anx98xx-edp.h
drivers/video/anx98xx-edp.h
+98
-0
drivers/video/bridge/Kconfig
drivers/video/bridge/Kconfig
+8
-0
drivers/video/bridge/Makefile
drivers/video/bridge/Makefile
+1
-0
drivers/video/bridge/anx6345.c
drivers/video/bridge/anx6345.c
+426
-0
drivers/video/bridge/video-bridge-uclass.c
drivers/video/bridge/video-bridge-uclass.c
+10
-0
drivers/video/da8xx-fb.c
drivers/video/da8xx-fb.c
+4
-4
drivers/video/exynos/exynos_dp.c
drivers/video/exynos/exynos_dp.c
+1
-1
drivers/video/sunxi/Makefile
drivers/video/sunxi/Makefile
+2
-2
drivers/video/sunxi/lcdc.c
drivers/video/sunxi/lcdc.c
+121
-1
drivers/video/sunxi/simplefb_common.c
drivers/video/sunxi/simplefb_common.c
+30
-0
drivers/video/sunxi/simplefb_common.h
drivers/video/sunxi/simplefb_common.h
+22
-0
drivers/video/sunxi/sunxi_de2.c
drivers/video/sunxi/sunxi_de2.c
+89
-0
drivers/video/sunxi/sunxi_display.c
drivers/video/sunxi/sunxi_display.c
+10
-126
drivers/video/sunxi/sunxi_lcd.c
drivers/video/sunxi/sunxi_lcd.c
+152
-0
include/configs/sunxi-common.h
include/configs/sunxi-common.h
+2
-7
include/video_bridge.h
include/video_bridge.h
+20
-0
scripts/config_whitelist.txt
scripts/config_whitelist.txt
+0
-1
未找到文件。
arch/arm/include/asm/arch-sunxi/lcdc.h
浏览文件 @
2d5e6b4a
...
...
@@ -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 */
arch/arm/mach-sunxi/Kconfig
浏览文件 @
2d5e6b4a
...
...
@@ -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.
...
...
drivers/video/Kconfig
浏览文件 @
2d5e6b4a
...
...
@@ -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
drivers/video/anx9804.c
浏览文件 @
2d5e6b4a
...
...
@@ -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
*
...
...
drivers/video/anx98xx-edp.h
0 → 100644
浏览文件 @
2d5e6b4a
/*
* 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)
drivers/video/bridge/Kconfig
浏览文件 @
2d5e6b4a
...
...
@@ -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.
drivers/video/bridge/Makefile
浏览文件 @
2d5e6b4a
...
...
@@ -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
drivers/video/bridge/anx6345.c
0 → 100644
浏览文件 @
2d5e6b4a
/*
* 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
),
};
drivers/video/bridge/video-bridge-uclass.c
浏览文件 @
2d5e6b4a
...
...
@@ -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
);
...
...
drivers/video/da8xx-fb.c
浏览文件 @
2d5e6b4a
...
...
@@ -14,7 +14,7 @@
*/
#include <common.h>
#include <m
alloc
.h>
#include <m
emalign
.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
;
...
...
drivers/video/exynos/exynos_dp.c
浏览文件 @
2d5e6b4a
...
...
@@ -1075,7 +1075,7 @@ static const struct udevice_id exynos_dp_ids[] = {
};
U_BOOT_DRIVER
(
exynos_dp
)
=
{
.
name
=
"e
e
xynos_dp"
,
.
name
=
"exynos_dp"
,
.
id
=
UCLASS_DISPLAY
,
.
of_match
=
exynos_dp_ids
,
.
ops
=
&
exynos_dp_ops
,
...
...
drivers/video/sunxi/Makefile
浏览文件 @
2d5e6b4a
...
...
@@ -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
drivers/video/sunxi/lcdc.c
浏览文件 @
2d5e6b4a
...
...
@@ -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
);
#if
def 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
;
}
drivers/video/sunxi/simplefb_common.c
0 → 100644
浏览文件 @
2d5e6b4a
/*
* 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
;
}
drivers/video/sunxi/simplefb_common.h
0 → 100644
浏览文件 @
2d5e6b4a
/*
* (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
drivers/video/sunxi/sunxi_de2.c
浏览文件 @
2d5e6b4a
...
...
@@ -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 */
drivers/video/sunxi/sunxi_display.c
浏览文件 @
2d5e6b4a
...
...
@@ -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 */
...
...
drivers/video/sunxi/sunxi_lcd.c
0 → 100644
浏览文件 @
2d5e6b4a
/*
* 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
include/configs/sunxi-common.h
浏览文件 @
2d5e6b4a
...
...
@@ -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
...
...
include/video_bridge.h
浏览文件 @
2d5e6b4a
...
...
@@ -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
scripts/config_whitelist.txt
浏览文件 @
2d5e6b4a
...
...
@@ -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
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录