mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 05:50:17 +00:00 
			
		
		
		
	- Add features and fixups to support video on Amlogic GX SoCs
- Add video support for Amlogic GX SoC - Add DT fixups - Enable Video and USB Console for libretech-cc board -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJcUrPBAAoJEHfc29rIyEnRtJ8QAI2YFvozhCwdNhZg1Z1jRS2j 5gkEW4HjwD7p4BXWYNmymDybWUtax21vXy/Q7zJHnOYuYeVwH7Tw2H0kAwVnMjja RXewtvaeb4sd2OWm7v9PoiUrg2+xwC9YqNCPMkEAE7EMo95Lpx11NwuvHVJqbsTG Qo46P5KBwOsnzg3/WAGth8/IBrFvsdJAoa7WtRRgF/THYhu1PtkzX8Cu1DHgQQMt UiDaoTaarCMiVP0g6dVnPJB/IrW9D9lEU9sx2C0J/yU2ikLdbX5TPPjMlqVznn8D hO+kqfkiGAlXiPwDEc4UskqRHTvivaL8wLGdtYyXkp0eRgxipAyDdO9oGUjkN8+e f1B/hQMipMnSpehYqB13XJYtjGqR8JdKNaN/BptH26YYS44iuHiTJs9XsXqyKTRU X9rnDSrWiaREL6ChrP0KMXzbP47KUBHA5OPsTv0YHLkcuoRMovqu2OgiK13GNQqf Q2RaQqBiz+sfNIsx7OKaFIr2TMpSUbe+WxEne0s+C1XrD0/V86iN32jnmioxLdEo qFMkKZWXHv7pfwVaMK91wAZFasnWjg5VqkEXFS4ti+SIxfkpgsg+nLHMQpw48M4e KfmBW5tsIiN3gfXI+ZfCEWdU2dkd9u5B+QKzLC8dimxEziZYkGk0CXN0N4lBp4on AItt+R8BbrBsvcp3r1WY =MWXC -----END PGP SIGNATURE----- Merge tag 'u-boot-amlogic-20190131' of git://git.denx.de/u-boot-amlogic - Add features and fixups to support video on Amlogic GX SoCs - Add video support for Amlogic GX SoC - Add DT fixups - Enable Video and USB Console for libretech-cc board
This commit is contained in:
		
						commit
						ab0ec15f77
					
				
							
								
								
									
										21
									
								
								arch/arm/dts/meson-gx-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								arch/arm/dts/meson-gx-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 BayLibre, SAS.
 | 
			
		||||
 * Author: Maxime Jourdan <mjourdan@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/ {
 | 
			
		||||
	soc {
 | 
			
		||||
		u-boot,dm-pre-reloc;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
&vpu {
 | 
			
		||||
	u-boot,dm-pre-reloc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
&hdmi_tx {
 | 
			
		||||
	reg = <0x0 0xc883a000 0x0 0x1c>,
 | 
			
		||||
	      <0x0 0xc883c000 0x0 0x1000>;
 | 
			
		||||
	reg-names = "hdmitx", "hhi";
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										7
									
								
								arch/arm/dts/meson-gxbb-nanopi-k2-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								arch/arm/dts/meson-gxbb-nanopi-k2-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson-gx-u-boot.dtsi"
 | 
			
		||||
							
								
								
									
										7
									
								
								arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson-gx-u-boot.dtsi"
 | 
			
		||||
							
								
								
									
										7
									
								
								arch/arm/dts/meson-gxl-s905x-khadas-vim-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								arch/arm/dts/meson-gxl-s905x-khadas-vim-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson-gx-u-boot.dtsi"
 | 
			
		||||
@ -78,6 +78,7 @@
 | 
			
		||||
	status = "okay";
 | 
			
		||||
	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
 | 
			
		||||
	pinctrl-names = "default";
 | 
			
		||||
	hdmi-supply = <&hdmi_5v>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
&hdmi_tx_tmds_port {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								arch/arm/dts/meson-gxl-s905x-libretech-cc-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								arch/arm/dts/meson-gxl-s905x-libretech-cc-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson-gx-u-boot.dtsi"
 | 
			
		||||
@ -155,6 +155,7 @@
 | 
			
		||||
	status = "okay";
 | 
			
		||||
	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
 | 
			
		||||
	pinctrl-names = "default";
 | 
			
		||||
	hdmi-supply = <&hdmi_5v>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
&hdmi_tx_tmds_port {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								arch/arm/dts/meson-gxl-s905x-p212-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								arch/arm/dts/meson-gxl-s905x-p212-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson-gx-u-boot.dtsi"
 | 
			
		||||
@ -51,6 +51,7 @@
 | 
			
		||||
	status = "okay";
 | 
			
		||||
	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
 | 
			
		||||
	pinctrl-names = "default";
 | 
			
		||||
	hdmi-supply = <&hdmi_5v>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
&hdmi_tx_tmds_port {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								arch/arm/dts/meson-gxm-khadas-vim2-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								arch/arm/dts/meson-gxm-khadas-vim2-u-boot.dtsi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson-gx-u-boot.dtsi"
 | 
			
		||||
@ -271,6 +271,7 @@
 | 
			
		||||
	status = "okay";
 | 
			
		||||
	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
 | 
			
		||||
	pinctrl-names = "default";
 | 
			
		||||
	hdmi-supply = <&hdmi_5v>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
&hdmi_tx_tmds_port {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								arch/arm/include/asm/arch-meson/meson-vpu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								arch/arm/include/asm/arch-meson/meson-vpu.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0+ */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 BayLibre, SAS
 | 
			
		||||
 * Author: Maxime Jourdan <mjourdan@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MESON_VPU_H__
 | 
			
		||||
#define __MESON_VPU_H__
 | 
			
		||||
 | 
			
		||||
/* Allow reserving the framebuffer memory region */
 | 
			
		||||
void meson_vpu_rsv_fb(void *fdt);
 | 
			
		||||
 | 
			
		||||
#endif /* __MESON_VPU_H__ */
 | 
			
		||||
@ -9,6 +9,7 @@
 | 
			
		||||
#include <asm/arch/eth.h>
 | 
			
		||||
#include <asm/arch/gx.h>
 | 
			
		||||
#include <asm/arch/mem.h>
 | 
			
		||||
#include <asm/arch/meson-vpu.h>
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
#include <asm/armv8/mmu.h>
 | 
			
		||||
#include <linux/sizes.h>
 | 
			
		||||
@ -65,6 +66,10 @@ void meson_init_reserved_memory(void *fdt)
 | 
			
		||||
	/* Add BL32 reserved zone */
 | 
			
		||||
	if (bl32_start && bl32_size)
 | 
			
		||||
		meson_board_add_reserved_memory(fdt, bl32_start, bl32_size);
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_VIDEO_MESON)
 | 
			
		||||
	meson_vpu_rsv_fb(fdt);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
phys_size_t get_effective_memsize(void)
 | 
			
		||||
 | 
			
		||||
@ -44,3 +44,5 @@ CONFIG_USB_XHCI_DWC3=y
 | 
			
		||||
CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
 | 
			
		||||
CONFIG_USB_DWC3=y
 | 
			
		||||
CONFIG_OF_LIBFDT_OVERLAY=y
 | 
			
		||||
CONFIG_CONSOLE_MUX=y
 | 
			
		||||
CONFIG_SYS_CONSOLE_IS_IN_ENV=y
 | 
			
		||||
 | 
			
		||||
@ -49,3 +49,5 @@ CONFIG_USB_XHCI_DWC3=y
 | 
			
		||||
CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
 | 
			
		||||
CONFIG_USB_DWC3=y
 | 
			
		||||
CONFIG_OF_LIBFDT_OVERLAY=y
 | 
			
		||||
CONFIG_CONSOLE_MUX=y
 | 
			
		||||
CONFIG_SYS_CONSOLE_IS_IN_ENV=y
 | 
			
		||||
 | 
			
		||||
@ -49,3 +49,11 @@ CONFIG_USB_XHCI_DWC3=y
 | 
			
		||||
CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
 | 
			
		||||
CONFIG_USB_DWC3=y
 | 
			
		||||
CONFIG_OF_LIBFDT_OVERLAY=y
 | 
			
		||||
CONFIG_CONSOLE_MUX=y
 | 
			
		||||
CONFIG_SYS_CONSOLE_IS_IN_ENV=y
 | 
			
		||||
CONFIG_POWER_DOMAIN=y
 | 
			
		||||
CONFIG_MESON_GX_VPU_POWER_DOMAIN=y
 | 
			
		||||
CONFIG_DM_VIDEO=y
 | 
			
		||||
CONFIG_VIDEO_MESON=y
 | 
			
		||||
CONFIG_SYS_WHITE_ON_BLACK=y
 | 
			
		||||
CONFIG_VIDEO_DT_SIMPLEFB=y
 | 
			
		||||
 | 
			
		||||
@ -38,3 +38,5 @@ CONFIG_DEBUG_UART_ANNOUNCE=y
 | 
			
		||||
CONFIG_DEBUG_UART_SKIP_INIT=y
 | 
			
		||||
CONFIG_MESON_SERIAL=y
 | 
			
		||||
CONFIG_OF_LIBFDT_OVERLAY=y
 | 
			
		||||
CONFIG_CONSOLE_MUX=y
 | 
			
		||||
CONFIG_SYS_CONSOLE_IS_IN_ENV=y
 | 
			
		||||
 | 
			
		||||
@ -48,3 +48,5 @@ CONFIG_USB_XHCI_DWC3=y
 | 
			
		||||
CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
 | 
			
		||||
CONFIG_USB_DWC3=y
 | 
			
		||||
CONFIG_OF_LIBFDT_OVERLAY=y
 | 
			
		||||
CONFIG_CONSOLE_MUX=y
 | 
			
		||||
CONFIG_SYS_CONSOLE_IS_IN_ENV=y
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ config MTK_POWER_DOMAIN
 | 
			
		||||
 | 
			
		||||
config MESON_GX_VPU_POWER_DOMAIN
 | 
			
		||||
	bool "Enable Amlogic Meson GX VPU power domain driver"
 | 
			
		||||
	depends on ARCH_MESON
 | 
			
		||||
	depends on POWER_DOMAIN && ARCH_MESON
 | 
			
		||||
	help
 | 
			
		||||
	  Enable support for manipulating Amlogic Meson GX Video Processing
 | 
			
		||||
	  Unit power domain.
 | 
			
		||||
 | 
			
		||||
@ -401,6 +401,8 @@ config VIDEO_LCD_SPI_MISO
 | 
			
		||||
	option takes a string in the format understood by 'name_to_gpio'
 | 
			
		||||
	function, e.g. PH1 for pin 1 of port H.
 | 
			
		||||
 | 
			
		||||
source "drivers/video/meson/Kconfig"
 | 
			
		||||
 | 
			
		||||
config VIDEO_MVEBU
 | 
			
		||||
	bool "Armada XP LCD controller"
 | 
			
		||||
	default n
 | 
			
		||||
 | 
			
		||||
@ -52,6 +52,7 @@ obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o
 | 
			
		||||
obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
 | 
			
		||||
obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
 | 
			
		||||
obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o
 | 
			
		||||
obj-${CONFIG_VIDEO_MESON} += meson/
 | 
			
		||||
obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o
 | 
			
		||||
obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o
 | 
			
		||||
obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@
 | 
			
		||||
#include <common.h>
 | 
			
		||||
#include <fdtdec.h>
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
#include <media_bus_format.h>
 | 
			
		||||
#include "dw_hdmi.h"
 | 
			
		||||
 | 
			
		||||
struct tmds_n_cts {
 | 
			
		||||
@ -52,7 +53,25 @@ static const struct tmds_n_cts n_cts_table[] = {
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void hdmi_write(struct dw_hdmi *hdmi, u8 val, int offset)
 | 
			
		||||
static const u16 csc_coeff_default[3][4] = {
 | 
			
		||||
	{ 0x2000, 0x0000, 0x0000, 0x0000 },
 | 
			
		||||
	{ 0x0000, 0x2000, 0x0000, 0x0000 },
 | 
			
		||||
	{ 0x0000, 0x0000, 0x2000, 0x0000 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
 | 
			
		||||
	{ 0x2591, 0x1322, 0x074b, 0x0000 },
 | 
			
		||||
	{ 0x6535, 0x2000, 0x7acc, 0x0200 },
 | 
			
		||||
	{ 0x6acd, 0x7534, 0x2000, 0x0200 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
 | 
			
		||||
	{ 0x2000, 0x6926, 0x74fd, 0x010e },
 | 
			
		||||
	{ 0x2000, 0x2cdd, 0x0000, 0x7e9a },
 | 
			
		||||
	{ 0x2000, 0x0000, 0x38b4, 0x7e3b }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void dw_hdmi_write(struct dw_hdmi *hdmi, u8 val, int offset)
 | 
			
		||||
{
 | 
			
		||||
	switch (hdmi->reg_io_width) {
 | 
			
		||||
	case 1:
 | 
			
		||||
@ -67,7 +86,7 @@ static void hdmi_write(struct dw_hdmi *hdmi, u8 val, int offset)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u8 hdmi_read(struct dw_hdmi *hdmi, int offset)
 | 
			
		||||
static u8 dw_hdmi_read(struct dw_hdmi *hdmi, int offset)
 | 
			
		||||
{
 | 
			
		||||
	switch (hdmi->reg_io_width) {
 | 
			
		||||
	case 1:
 | 
			
		||||
@ -82,6 +101,10 @@ static u8 hdmi_read(struct dw_hdmi *hdmi, int offset)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u8 (*hdmi_read)(struct dw_hdmi *hdmi, int offset) = dw_hdmi_read;
 | 
			
		||||
static void (*hdmi_write)(struct dw_hdmi *hdmi, u8 val, int offset) =
 | 
			
		||||
								 dw_hdmi_write;
 | 
			
		||||
 | 
			
		||||
static void hdmi_mod(struct dw_hdmi *hdmi, unsigned reg, u8 mask, u8 data)
 | 
			
		||||
{
 | 
			
		||||
	u8 val = hdmi_read(hdmi, reg) & ~mask;
 | 
			
		||||
@ -158,9 +181,52 @@ static void hdmi_audio_set_samplerate(struct dw_hdmi *hdmi, u32 pixel_clk)
 | 
			
		||||
 */
 | 
			
		||||
static void hdmi_video_sample(struct dw_hdmi *hdmi)
 | 
			
		||||
{
 | 
			
		||||
	u32 color_format = 0x01;
 | 
			
		||||
	u32 color_format;
 | 
			
		||||
	uint val;
 | 
			
		||||
 | 
			
		||||
	switch (hdmi->hdmi_data.enc_in_bus_format) {
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB888_1X24:
 | 
			
		||||
		color_format = 0x01;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB101010_1X30:
 | 
			
		||||
		color_format = 0x03;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB121212_1X36:
 | 
			
		||||
		color_format = 0x05;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB161616_1X48:
 | 
			
		||||
		color_format = 0x07;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV8_1X24:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
 | 
			
		||||
		color_format = 0x09;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV10_1X30:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
 | 
			
		||||
		color_format = 0x0B;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV12_1X36:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
 | 
			
		||||
		color_format = 0x0D;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV16_1X48:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
 | 
			
		||||
		color_format = 0x0F;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY8_1X16:
 | 
			
		||||
		color_format = 0x16;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY10_1X20:
 | 
			
		||||
		color_format = 0x14;
 | 
			
		||||
		break;
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY12_1X24:
 | 
			
		||||
		color_format = 0x12;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		color_format = 0x01;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
 | 
			
		||||
	      ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
 | 
			
		||||
	      HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
 | 
			
		||||
@ -453,6 +519,180 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 | 
			
		||||
	hdmi_write(hdmi, edid->vsync_len.typ, HDMI_FC_VSYNCINWIDTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format)
 | 
			
		||||
{
 | 
			
		||||
	switch (bus_format) {
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB888_1X24:
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB101010_1X30:
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB121212_1X36:
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB161616_1X48:
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format)
 | 
			
		||||
{
 | 
			
		||||
	switch (bus_format) {
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV8_1X24:
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV10_1X30:
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV12_1X36:
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV16_1X48:
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
 | 
			
		||||
{
 | 
			
		||||
	switch (bus_format) {
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY8_1X16:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY10_1X20:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY12_1X24:
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int is_color_space_interpolation(struct dw_hdmi *hdmi)
 | 
			
		||||
{
 | 
			
		||||
	if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_in_bus_format))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
 | 
			
		||||
	    hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int is_color_space_decimation(struct dw_hdmi *hdmi)
 | 
			
		||||
{
 | 
			
		||||
	if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) ||
 | 
			
		||||
	    hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_in_bus_format))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
 | 
			
		||||
{
 | 
			
		||||
	switch (bus_format) {
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB888_1X24:
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV8_1X24:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY8_1X16:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
 | 
			
		||||
		return 8;
 | 
			
		||||
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB101010_1X30:
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV10_1X30:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY10_1X20:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
 | 
			
		||||
		return 10;
 | 
			
		||||
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB121212_1X36:
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV12_1X36:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYVY12_1X24:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
 | 
			
		||||
		return 12;
 | 
			
		||||
 | 
			
		||||
	case MEDIA_BUS_FMT_RGB161616_1X48:
 | 
			
		||||
	case MEDIA_BUS_FMT_YUV16_1X48:
 | 
			
		||||
	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
 | 
			
		||||
		return 16;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int is_color_space_conversion(struct dw_hdmi *hdmi)
 | 
			
		||||
{
 | 
			
		||||
	return hdmi->hdmi_data.enc_in_bus_format !=
 | 
			
		||||
	       hdmi->hdmi_data.enc_out_bus_format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
 | 
			
		||||
{
 | 
			
		||||
	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	u32 csc_scale = 1;
 | 
			
		||||
 | 
			
		||||
	if (is_color_space_conversion(hdmi)) {
 | 
			
		||||
		if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
 | 
			
		||||
			csc_coeff = &csc_coeff_rgb_out_eitu601;
 | 
			
		||||
		} else if (hdmi_bus_fmt_is_rgb(
 | 
			
		||||
					hdmi->hdmi_data.enc_in_bus_format)) {
 | 
			
		||||
			csc_coeff = &csc_coeff_rgb_in_eitu601;
 | 
			
		||||
			csc_scale = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* The CSC registers are sequential, alternating MSB then LSB */
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
 | 
			
		||||
		u16 coeff_a = (*csc_coeff)[0][i];
 | 
			
		||||
		u16 coeff_b = (*csc_coeff)[1][i];
 | 
			
		||||
		u16 coeff_c = (*csc_coeff)[2][i];
 | 
			
		||||
 | 
			
		||||
		hdmi_write(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
 | 
			
		||||
		hdmi_write(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
 | 
			
		||||
		hdmi_write(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
 | 
			
		||||
		hdmi_write(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
 | 
			
		||||
		hdmi_write(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
 | 
			
		||||
		hdmi_write(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hdmi_mod(hdmi, HDMI_CSC_SCALE, HDMI_CSC_SCALE_CSCSCALE_MASK, csc_scale);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void hdmi_video_csc(struct dw_hdmi *hdmi)
 | 
			
		||||
{
 | 
			
		||||
	int color_depth = 0;
 | 
			
		||||
	int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
 | 
			
		||||
	int decimation = 0;
 | 
			
		||||
 | 
			
		||||
	/* YCC422 interpolation to 444 mode */
 | 
			
		||||
	if (is_color_space_interpolation(hdmi))
 | 
			
		||||
		interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
 | 
			
		||||
	else if (is_color_space_decimation(hdmi))
 | 
			
		||||
		decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
 | 
			
		||||
 | 
			
		||||
	switch (hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format)) {
 | 
			
		||||
	case 8:
 | 
			
		||||
		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
 | 
			
		||||
		break;
 | 
			
		||||
	case 10:
 | 
			
		||||
		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
 | 
			
		||||
		break;
 | 
			
		||||
	case 12:
 | 
			
		||||
		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
 | 
			
		||||
		break;
 | 
			
		||||
	case 16:
 | 
			
		||||
		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Configure the CSC registers */
 | 
			
		||||
	hdmi_write(hdmi, interpolation | decimation, HDMI_CSC_CFG);
 | 
			
		||||
 | 
			
		||||
	hdmi_mod(hdmi, HDMI_CSC_SCALE, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
 | 
			
		||||
		 color_depth);
 | 
			
		||||
 | 
			
		||||
	dw_hdmi_update_csc_coeffs(hdmi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* hdmi initialization step b.4 */
 | 
			
		||||
static void hdmi_enable_video_path(struct dw_hdmi *hdmi, bool audio)
 | 
			
		||||
{
 | 
			
		||||
@ -479,6 +719,20 @@ static void hdmi_enable_video_path(struct dw_hdmi *hdmi, bool audio)
 | 
			
		||||
	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
 | 
			
		||||
	hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
 | 
			
		||||
 | 
			
		||||
	/* Enable csc path */
 | 
			
		||||
	if (is_color_space_conversion(hdmi)) {
 | 
			
		||||
		clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
 | 
			
		||||
		hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Enable color space conversion if needed */
 | 
			
		||||
	if (is_color_space_conversion(hdmi))
 | 
			
		||||
		hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
 | 
			
		||||
			   HDMI_MC_FLOWCTRL);
 | 
			
		||||
	else
 | 
			
		||||
		hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
 | 
			
		||||
			   HDMI_MC_FLOWCTRL);
 | 
			
		||||
 | 
			
		||||
	if (audio) {
 | 
			
		||||
		clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
 | 
			
		||||
		hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
 | 
			
		||||
@ -732,6 +986,7 @@ int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hdmi_video_packetize(hdmi);
 | 
			
		||||
	hdmi_video_csc(hdmi);
 | 
			
		||||
	hdmi_video_sample(hdmi);
 | 
			
		||||
 | 
			
		||||
	hdmi_clear_overflow(hdmi);
 | 
			
		||||
@ -754,6 +1009,12 @@ void dw_hdmi_init(struct dw_hdmi *hdmi)
 | 
			
		||||
		  HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
 | 
			
		||||
		  HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
 | 
			
		||||
 | 
			
		||||
	if (hdmi->write_reg)
 | 
			
		||||
		hdmi_write = hdmi->write_reg;
 | 
			
		||||
 | 
			
		||||
	if (hdmi->read_reg)
 | 
			
		||||
		hdmi_read = hdmi->read_reg;
 | 
			
		||||
 | 
			
		||||
	hdmi_write(hdmi, ih_mute, HDMI_IH_MUTE);
 | 
			
		||||
 | 
			
		||||
	/* enable i2c master done irq */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								drivers/video/meson/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								drivers/video/meson/Kconfig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
# SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2018 BayLibre, SAS
 | 
			
		||||
#
 | 
			
		||||
# Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 | 
			
		||||
config VIDEO_MESON
 | 
			
		||||
	bool "Enable Amlogic Meson video support"
 | 
			
		||||
	depends on DM_VIDEO
 | 
			
		||||
	select DISPLAY
 | 
			
		||||
	help
 | 
			
		||||
	  Enable Amlogic Meson Video Processing Unit video support.
 | 
			
		||||
							
								
								
									
										9
									
								
								drivers/video/meson/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								drivers/video/meson/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
# SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2018 BayLibre, SAS
 | 
			
		||||
#
 | 
			
		||||
# Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_VIDEO_MESON) = meson_vpu.o meson_vpu_init.o meson_canvas.o
 | 
			
		||||
obj-$(CONFIG_VIDEO_MESON) += meson_plane.o meson_venc.o meson_vclk.o
 | 
			
		||||
obj-$(CONFIG_VIDEO_MESON) += meson_dw_hdmi.o simplefb_common.o ../dw_hdmi.o
 | 
			
		||||
							
								
								
									
										45
									
								
								drivers/video/meson/meson_canvas.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								drivers/video/meson/meson_canvas.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Amlogic Meson Video Processing Unit driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2018 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson_vpu.h"
 | 
			
		||||
 | 
			
		||||
/* DMC Registers */
 | 
			
		||||
#define DMC_CAV_LUT_DATAL	0x48 /* 0x12 offset in data sheet */
 | 
			
		||||
#define CANVAS_WIDTH_LBIT	29
 | 
			
		||||
#define CANVAS_WIDTH_LWID	3
 | 
			
		||||
#define DMC_CAV_LUT_DATAH	0x4c /* 0x13 offset in data sheet */
 | 
			
		||||
#define CANVAS_WIDTH_HBIT	0
 | 
			
		||||
#define CANVAS_HEIGHT_BIT	9
 | 
			
		||||
#define CANVAS_BLKMODE_BIT	24
 | 
			
		||||
#define DMC_CAV_LUT_ADDR	0x50 /* 0x14 offset in data sheet */
 | 
			
		||||
#define CANVAS_LUT_WR_EN	(0x2 << 8)
 | 
			
		||||
#define CANVAS_LUT_RD_EN	(0x1 << 8)
 | 
			
		||||
 | 
			
		||||
void meson_canvas_setup(struct meson_vpu_priv *priv,
 | 
			
		||||
			u32 canvas_index, u32 addr,
 | 
			
		||||
			u32 stride, u32 height,
 | 
			
		||||
			unsigned int wrap,
 | 
			
		||||
			unsigned int blkmode)
 | 
			
		||||
{
 | 
			
		||||
	dmc_write(DMC_CAV_LUT_DATAL,
 | 
			
		||||
		  (((addr + 7) >> 3)) |
 | 
			
		||||
		  (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
 | 
			
		||||
 | 
			
		||||
	dmc_write(DMC_CAV_LUT_DATAH,
 | 
			
		||||
		  ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
 | 
			
		||||
						CANVAS_WIDTH_HBIT) |
 | 
			
		||||
		  (height << CANVAS_HEIGHT_BIT) |
 | 
			
		||||
		  (wrap << 22) |
 | 
			
		||||
		  (blkmode << CANVAS_BLKMODE_BIT));
 | 
			
		||||
 | 
			
		||||
	dmc_write(DMC_CAV_LUT_ADDR,
 | 
			
		||||
		  CANVAS_LUT_WR_EN | canvas_index);
 | 
			
		||||
 | 
			
		||||
	/* Force a read-back to make sure everything is flushed. */
 | 
			
		||||
	dmc_read(DMC_CAV_LUT_DATAH);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										445
									
								
								drivers/video/meson/meson_dw_hdmi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										445
									
								
								drivers/video/meson/meson_dw_hdmi.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,445 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 BayLibre, SAS
 | 
			
		||||
 * Author: Jorge Ramirez-Ortiz <jramirez@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <common.h>
 | 
			
		||||
#include <display.h>
 | 
			
		||||
#include <dm.h>
 | 
			
		||||
#include <edid.h>
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
#include <dw_hdmi.h>
 | 
			
		||||
#include <dm/device-internal.h>
 | 
			
		||||
#include <dm/uclass-internal.h>
 | 
			
		||||
#include <power/regulator.h>
 | 
			
		||||
#include <clk.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <reset.h>
 | 
			
		||||
#include <media_bus_format.h>
 | 
			
		||||
#include "meson_dw_hdmi.h"
 | 
			
		||||
#include "meson_vpu.h"
 | 
			
		||||
 | 
			
		||||
/* TOP Block Communication Channel */
 | 
			
		||||
#define HDMITX_TOP_ADDR_REG	0x0
 | 
			
		||||
#define HDMITX_TOP_DATA_REG	0x4
 | 
			
		||||
#define HDMITX_TOP_CTRL_REG	0x8
 | 
			
		||||
 | 
			
		||||
/* Controller Communication Channel */
 | 
			
		||||
#define HDMITX_DWC_ADDR_REG	0x10
 | 
			
		||||
#define HDMITX_DWC_DATA_REG	0x14
 | 
			
		||||
#define HDMITX_DWC_CTRL_REG	0x18
 | 
			
		||||
 | 
			
		||||
/* HHI Registers */
 | 
			
		||||
#define HHI_MEM_PD_REG0		0x100 /* 0x40 */
 | 
			
		||||
#define HHI_HDMI_CLK_CNTL	0x1cc /* 0x73 */
 | 
			
		||||
#define HHI_HDMI_PHY_CNTL0	0x3a0 /* 0xe8 */
 | 
			
		||||
#define HHI_HDMI_PHY_CNTL1	0x3a4 /* 0xe9 */
 | 
			
		||||
#define HHI_HDMI_PHY_CNTL2	0x3a8 /* 0xea */
 | 
			
		||||
#define HHI_HDMI_PHY_CNTL3	0x3ac /* 0xeb */
 | 
			
		||||
 | 
			
		||||
struct meson_dw_hdmi {
 | 
			
		||||
	struct udevice *dev;
 | 
			
		||||
	struct dw_hdmi hdmi;
 | 
			
		||||
	void __iomem *hhi_base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum hdmi_compatible {
 | 
			
		||||
	HDMI_COMPATIBLE_GXBB = 0,
 | 
			
		||||
	HDMI_COMPATIBLE_GXL = 1,
 | 
			
		||||
	HDMI_COMPATIBLE_GXM = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline bool meson_hdmi_is_compatible(struct meson_dw_hdmi *priv,
 | 
			
		||||
					    enum hdmi_compatible family)
 | 
			
		||||
{
 | 
			
		||||
	enum hdmi_compatible compat = dev_get_driver_data(priv->dev);
 | 
			
		||||
 | 
			
		||||
	return compat == family;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned int dw_hdmi_top_read(struct dw_hdmi *hdmi, unsigned int addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int data;
 | 
			
		||||
 | 
			
		||||
	/* ADDR must be written twice */
 | 
			
		||||
	writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG);
 | 
			
		||||
	writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG);
 | 
			
		||||
 | 
			
		||||
	/* Read needs a second DATA read */
 | 
			
		||||
	data = readl(hdmi->ioaddr + HDMITX_TOP_DATA_REG);
 | 
			
		||||
	data = readl(hdmi->ioaddr + HDMITX_TOP_DATA_REG);
 | 
			
		||||
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dw_hdmi_top_write(struct dw_hdmi *hdmi,
 | 
			
		||||
				     unsigned int addr, unsigned int data)
 | 
			
		||||
{
 | 
			
		||||
	/* ADDR must be written twice */
 | 
			
		||||
	writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG);
 | 
			
		||||
	writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG);
 | 
			
		||||
 | 
			
		||||
	/* Write needs single DATA write */
 | 
			
		||||
	writel(data, hdmi->ioaddr + HDMITX_TOP_DATA_REG);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dw_hdmi_top_write_bits(struct dw_hdmi *hdmi,
 | 
			
		||||
					  unsigned int addr,
 | 
			
		||||
					  unsigned int mask,
 | 
			
		||||
					  unsigned int val)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int data = dw_hdmi_top_read(hdmi, addr);
 | 
			
		||||
 | 
			
		||||
	data &= ~mask;
 | 
			
		||||
	data |= val;
 | 
			
		||||
	dw_hdmi_top_write(hdmi, addr, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u8 dw_hdmi_dwc_read(struct dw_hdmi *hdmi, int addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int data;
 | 
			
		||||
 | 
			
		||||
	/* ADDR must be written twice */
 | 
			
		||||
	writel(addr & 0xffff, hdmi->ioaddr + HDMITX_DWC_ADDR_REG);
 | 
			
		||||
	writel(addr & 0xffff, hdmi->ioaddr + HDMITX_DWC_ADDR_REG);
 | 
			
		||||
 | 
			
		||||
	/* Read needs a second DATA read */
 | 
			
		||||
	data = readl(hdmi->ioaddr + HDMITX_DWC_DATA_REG);
 | 
			
		||||
	data = readl(hdmi->ioaddr + HDMITX_DWC_DATA_REG);
 | 
			
		||||
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dw_hdmi_dwc_write(struct dw_hdmi *hdmi, u8 data, int addr)
 | 
			
		||||
{
 | 
			
		||||
	/* ADDR must be written twice */
 | 
			
		||||
	writel(addr & 0xffff, hdmi->ioaddr + HDMITX_DWC_ADDR_REG);
 | 
			
		||||
	writel(addr & 0xffff, hdmi->ioaddr + HDMITX_DWC_ADDR_REG);
 | 
			
		||||
 | 
			
		||||
	/* Write needs single DATA write */
 | 
			
		||||
	writel(data, hdmi->ioaddr + HDMITX_DWC_DATA_REG);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dw_hdmi_dwc_write_bits(struct dw_hdmi *hdmi,
 | 
			
		||||
					  unsigned int addr,
 | 
			
		||||
					  unsigned int mask,
 | 
			
		||||
					  unsigned int val)
 | 
			
		||||
{
 | 
			
		||||
	u8 data = dw_hdmi_dwc_read(hdmi, addr);
 | 
			
		||||
 | 
			
		||||
	data &= ~mask;
 | 
			
		||||
	data |= val;
 | 
			
		||||
 | 
			
		||||
	dw_hdmi_dwc_write(hdmi, data, addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dw_hdmi_hhi_write(struct meson_dw_hdmi *priv,
 | 
			
		||||
				     unsigned int addr, unsigned int data)
 | 
			
		||||
{
 | 
			
		||||
	hhi_write(addr, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute__((unused))
 | 
			
		||||
static unsigned int dw_hdmi_hhi_read(struct meson_dw_hdmi *priv,
 | 
			
		||||
				     unsigned int addr)
 | 
			
		||||
{
 | 
			
		||||
	return hhi_read(addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dw_hdmi_hhi_update_bits(struct meson_dw_hdmi *priv,
 | 
			
		||||
					   unsigned int addr,
 | 
			
		||||
					   unsigned int mask,
 | 
			
		||||
					   unsigned int val)
 | 
			
		||||
{
 | 
			
		||||
	hhi_update_bits(addr, mask, val);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int meson_dw_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
 | 
			
		||||
{
 | 
			
		||||
#if defined DEBUG
 | 
			
		||||
	struct display_timing timing;
 | 
			
		||||
	int panel_bits_per_colour;
 | 
			
		||||
#endif
 | 
			
		||||
	struct meson_dw_hdmi *priv = dev_get_priv(dev);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = dw_hdmi_read_edid(&priv->hdmi, buf, buf_size);
 | 
			
		||||
 | 
			
		||||
#if defined DEBUG
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	edid_print_info((struct edid1_info *)buf);
 | 
			
		||||
	edid_get_timing(buf, ret, &timing, &panel_bits_per_colour);
 | 
			
		||||
	debug("Display timing:\n");
 | 
			
		||||
	debug(" hactive %04d, hfrontp %04d, hbackp %04d hsync %04d\n"
 | 
			
		||||
	      " vactive %04d, vfrontp %04d, vbackp %04d vsync %04d\n",
 | 
			
		||||
	       timing.hactive.typ, timing.hfront_porch.typ,
 | 
			
		||||
	       timing.hback_porch.typ, timing.hsync_len.typ,
 | 
			
		||||
	       timing.vactive.typ, timing.vfront_porch.typ,
 | 
			
		||||
	       timing.vback_porch.typ, timing.vsync_len.typ);
 | 
			
		||||
	debug(" flags: ");
 | 
			
		||||
	if (timing.flags & DISPLAY_FLAGS_INTERLACED)
 | 
			
		||||
		debug("interlaced ");
 | 
			
		||||
	if (timing.flags & DISPLAY_FLAGS_DOUBLESCAN)
 | 
			
		||||
		debug("doublescan ");
 | 
			
		||||
	if (timing.flags & DISPLAY_FLAGS_DOUBLECLK)
 | 
			
		||||
		debug("doubleclk ");
 | 
			
		||||
	if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
 | 
			
		||||
		debug("hsync_low ");
 | 
			
		||||
	if (timing.flags & DISPLAY_FLAGS_HSYNC_HIGH)
 | 
			
		||||
		debug("hsync_high ");
 | 
			
		||||
	if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
 | 
			
		||||
		debug("vsync_low ");
 | 
			
		||||
	if (timing.flags & DISPLAY_FLAGS_VSYNC_HIGH)
 | 
			
		||||
		debug("vsync_high ");
 | 
			
		||||
	debug("\n");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *priv)
 | 
			
		||||
{
 | 
			
		||||
	/* Enable and software reset */
 | 
			
		||||
	dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
 | 
			
		||||
 | 
			
		||||
	mdelay(2);
 | 
			
		||||
 | 
			
		||||
	/* Enable and unreset */
 | 
			
		||||
	dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, 0xf, 0xe);
 | 
			
		||||
 | 
			
		||||
	mdelay(2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void meson_dw_hdmi_phy_setup_mode(struct meson_dw_hdmi *priv,
 | 
			
		||||
					 uint pixel_clock)
 | 
			
		||||
{
 | 
			
		||||
	pixel_clock = pixel_clock / 1000;
 | 
			
		||||
 | 
			
		||||
	if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXL) ||
 | 
			
		||||
	    meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXM)) {
 | 
			
		||||
		if (pixel_clock >= 371250) {
 | 
			
		||||
			/* 5.94Gbps, 3.7125Gbps */
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL0, 0x333d3282);
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL3, 0x2136315b);
 | 
			
		||||
		} else if (pixel_clock >= 297000) {
 | 
			
		||||
			/* 2.97Gbps */
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL0, 0x33303382);
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL3, 0x2036315b);
 | 
			
		||||
		} else if (pixel_clock >= 148500) {
 | 
			
		||||
			/* 1.485Gbps */
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL0, 0x33303362);
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL3, 0x2016315b);
 | 
			
		||||
		} else {
 | 
			
		||||
			/* 742.5Mbps, and below */
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL0, 0x33604142);
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL3, 0x0016315b);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (pixel_clock >= 371250) {
 | 
			
		||||
			/* 5.94Gbps, 3.7125Gbps */
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL0, 0x33353245);
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL3, 0x2100115b);
 | 
			
		||||
		} else if (pixel_clock >= 297000) {
 | 
			
		||||
			/* 2.97Gbps */
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL0, 0x33634283);
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL3, 0xb000115b);
 | 
			
		||||
		} else {
 | 
			
		||||
			/* 1.485Gbps, and below */
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL0, 0x33632122);
 | 
			
		||||
			hhi_write(HHI_HDMI_PHY_CNTL3, 0x2000115b);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock)
 | 
			
		||||
{
 | 
			
		||||
	struct meson_dw_hdmi *priv = container_of(hdmi, struct meson_dw_hdmi,
 | 
			
		||||
						  hdmi);
 | 
			
		||||
	/* Enable clocks */
 | 
			
		||||
	dw_hdmi_hhi_update_bits(priv, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
 | 
			
		||||
 | 
			
		||||
	/* Bring HDMITX MEM output of power down */
 | 
			
		||||
	dw_hdmi_hhi_update_bits(priv, HHI_MEM_PD_REG0, 0xff << 8, 0);
 | 
			
		||||
 | 
			
		||||
	/* Bring out of reset */
 | 
			
		||||
	dw_hdmi_top_write(hdmi, HDMITX_TOP_SW_RESET,  0);
 | 
			
		||||
 | 
			
		||||
	/* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
 | 
			
		||||
	dw_hdmi_top_write_bits(hdmi, HDMITX_TOP_CLK_CNTL, 0x3, 0x3);
 | 
			
		||||
	dw_hdmi_top_write_bits(hdmi, HDMITX_TOP_CLK_CNTL, 0x3 << 4, 0x3 << 4);
 | 
			
		||||
 | 
			
		||||
	/* Enable normal output to PHY */
 | 
			
		||||
	dw_hdmi_top_write(hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
 | 
			
		||||
 | 
			
		||||
	/* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
 | 
			
		||||
	dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
 | 
			
		||||
	dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
 | 
			
		||||
 | 
			
		||||
	/* Load TMDS pattern */
 | 
			
		||||
	dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
 | 
			
		||||
	mdelay(20);
 | 
			
		||||
	dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
 | 
			
		||||
 | 
			
		||||
	/* Setup PHY parameters */
 | 
			
		||||
	meson_dw_hdmi_phy_setup_mode(priv, pixel_clock);
 | 
			
		||||
 | 
			
		||||
	/* Setup PHY */
 | 
			
		||||
	dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1,
 | 
			
		||||
				0xffff << 16, 0x0390 << 16);
 | 
			
		||||
 | 
			
		||||
	/* BIT_INVERT */
 | 
			
		||||
	if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXL) ||
 | 
			
		||||
	    meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXM))
 | 
			
		||||
		dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, BIT(17), 0);
 | 
			
		||||
	else
 | 
			
		||||
		dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1,
 | 
			
		||||
					BIT(17), BIT(17));
 | 
			
		||||
 | 
			
		||||
	/* Disable clock, fifo, fifo_wr */
 | 
			
		||||
	dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, 0xf, 0);
 | 
			
		||||
 | 
			
		||||
	mdelay(100);
 | 
			
		||||
 | 
			
		||||
	/* Reset PHY 3 times in a row */
 | 
			
		||||
	meson_dw_hdmi_phy_reset(priv);
 | 
			
		||||
	meson_dw_hdmi_phy_reset(priv);
 | 
			
		||||
	meson_dw_hdmi_phy_reset(priv);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int meson_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
 | 
			
		||||
				const struct display_timing *edid)
 | 
			
		||||
{
 | 
			
		||||
	struct meson_dw_hdmi *priv = dev_get_priv(dev);
 | 
			
		||||
 | 
			
		||||
	/* will back into meson_dw_hdmi_phy_init */
 | 
			
		||||
	return dw_hdmi_enable(&priv->hdmi, edid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int meson_dw_hdmi_wait_hpd(struct dw_hdmi *hdmi)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* Poll 1 second for HPD signal */
 | 
			
		||||
	for (i = 0; i < 10; ++i) {
 | 
			
		||||
		if (dw_hdmi_top_read(hdmi, HDMITX_TOP_STAT0))
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		mdelay(100);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -ETIMEDOUT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int meson_dw_hdmi_probe(struct udevice *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct meson_dw_hdmi *priv = dev_get_priv(dev);
 | 
			
		||||
	struct reset_ctl_bulk resets;
 | 
			
		||||
	struct clk_bulk clocks;
 | 
			
		||||
	struct udevice *supply;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	priv->dev = dev;
 | 
			
		||||
 | 
			
		||||
	priv->hdmi.ioaddr = (ulong)dev_remap_addr_index(dev, 0);
 | 
			
		||||
	if (!priv->hdmi.ioaddr)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	priv->hhi_base = dev_remap_addr_index(dev, 1);
 | 
			
		||||
	if (!priv->hhi_base)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	priv->hdmi.hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 | 
			
		||||
	priv->hdmi.hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
 | 
			
		||||
	priv->hdmi.phy_set = meson_dw_hdmi_phy_init;
 | 
			
		||||
	priv->hdmi.write_reg = dw_hdmi_dwc_write;
 | 
			
		||||
	priv->hdmi.read_reg = dw_hdmi_dwc_read;
 | 
			
		||||
	priv->hdmi.i2c_clk_high = 0x67;
 | 
			
		||||
	priv->hdmi.i2c_clk_low = 0x78;
 | 
			
		||||
 | 
			
		||||
	ret = device_get_supply_regulator(dev, "hdmi-supply", &supply);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = regulator_set_enable(supply, true);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = reset_get_bulk(dev, &resets);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = clk_get_bulk(dev, &clocks);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = clk_enable_bulk(&clocks);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* Enable clocks */
 | 
			
		||||
	dw_hdmi_hhi_update_bits(priv, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
 | 
			
		||||
 | 
			
		||||
	/* Bring HDMITX MEM output of power down */
 | 
			
		||||
	dw_hdmi_hhi_update_bits(priv, HHI_MEM_PD_REG0, 0xff << 8, 0);
 | 
			
		||||
 | 
			
		||||
	/* Reset HDMITX APB & TX & PHY: cycle needed for EDID */
 | 
			
		||||
	ret = reset_deassert_bulk(&resets);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = reset_assert_bulk(&resets);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = reset_deassert_bulk(&resets);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* Enable APB3 fail on error */
 | 
			
		||||
	writel_bits(BIT(15), BIT(15), priv->hdmi.ioaddr + HDMITX_TOP_CTRL_REG);
 | 
			
		||||
	writel_bits(BIT(15), BIT(15), priv->hdmi.ioaddr + HDMITX_DWC_CTRL_REG);
 | 
			
		||||
 | 
			
		||||
	/* Bring out of reset */
 | 
			
		||||
	dw_hdmi_top_write(&priv->hdmi, HDMITX_TOP_SW_RESET,  0);
 | 
			
		||||
	mdelay(20);
 | 
			
		||||
	dw_hdmi_top_write(&priv->hdmi, HDMITX_TOP_CLK_CNTL, 0xff);
 | 
			
		||||
 | 
			
		||||
	dw_hdmi_init(&priv->hdmi);
 | 
			
		||||
	dw_hdmi_phy_init(&priv->hdmi);
 | 
			
		||||
 | 
			
		||||
	/* wait for connector */
 | 
			
		||||
	ret = meson_dw_hdmi_wait_hpd(&priv->hdmi);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		debug("hdmi can not get hpd signal\n");
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct dm_display_ops meson_dw_hdmi_ops = {
 | 
			
		||||
	.read_edid = meson_dw_hdmi_read_edid,
 | 
			
		||||
	.enable = meson_dw_hdmi_enable,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct udevice_id meson_dw_hdmi_ids[] = {
 | 
			
		||||
	{ .compatible = "amlogic,meson-gxbb-dw-hdmi",
 | 
			
		||||
		.data = HDMI_COMPATIBLE_GXBB },
 | 
			
		||||
	{ .compatible = "amlogic,meson-gxl-dw-hdmi",
 | 
			
		||||
		.data = HDMI_COMPATIBLE_GXL },
 | 
			
		||||
	{ .compatible = "amlogic,meson-gxm-dw-hdmi",
 | 
			
		||||
		.data = HDMI_COMPATIBLE_GXM },
 | 
			
		||||
	{ }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
U_BOOT_DRIVER(meson_dw_hdmi) = {
 | 
			
		||||
	.name = "meson_dw_hdmi",
 | 
			
		||||
	.id = UCLASS_DISPLAY,
 | 
			
		||||
	.of_match = meson_dw_hdmi_ids,
 | 
			
		||||
	.ops = &meson_dw_hdmi_ops,
 | 
			
		||||
	.probe = meson_dw_hdmi_probe,
 | 
			
		||||
	.priv_auto_alloc_size = sizeof(struct meson_dw_hdmi),
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										134
									
								
								drivers/video/meson/meson_dw_hdmi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								drivers/video/meson/meson_dw_hdmi.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,134 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 BayLibre, SAS
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MESON_DW_HDMI_H
 | 
			
		||||
#define __MESON_DW_HDMI_H
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Bit 7 RW Reserved. Default 1.
 | 
			
		||||
 * Bit 6 RW Reserved. Default 1.
 | 
			
		||||
 * Bit 5 RW Reserved. Default 1.
 | 
			
		||||
 * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset.
 | 
			
		||||
 *     Default 1.
 | 
			
		||||
 * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset;
 | 
			
		||||
 *     0=Release from reset.
 | 
			
		||||
 *     Default 1.
 | 
			
		||||
 * Bit 2 RW sw_reset_mem: KSV/REVOC mem. 1=Apply reset; 0=Release from reset.
 | 
			
		||||
 *     Default 1.
 | 
			
		||||
 * Bit 1 RW sw_reset_rnd: random number interface to HDCP. 1=Apply reset;
 | 
			
		||||
 *     0=Release from reset. Default 1.
 | 
			
		||||
 * Bit 0 RW sw_reset_core: connects to IP's ~irstz. 1=Apply reset;
 | 
			
		||||
 *     0=Release from reset. Default 1.
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_SW_RESET                     (0x000)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0.
 | 
			
		||||
 * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0.
 | 
			
		||||
 * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0.
 | 
			
		||||
 * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0.
 | 
			
		||||
 * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0.
 | 
			
		||||
 * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0.
 | 
			
		||||
 * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0.
 | 
			
		||||
 * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0.
 | 
			
		||||
 * Bit 1 RW tmds_clk_en: 1=enable tmds_clk;  0=disable. Default 0.
 | 
			
		||||
 * Bit 0 RW pixel_clk_en: 1=enable pixel_clk; 0=disable. Default 0.
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_CLK_CNTL                     (0x001)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024.    Default 0.
 | 
			
		||||
 * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N.       Default 0.
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_HPD_FILTER                   (0x002)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * intr_maskn: MASK_N, one bit per interrupt source.
 | 
			
		||||
 *     1=Enable interrupt source; 0=Disable interrupt source. Default 0.
 | 
			
		||||
 * [  4] hdcp22_rndnum_err
 | 
			
		||||
 * [  3] nonce_rfrsh_rise
 | 
			
		||||
 * [  2] hpd_fall_intr
 | 
			
		||||
 * [  1] hpd_rise_intr
 | 
			
		||||
 * [  0] core_intr
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_INTR_MASKN                   (0x003)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt
 | 
			
		||||
 *     bit, read back the interrupt status.
 | 
			
		||||
 * Bit    31 R  IP interrupt status
 | 
			
		||||
 * Bit     2 RW hpd_fall
 | 
			
		||||
 * Bit     1 RW hpd_rise
 | 
			
		||||
 * Bit     0 RW IP interrupt
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_INTR_STAT                    (0x004)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * [4]	  hdcp22_rndnum_err
 | 
			
		||||
 * [3]	  nonce_rfrsh_rise
 | 
			
		||||
 * [2]	  hpd_fall
 | 
			
		||||
 * [1]	  hpd_rise
 | 
			
		||||
 * [0]	  core_intr_rise
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_INTR_STAT_CLR                (0x005)
 | 
			
		||||
 | 
			
		||||
#define HDMITX_TOP_INTR_CORE		BIT(0)
 | 
			
		||||
#define HDMITX_TOP_INTR_HPD_RISE	BIT(1)
 | 
			
		||||
#define HDMITX_TOP_INTR_HPD_FALL	BIT(2)
 | 
			
		||||
 | 
			
		||||
/* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data;
 | 
			
		||||
 *     3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0.
 | 
			
		||||
 * Bit 11: 9 RW shift_pttn_repeat: 0=New pattern every clk cycle; 1=New pattern
 | 
			
		||||
 *     every 2 clk cycles; ...; 7=New pattern every 8 clk cycles. Default 0.
 | 
			
		||||
 * Bit 8 RW shift_pttn_en: 1= Enable shift pattern generator; 0=Disable.
 | 
			
		||||
 *     Default 0.
 | 
			
		||||
 * Bit 4: 3 RW prbs_pttn_mode: 0=PRBS11; 1=PRBS15; 2=PRBS7; 3=PRBS31. Default 0.
 | 
			
		||||
 * Bit 2: 1 RW prbs_pttn_width: 0=idle; 1=output 8-bit pattern;
 | 
			
		||||
 *     2=Output 1-bit pattern; 3=output 10-bit pattern. Default 0.
 | 
			
		||||
 * Bit 0 RW prbs_pttn_en: 1=Enable PRBS generator; 0=Disable. Default 0.
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_BIST_CNTL                    (0x006)
 | 
			
		||||
 | 
			
		||||
/* Bit 29:20 RW shift_pttn_data[59:50]. Default 0. */
 | 
			
		||||
/* Bit 19:10 RW shift_pttn_data[69:60]. Default 0. */
 | 
			
		||||
/* Bit  9: 0 RW shift_pttn_data[79:70]. Default 0. */
 | 
			
		||||
#define HDMITX_TOP_SHIFT_PTTN_012               (0x007)
 | 
			
		||||
 | 
			
		||||
/* Bit 29:20 RW shift_pttn_data[29:20]. Default 0. */
 | 
			
		||||
/* Bit 19:10 RW shift_pttn_data[39:30]. Default 0. */
 | 
			
		||||
/* Bit  9: 0 RW shift_pttn_data[49:40]. Default 0. */
 | 
			
		||||
#define HDMITX_TOP_SHIFT_PTTN_345               (0x008)
 | 
			
		||||
 | 
			
		||||
/* Bit 19:10 RW shift_pttn_data[ 9: 0]. Default 0. */
 | 
			
		||||
/* Bit  9: 0 RW shift_pttn_data[19:10]. Default 0. */
 | 
			
		||||
#define HDMITX_TOP_SHIFT_PTTN_67                (0x009)
 | 
			
		||||
 | 
			
		||||
/* Bit 25:16 RW tmds_clk_pttn[19:10]. Default 0. */
 | 
			
		||||
/* Bit  9: 0 RW tmds_clk_pttn[ 9: 0]. Default 0. */
 | 
			
		||||
#define HDMITX_TOP_TMDS_CLK_PTTN_01             (0x00A)
 | 
			
		||||
 | 
			
		||||
/* Bit 25:16 RW tmds_clk_pttn[39:30]. Default 0. */
 | 
			
		||||
/* Bit  9: 0 RW tmds_clk_pttn[29:20]. Default 0. */
 | 
			
		||||
#define HDMITX_TOP_TMDS_CLK_PTTN_23             (0x00B)
 | 
			
		||||
 | 
			
		||||
/* Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern,
 | 
			
		||||
 * used when TMDS CLK rate = TMDS character rate /4. Default 0.
 | 
			
		||||
 * Bit 0 R  Reserved. Default 0.
 | 
			
		||||
 * [	1] shift_tmds_clk_pttn
 | 
			
		||||
 * [	0] load_tmds_clk_pttn
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_TMDS_CLK_PTTN_CNTL           (0x00C)
 | 
			
		||||
 | 
			
		||||
/* Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM
 | 
			
		||||
 * failure, write 1 to clear the failure flag.  Default 0.
 | 
			
		||||
 */
 | 
			
		||||
#define HDMITX_TOP_REVOCMEM_STAT                (0x00D)
 | 
			
		||||
 | 
			
		||||
/* Bit     0 R  filtered HPD status. */
 | 
			
		||||
#define HDMITX_TOP_STAT0                        (0x00E)
 | 
			
		||||
 | 
			
		||||
#endif /* __MESON_DW_HDMI_H */
 | 
			
		||||
							
								
								
									
										177
									
								
								drivers/video/meson/meson_plane.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								drivers/video/meson/meson_plane.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,177 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Amlogic Meson Video Processing Unit driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2018 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson_vpu.h"
 | 
			
		||||
 | 
			
		||||
/* OSDx_BLKx_CFG */
 | 
			
		||||
#define OSD_CANVAS_SEL		16
 | 
			
		||||
 | 
			
		||||
#define OSD_ENDIANNESS_LE	BIT(15)
 | 
			
		||||
#define OSD_ENDIANNESS_BE	(0)
 | 
			
		||||
 | 
			
		||||
#define OSD_BLK_MODE_422	(0x03 << 8)
 | 
			
		||||
#define OSD_BLK_MODE_16		(0x04 << 8)
 | 
			
		||||
#define OSD_BLK_MODE_32		(0x05 << 8)
 | 
			
		||||
#define OSD_BLK_MODE_24		(0x07 << 8)
 | 
			
		||||
 | 
			
		||||
#define OSD_OUTPUT_COLOR_RGB	BIT(7)
 | 
			
		||||
#define OSD_OUTPUT_COLOR_YUV	(0)
 | 
			
		||||
 | 
			
		||||
#define OSD_COLOR_MATRIX_32_RGBA	(0x00 << 2)
 | 
			
		||||
#define OSD_COLOR_MATRIX_32_ARGB	(0x01 << 2)
 | 
			
		||||
#define OSD_COLOR_MATRIX_32_ABGR	(0x02 << 2)
 | 
			
		||||
#define OSD_COLOR_MATRIX_32_BGRA	(0x03 << 2)
 | 
			
		||||
 | 
			
		||||
#define OSD_COLOR_MATRIX_24_RGB		(0x00 << 2)
 | 
			
		||||
 | 
			
		||||
#define OSD_COLOR_MATRIX_16_RGB655	(0x00 << 2)
 | 
			
		||||
#define OSD_COLOR_MATRIX_16_RGB565	(0x04 << 2)
 | 
			
		||||
 | 
			
		||||
#define OSD_INTERLACE_ENABLED	BIT(1)
 | 
			
		||||
#define OSD_INTERLACE_ODD	BIT(0)
 | 
			
		||||
#define OSD_INTERLACE_EVEN	(0)
 | 
			
		||||
 | 
			
		||||
/* OSDx_CTRL_STAT */
 | 
			
		||||
#define OSD_ENABLE		BIT(21)
 | 
			
		||||
#define OSD_BLK0_ENABLE		BIT(0)
 | 
			
		||||
 | 
			
		||||
#define OSD_GLOBAL_ALPHA_SHIFT	12
 | 
			
		||||
 | 
			
		||||
/* OSDx_CTRL_STAT2 */
 | 
			
		||||
#define OSD_REPLACE_EN		BIT(14)
 | 
			
		||||
#define OSD_REPLACE_SHIFT	6
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * When the output is interlaced, the OSD must switch between
 | 
			
		||||
 * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
 | 
			
		||||
 * at each vsync.
 | 
			
		||||
 * But the vertical scaler can provide such funtionnality if
 | 
			
		||||
 * is configured for 2:1 scaling with interlace options enabled.
 | 
			
		||||
 */
 | 
			
		||||
static void meson_vpp_setup_interlace_vscaler_osd1(struct meson_vpu_priv *priv,
 | 
			
		||||
						   struct video_priv *uc_priv)
 | 
			
		||||
{
 | 
			
		||||
	writel(BIT(3) /* Enable scaler */ |
 | 
			
		||||
	       BIT(2), /* Select OSD1 */
 | 
			
		||||
	       priv->io_base + _REG(VPP_OSD_SC_CTRL0));
 | 
			
		||||
 | 
			
		||||
	writel(((uc_priv->xsize - 1) << 16) | (uc_priv->ysize - 1),
 | 
			
		||||
	       priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
 | 
			
		||||
	/* 2:1 scaling */
 | 
			
		||||
	writel((0 << 16) | uc_priv->xsize,
 | 
			
		||||
	       priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
 | 
			
		||||
	writel(((0 >> 1) << 16) | (uc_priv->ysize >> 1),
 | 
			
		||||
	       priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
 | 
			
		||||
 | 
			
		||||
	/* 2:1 scaling values */
 | 
			
		||||
	writel(BIT(16), priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
 | 
			
		||||
	writel(BIT(25), priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
 | 
			
		||||
 | 
			
		||||
	writel(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
 | 
			
		||||
 | 
			
		||||
	writel((4 << 0)  /* osd_vsc_bank_length */ |
 | 
			
		||||
	       (4 << 3)  /* osd_vsc_top_ini_rcv_num0 */ |
 | 
			
		||||
	       (1 << 8)  /* osd_vsc_top_rpt_p0_num0 */ |
 | 
			
		||||
	       (6 << 11) /* osd_vsc_bot_ini_rcv_num0 */ |
 | 
			
		||||
	       (2 << 16) /* osd_vsc_bot_rpt_p0_num0 */ |
 | 
			
		||||
	       BIT(23)	 /* osd_prog_interlace */ |
 | 
			
		||||
	       BIT(24),  /* Enable vertical scaler */
 | 
			
		||||
	       priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meson_vpp_disable_interlace_vscaler_osd1(struct meson_vpu_priv *priv)
 | 
			
		||||
{
 | 
			
		||||
	writel(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
 | 
			
		||||
	writel(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
 | 
			
		||||
	writel(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void meson_vpu_setup_plane(struct udevice *dev, bool is_interlaced)
 | 
			
		||||
{
 | 
			
		||||
	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
 | 
			
		||||
	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 | 
			
		||||
	struct meson_vpu_priv *priv = dev_get_priv(dev);
 | 
			
		||||
	u32 osd1_ctrl_stat;
 | 
			
		||||
	u32 osd1_blk0_cfg[5];
 | 
			
		||||
	bool osd1_interlace;
 | 
			
		||||
	unsigned int src_x1, src_x2, src_y1, src_y2;
 | 
			
		||||
	unsigned int dest_x1, dest_x2, dest_y1, dest_y2;
 | 
			
		||||
 | 
			
		||||
	dest_x1 = src_x1 = 0;
 | 
			
		||||
	dest_x2 = src_x2 = uc_priv->xsize;
 | 
			
		||||
	dest_y1 = src_y1 = 0;
 | 
			
		||||
	dest_y2 = src_y2 = uc_priv->ysize;
 | 
			
		||||
 | 
			
		||||
	/* Enable VPP Postblend */
 | 
			
		||||
	writel(uc_priv->xsize,
 | 
			
		||||
	       priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
 | 
			
		||||
 | 
			
		||||
	writel_bits(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
 | 
			
		||||
		    priv->io_base + _REG(VPP_MISC));
 | 
			
		||||
 | 
			
		||||
	/* uc_plat->base is the framebuffer */
 | 
			
		||||
 | 
			
		||||
	/* Enable OSD and BLK0, set max global alpha */
 | 
			
		||||
	osd1_ctrl_stat = OSD_ENABLE | (0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
 | 
			
		||||
			 OSD_BLK0_ENABLE;
 | 
			
		||||
 | 
			
		||||
	/* Set up BLK0 to point to the right canvas */
 | 
			
		||||
	osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
 | 
			
		||||
			   OSD_ENDIANNESS_LE);
 | 
			
		||||
 | 
			
		||||
	/* On GXBB, Use the old non-HDR RGB2YUV converter */
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
 | 
			
		||||
		osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB;
 | 
			
		||||
 | 
			
		||||
	/* For XRGB, replace the pixel's alpha by 0xFF */
 | 
			
		||||
	writel_bits(OSD_REPLACE_EN, OSD_REPLACE_EN,
 | 
			
		||||
		    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
 | 
			
		||||
	osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
 | 
			
		||||
		OSD_COLOR_MATRIX_32_ARGB;
 | 
			
		||||
 | 
			
		||||
	if (is_interlaced) {
 | 
			
		||||
		osd1_interlace = true;
 | 
			
		||||
		dest_y1 /= 2;
 | 
			
		||||
		dest_y2 /= 2;
 | 
			
		||||
	} else {
 | 
			
		||||
		osd1_interlace = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The format of these registers is (x2 << 16 | x1),
 | 
			
		||||
	 * where x2 is exclusive.
 | 
			
		||||
	 * e.g. +30x1920 would be (1919 << 16) | 30
 | 
			
		||||
	 */
 | 
			
		||||
	osd1_blk0_cfg[1] = ((src_x2 - 1) << 16) | src_x1;
 | 
			
		||||
	osd1_blk0_cfg[2] = ((src_y2 - 1) << 16) | src_y1;
 | 
			
		||||
	osd1_blk0_cfg[3] = ((dest_x2 - 1) << 16) | dest_x1;
 | 
			
		||||
	osd1_blk0_cfg[4] = ((dest_y2 - 1) << 16) | dest_y1;
 | 
			
		||||
 | 
			
		||||
	writel(osd1_ctrl_stat, priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
 | 
			
		||||
	writel(osd1_blk0_cfg[0], priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0));
 | 
			
		||||
	writel(osd1_blk0_cfg[1], priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1));
 | 
			
		||||
	writel(osd1_blk0_cfg[2], priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2));
 | 
			
		||||
	writel(osd1_blk0_cfg[3], priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));
 | 
			
		||||
	writel(osd1_blk0_cfg[4], priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4));
 | 
			
		||||
 | 
			
		||||
	/* If output is interlace, make use of the Scaler */
 | 
			
		||||
	if (osd1_interlace)
 | 
			
		||||
		meson_vpp_setup_interlace_vscaler_osd1(priv, uc_priv);
 | 
			
		||||
	else
 | 
			
		||||
		meson_vpp_disable_interlace_vscaler_osd1(priv);
 | 
			
		||||
 | 
			
		||||
	meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
 | 
			
		||||
			   uc_plat->base, uc_priv->xsize * 4,
 | 
			
		||||
			   uc_priv->ysize, MESON_CANVAS_WRAP_NONE,
 | 
			
		||||
			   MESON_CANVAS_BLKMODE_LINEAR);
 | 
			
		||||
 | 
			
		||||
	/* Enable OSD1 */
 | 
			
		||||
	writel_bits(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
 | 
			
		||||
		    priv->io_base + _REG(VPP_MISC));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1393
									
								
								drivers/video/meson/meson_registers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1393
									
								
								drivers/video/meson/meson_registers.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										893
									
								
								drivers/video/meson/meson_vclk.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										893
									
								
								drivers/video/meson/meson_vclk.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,893 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Amlogic Meson Video Processing Unit driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2018 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <edid.h>
 | 
			
		||||
#include "meson_vpu.h"
 | 
			
		||||
#include <linux/iopoll.h>
 | 
			
		||||
#include <linux/math64.h>
 | 
			
		||||
 | 
			
		||||
#define writel_bits(mask, val, addr) \
 | 
			
		||||
	writel((readl(addr) & ~(mask)) | (val), addr)
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	MESON_VCLK_TARGET_CVBS = 0,
 | 
			
		||||
	MESON_VCLK_TARGET_HDMI = 1,
 | 
			
		||||
	MESON_VCLK_TARGET_DMT = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* HHI Registers */
 | 
			
		||||
#define HHI_VID_PLL_CLK_DIV	0x1a0 /* 0x68 offset in data sheet */
 | 
			
		||||
#define VID_PLL_EN		BIT(19)
 | 
			
		||||
#define VID_PLL_BYPASS		BIT(18)
 | 
			
		||||
#define VID_PLL_PRESET		BIT(15)
 | 
			
		||||
#define HHI_VIID_CLK_DIV	0x128 /* 0x4a offset in data sheet */
 | 
			
		||||
#define VCLK2_DIV_MASK		0xff
 | 
			
		||||
#define VCLK2_DIV_EN		BIT(16)
 | 
			
		||||
#define VCLK2_DIV_RESET		BIT(17)
 | 
			
		||||
#define CTS_VDAC_SEL_MASK	(0xf << 28)
 | 
			
		||||
#define CTS_VDAC_SEL_SHIFT	28
 | 
			
		||||
#define HHI_VIID_CLK_CNTL	0x12c /* 0x4b offset in data sheet */
 | 
			
		||||
#define VCLK2_EN		BIT(19)
 | 
			
		||||
#define VCLK2_SEL_MASK		(0x7 << 16)
 | 
			
		||||
#define VCLK2_SEL_SHIFT		16
 | 
			
		||||
#define VCLK2_SOFT_RESET	BIT(15)
 | 
			
		||||
#define VCLK2_DIV1_EN		BIT(0)
 | 
			
		||||
#define HHI_VID_CLK_DIV		0x164 /* 0x59 offset in data sheet */
 | 
			
		||||
#define VCLK_DIV_MASK		0xff
 | 
			
		||||
#define VCLK_DIV_EN		BIT(16)
 | 
			
		||||
#define VCLK_DIV_RESET		BIT(17)
 | 
			
		||||
#define CTS_ENCP_SEL_MASK	(0xf << 24)
 | 
			
		||||
#define CTS_ENCP_SEL_SHIFT	24
 | 
			
		||||
#define CTS_ENCI_SEL_MASK	(0xf << 28)
 | 
			
		||||
#define CTS_ENCI_SEL_SHIFT	28
 | 
			
		||||
#define HHI_VID_CLK_CNTL	0x17c /* 0x5f offset in data sheet */
 | 
			
		||||
#define VCLK_EN			BIT(19)
 | 
			
		||||
#define VCLK_SEL_MASK		(0x7 << 16)
 | 
			
		||||
#define VCLK_SEL_SHIFT		16
 | 
			
		||||
#define VCLK_SOFT_RESET		BIT(15)
 | 
			
		||||
#define VCLK_DIV1_EN		BIT(0)
 | 
			
		||||
#define VCLK_DIV2_EN		BIT(1)
 | 
			
		||||
#define VCLK_DIV4_EN		BIT(2)
 | 
			
		||||
#define VCLK_DIV6_EN		BIT(3)
 | 
			
		||||
#define VCLK_DIV12_EN		BIT(4)
 | 
			
		||||
#define HHI_VID_CLK_CNTL2	0x194 /* 0x65 offset in data sheet */
 | 
			
		||||
#define CTS_ENCI_EN		BIT(0)
 | 
			
		||||
#define CTS_ENCP_EN		BIT(2)
 | 
			
		||||
#define CTS_VDAC_EN		BIT(4)
 | 
			
		||||
#define HDMI_TX_PIXEL_EN	BIT(5)
 | 
			
		||||
#define HHI_HDMI_CLK_CNTL	0x1cc /* 0x73 offset in data sheet */
 | 
			
		||||
#define HDMI_TX_PIXEL_SEL_MASK	(0xf << 16)
 | 
			
		||||
#define HDMI_TX_PIXEL_SEL_SHIFT	16
 | 
			
		||||
#define CTS_HDMI_SYS_SEL_MASK	(0x7 << 9)
 | 
			
		||||
#define CTS_HDMI_SYS_DIV_MASK	(0x7f)
 | 
			
		||||
#define CTS_HDMI_SYS_EN		BIT(8)
 | 
			
		||||
 | 
			
		||||
#define HHI_HDMI_PLL_CNTL	0x320 /* 0xc8 offset in data sheet */
 | 
			
		||||
#define HHI_HDMI_PLL_CNTL2	0x324 /* 0xc9 offset in data sheet */
 | 
			
		||||
#define HHI_HDMI_PLL_CNTL3	0x328 /* 0xca offset in data sheet */
 | 
			
		||||
#define HHI_HDMI_PLL_CNTL4	0x32C /* 0xcb offset in data sheet */
 | 
			
		||||
#define HHI_HDMI_PLL_CNTL5	0x330 /* 0xcc offset in data sheet */
 | 
			
		||||
#define HHI_HDMI_PLL_CNTL6	0x334 /* 0xcd offset in data sheet */
 | 
			
		||||
 | 
			
		||||
#define HDMI_PLL_RESET		BIT(28)
 | 
			
		||||
#define HDMI_PLL_LOCK		BIT(31)
 | 
			
		||||
 | 
			
		||||
/* VID PLL Dividers */
 | 
			
		||||
enum {
 | 
			
		||||
	VID_PLL_DIV_1 = 0,
 | 
			
		||||
	VID_PLL_DIV_2,
 | 
			
		||||
	VID_PLL_DIV_2p5,
 | 
			
		||||
	VID_PLL_DIV_3,
 | 
			
		||||
	VID_PLL_DIV_3p5,
 | 
			
		||||
	VID_PLL_DIV_3p75,
 | 
			
		||||
	VID_PLL_DIV_4,
 | 
			
		||||
	VID_PLL_DIV_5,
 | 
			
		||||
	VID_PLL_DIV_6,
 | 
			
		||||
	VID_PLL_DIV_6p25,
 | 
			
		||||
	VID_PLL_DIV_7,
 | 
			
		||||
	VID_PLL_DIV_7p5,
 | 
			
		||||
	VID_PLL_DIV_12,
 | 
			
		||||
	VID_PLL_DIV_14,
 | 
			
		||||
	VID_PLL_DIV_15,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void meson_vid_pll_set(struct meson_vpu_priv *priv, unsigned int div)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int shift_val = 0;
 | 
			
		||||
	unsigned int shift_sel = 0;
 | 
			
		||||
 | 
			
		||||
	/* Disable vid_pll output clock */
 | 
			
		||||
	hhi_update_bits(HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
 | 
			
		||||
	hhi_update_bits(HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
 | 
			
		||||
 | 
			
		||||
	switch (div) {
 | 
			
		||||
	case VID_PLL_DIV_2:
 | 
			
		||||
		shift_val = 0x0aaa;
 | 
			
		||||
		shift_sel = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_2p5:
 | 
			
		||||
		shift_val = 0x5294;
 | 
			
		||||
		shift_sel = 2;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_3:
 | 
			
		||||
		shift_val = 0x0db6;
 | 
			
		||||
		shift_sel = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_3p5:
 | 
			
		||||
		shift_val = 0x36cc;
 | 
			
		||||
		shift_sel = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_3p75:
 | 
			
		||||
		shift_val = 0x6666;
 | 
			
		||||
		shift_sel = 2;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_4:
 | 
			
		||||
		shift_val = 0x0ccc;
 | 
			
		||||
		shift_sel = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_5:
 | 
			
		||||
		shift_val = 0x739c;
 | 
			
		||||
		shift_sel = 2;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_6:
 | 
			
		||||
		shift_val = 0x0e38;
 | 
			
		||||
		shift_sel = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_6p25:
 | 
			
		||||
		shift_val = 0x0000;
 | 
			
		||||
		shift_sel = 3;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_7:
 | 
			
		||||
		shift_val = 0x3c78;
 | 
			
		||||
		shift_sel = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_7p5:
 | 
			
		||||
		shift_val = 0x78f0;
 | 
			
		||||
		shift_sel = 2;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_12:
 | 
			
		||||
		shift_val = 0x0fc0;
 | 
			
		||||
		shift_sel = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_14:
 | 
			
		||||
		shift_val = 0x3f80;
 | 
			
		||||
		shift_sel = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	case VID_PLL_DIV_15:
 | 
			
		||||
		shift_val = 0x7f80;
 | 
			
		||||
		shift_sel = 2;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (div == VID_PLL_DIV_1) {
 | 
			
		||||
		/* Enable vid_pll bypass to HDMI pll */
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				VID_PLL_BYPASS, VID_PLL_BYPASS);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Disable Bypass */
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				VID_PLL_BYPASS, 0);
 | 
			
		||||
		/* Clear sel */
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				3 << 16, 0);
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				VID_PLL_PRESET, 0);
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				0x7fff, 0);
 | 
			
		||||
 | 
			
		||||
		/* Setup sel and val */
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				3 << 16, shift_sel << 16);
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				VID_PLL_PRESET, VID_PLL_PRESET);
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				0x7fff, shift_val);
 | 
			
		||||
 | 
			
		||||
		hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
				VID_PLL_PRESET, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Enable the vid_pll output clock */
 | 
			
		||||
	hhi_update_bits(HHI_VID_PLL_CLK_DIV,
 | 
			
		||||
			VID_PLL_EN, VID_PLL_EN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC
 | 
			
		||||
 *
 | 
			
		||||
 * TOFIX: Refactor into table to also handle HDMI frequency and paths
 | 
			
		||||
 */
 | 
			
		||||
static void meson_venci_cvbs_clock_config(struct meson_vpu_priv *priv)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int val;
 | 
			
		||||
 | 
			
		||||
	debug("%s:%d\n", __func__, __LINE__);
 | 
			
		||||
 | 
			
		||||
	/* Setup PLL to output 1.485GHz */
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL, 0x5800023d);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL2, 0x00404e00);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL4, 0x801da72c);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL5, 0x71486980);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL6, 0x00000e55);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL, 0x4800023d);
 | 
			
		||||
	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 | 
			
		||||
		   meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL, 0x4000027b);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL2, 0x800cb300);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL3, 0xa6212844);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL4, 0x0c4d000c);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL5, 0x001fa729);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL6, 0x01a31500);
 | 
			
		||||
 | 
			
		||||
		/* Reset PLL */
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL,
 | 
			
		||||
				HDMI_PLL_RESET, HDMI_PLL_RESET);
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL,
 | 
			
		||||
				HDMI_PLL_RESET, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	debug("%s:%d\n", __func__, __LINE__);
 | 
			
		||||
 | 
			
		||||
	/* Poll for lock bit */
 | 
			
		||||
	readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
 | 
			
		||||
			   (val & HDMI_PLL_LOCK), 10);
 | 
			
		||||
 | 
			
		||||
	/* Disable VCLK2 */
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
 | 
			
		||||
 | 
			
		||||
	/* Setup vid_pll to /1 */
 | 
			
		||||
	meson_vid_pll_set(priv, VID_PLL_DIV_1);
 | 
			
		||||
 | 
			
		||||
	/* Setup the VCLK2 divider value to achieve 27MHz */
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_DIV,
 | 
			
		||||
			VCLK2_DIV_MASK, (55 - 1));
 | 
			
		||||
 | 
			
		||||
	/* select vid_pll for vclk2 */
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_CNTL,
 | 
			
		||||
			VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT));
 | 
			
		||||
	/* enable vclk2 gate */
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN);
 | 
			
		||||
 | 
			
		||||
	/* select vclk_div1 for enci */
 | 
			
		||||
	hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
			CTS_ENCI_SEL_MASK, (8 << CTS_ENCI_SEL_SHIFT));
 | 
			
		||||
	/* select vclk_div1 for vdac */
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_DIV,
 | 
			
		||||
			CTS_VDAC_SEL_MASK, (8 << CTS_VDAC_SEL_SHIFT));
 | 
			
		||||
 | 
			
		||||
	/* release vclk2_div_reset and enable vclk2_div */
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_DIV,
 | 
			
		||||
			VCLK2_DIV_EN | VCLK2_DIV_RESET, VCLK2_DIV_EN);
 | 
			
		||||
 | 
			
		||||
	/* enable vclk2_div1 gate */
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_CNTL,
 | 
			
		||||
			VCLK2_DIV1_EN, VCLK2_DIV1_EN);
 | 
			
		||||
 | 
			
		||||
	/* reset vclk2 */
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_CNTL,
 | 
			
		||||
			VCLK2_SOFT_RESET, VCLK2_SOFT_RESET);
 | 
			
		||||
	hhi_update_bits(HHI_VIID_CLK_CNTL,
 | 
			
		||||
			VCLK2_SOFT_RESET, 0);
 | 
			
		||||
 | 
			
		||||
	/* enable enci_clk */
 | 
			
		||||
	hhi_update_bits(HHI_VID_CLK_CNTL2,
 | 
			
		||||
			CTS_ENCI_EN, CTS_ENCI_EN);
 | 
			
		||||
	/* enable vdac_clk */
 | 
			
		||||
	hhi_update_bits(HHI_VID_CLK_CNTL2,
 | 
			
		||||
			CTS_VDAC_EN, CTS_VDAC_EN);
 | 
			
		||||
 | 
			
		||||
	debug("%s:%d\n", __func__, __LINE__);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
/* PLL	O1 O2 O3 VP DV     EN TX */
 | 
			
		||||
/* 4320 /4 /4 /1 /5 /1  => /2 /2 */
 | 
			
		||||
	MESON_VCLK_HDMI_ENCI_54000 = 1,
 | 
			
		||||
/* 4320 /4 /4 /1 /5 /1  => /1 /2 */
 | 
			
		||||
	MESON_VCLK_HDMI_DDR_54000,
 | 
			
		||||
/* 2970 /4 /1 /1 /5 /1  => /1 /2 */
 | 
			
		||||
	MESON_VCLK_HDMI_DDR_148500,
 | 
			
		||||
/* 2970 /2 /2 /2 /5 /1  => /1 /1 */
 | 
			
		||||
	MESON_VCLK_HDMI_74250,
 | 
			
		||||
/* 2970 /1 /2 /2 /5 /1  => /1 /1 */
 | 
			
		||||
	MESON_VCLK_HDMI_148500,
 | 
			
		||||
/* 2970 /1 /1 /1 /5 /2  => /1 /1 */
 | 
			
		||||
	MESON_VCLK_HDMI_297000,
 | 
			
		||||
/* 5940 /1 /1 /2 /5 /1  => /1 /1 */
 | 
			
		||||
	MESON_VCLK_HDMI_594000
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct meson_vclk_params {
 | 
			
		||||
	unsigned int pll_base_freq;
 | 
			
		||||
	unsigned int pll_od1;
 | 
			
		||||
	unsigned int pll_od2;
 | 
			
		||||
	unsigned int pll_od3;
 | 
			
		||||
	unsigned int vid_pll_div;
 | 
			
		||||
	unsigned int vclk_div;
 | 
			
		||||
} params[] = {
 | 
			
		||||
	[MESON_VCLK_HDMI_ENCI_54000] = {
 | 
			
		||||
		.pll_base_freq = 4320000,
 | 
			
		||||
		.pll_od1 = 4,
 | 
			
		||||
		.pll_od2 = 4,
 | 
			
		||||
		.pll_od3 = 1,
 | 
			
		||||
		.vid_pll_div = VID_PLL_DIV_5,
 | 
			
		||||
		.vclk_div = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[MESON_VCLK_HDMI_DDR_54000] = {
 | 
			
		||||
		.pll_base_freq = 4320000,
 | 
			
		||||
		.pll_od1 = 4,
 | 
			
		||||
		.pll_od2 = 4,
 | 
			
		||||
		.pll_od3 = 1,
 | 
			
		||||
		.vid_pll_div = VID_PLL_DIV_5,
 | 
			
		||||
		.vclk_div = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[MESON_VCLK_HDMI_DDR_148500] = {
 | 
			
		||||
		.pll_base_freq = 2970000,
 | 
			
		||||
		.pll_od1 = 4,
 | 
			
		||||
		.pll_od2 = 1,
 | 
			
		||||
		.pll_od3 = 1,
 | 
			
		||||
		.vid_pll_div = VID_PLL_DIV_5,
 | 
			
		||||
		.vclk_div = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[MESON_VCLK_HDMI_74250] = {
 | 
			
		||||
		.pll_base_freq = 2970000,
 | 
			
		||||
		.pll_od1 = 2,
 | 
			
		||||
		.pll_od2 = 2,
 | 
			
		||||
		.pll_od3 = 2,
 | 
			
		||||
		.vid_pll_div = VID_PLL_DIV_5,
 | 
			
		||||
		.vclk_div = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[MESON_VCLK_HDMI_148500] = {
 | 
			
		||||
		.pll_base_freq = 2970000,
 | 
			
		||||
		.pll_od1 = 1,
 | 
			
		||||
		.pll_od2 = 2,
 | 
			
		||||
		.pll_od3 = 2,
 | 
			
		||||
		.vid_pll_div = VID_PLL_DIV_5,
 | 
			
		||||
		.vclk_div = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[MESON_VCLK_HDMI_297000] = {
 | 
			
		||||
		.pll_base_freq = 2970000,
 | 
			
		||||
		.pll_od1 = 1,
 | 
			
		||||
		.pll_od2 = 1,
 | 
			
		||||
		.pll_od3 = 1,
 | 
			
		||||
		.vid_pll_div = VID_PLL_DIV_5,
 | 
			
		||||
		.vclk_div = 2,
 | 
			
		||||
	},
 | 
			
		||||
	[MESON_VCLK_HDMI_594000] = {
 | 
			
		||||
		.pll_base_freq = 5940000,
 | 
			
		||||
		.pll_od1 = 1,
 | 
			
		||||
		.pll_od2 = 1,
 | 
			
		||||
		.pll_od3 = 2,
 | 
			
		||||
		.vid_pll_div = VID_PLL_DIV_5,
 | 
			
		||||
		.vclk_div = 1,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline unsigned int pll_od_to_reg(unsigned int od)
 | 
			
		||||
{
 | 
			
		||||
	switch (od) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		return 0;
 | 
			
		||||
	case 2:
 | 
			
		||||
		return 1;
 | 
			
		||||
	case 4:
 | 
			
		||||
		return 2;
 | 
			
		||||
	case 8:
 | 
			
		||||
		return 3;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Invalid */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void meson_hdmi_pll_set_params(struct meson_vpu_priv *priv, unsigned int m,
 | 
			
		||||
			       unsigned int frac, unsigned int od1,
 | 
			
		||||
			       unsigned int od2, unsigned int od3)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int val;
 | 
			
		||||
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL, 0x58000200 | m);
 | 
			
		||||
		if (frac)
 | 
			
		||||
			hhi_write(HHI_HDMI_PLL_CNTL2,
 | 
			
		||||
				  0x00004000 | frac);
 | 
			
		||||
		else
 | 
			
		||||
			hhi_write(HHI_HDMI_PLL_CNTL2,
 | 
			
		||||
				  0x00000000);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL4, 0x801da72c);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL5, 0x71486980);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL6, 0x00000e55);
 | 
			
		||||
 | 
			
		||||
		/* Enable and unreset */
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL,
 | 
			
		||||
				0x7 << 28, 0x4 << 28);
 | 
			
		||||
 | 
			
		||||
		/* Poll for lock bit */
 | 
			
		||||
		readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
 | 
			
		||||
				   (val & HDMI_PLL_LOCK), 10);
 | 
			
		||||
	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 | 
			
		||||
		   meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL, 0x40000200 | m);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL3, 0x860f30c4);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL5, 0x001fa729);
 | 
			
		||||
		hhi_write(HHI_HDMI_PLL_CNTL6, 0x01a31500);
 | 
			
		||||
 | 
			
		||||
		/* Reset PLL */
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL,
 | 
			
		||||
				HDMI_PLL_RESET, HDMI_PLL_RESET);
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL,
 | 
			
		||||
				HDMI_PLL_RESET, 0);
 | 
			
		||||
 | 
			
		||||
		/* Poll for lock bit */
 | 
			
		||||
		readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
 | 
			
		||||
				   (val & HDMI_PLL_LOCK), 10);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL2,
 | 
			
		||||
				3 << 16, pll_od_to_reg(od1) << 16);
 | 
			
		||||
	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 | 
			
		||||
		 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL3,
 | 
			
		||||
				3 << 21, pll_od_to_reg(od1) << 21);
 | 
			
		||||
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL2,
 | 
			
		||||
				3 << 22, pll_od_to_reg(od2) << 22);
 | 
			
		||||
	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 | 
			
		||||
		 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL3,
 | 
			
		||||
				3 << 23, pll_od_to_reg(od2) << 23);
 | 
			
		||||
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL2,
 | 
			
		||||
				3 << 18, pll_od_to_reg(od3) << 18);
 | 
			
		||||
	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 | 
			
		||||
		 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_PLL_CNTL3,
 | 
			
		||||
				3 << 19, pll_od_to_reg(od3) << 19);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define XTAL_FREQ 24000
 | 
			
		||||
 | 
			
		||||
static unsigned int meson_hdmi_pll_get_m(struct meson_vpu_priv *priv,
 | 
			
		||||
					 unsigned int pll_freq)
 | 
			
		||||
{
 | 
			
		||||
	/* The GXBB PLL has a /2 pre-multiplier */
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
 | 
			
		||||
		pll_freq /= 2;
 | 
			
		||||
 | 
			
		||||
	return pll_freq / XTAL_FREQ;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define HDMI_FRAC_MAX_GXBB	4096
 | 
			
		||||
#define HDMI_FRAC_MAX_GXL	1024
 | 
			
		||||
 | 
			
		||||
static unsigned int meson_hdmi_pll_get_frac(struct meson_vpu_priv *priv,
 | 
			
		||||
					    unsigned int m,
 | 
			
		||||
					    unsigned int pll_freq)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int parent_freq = XTAL_FREQ;
 | 
			
		||||
	unsigned int frac_max = HDMI_FRAC_MAX_GXL;
 | 
			
		||||
	unsigned int frac_m;
 | 
			
		||||
	unsigned int frac;
 | 
			
		||||
 | 
			
		||||
	/* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
 | 
			
		||||
		frac_max = HDMI_FRAC_MAX_GXBB;
 | 
			
		||||
		parent_freq *= 2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* We can have a perfect match !*/
 | 
			
		||||
	if (pll_freq / m == parent_freq &&
 | 
			
		||||
	    pll_freq % m == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	frac = div_u64((u64)pll_freq * (u64)frac_max, parent_freq);
 | 
			
		||||
	frac_m = m * frac_max;
 | 
			
		||||
	if (frac_m > frac)
 | 
			
		||||
		return frac_max;
 | 
			
		||||
	frac -= frac_m;
 | 
			
		||||
 | 
			
		||||
	return min((u16)frac, (u16)(frac_max - 1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool meson_hdmi_pll_validate_params(struct meson_vpu_priv *priv,
 | 
			
		||||
					   unsigned int m,
 | 
			
		||||
					   unsigned int frac)
 | 
			
		||||
{
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
 | 
			
		||||
		/* Empiric supported min/max dividers */
 | 
			
		||||
		if (m < 53 || m > 123)
 | 
			
		||||
			return false;
 | 
			
		||||
		if (frac >= HDMI_FRAC_MAX_GXBB)
 | 
			
		||||
			return false;
 | 
			
		||||
	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 | 
			
		||||
		   meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
 | 
			
		||||
		/* Empiric supported min/max dividers */
 | 
			
		||||
		if (m < 106 || m > 247)
 | 
			
		||||
			return false;
 | 
			
		||||
		if (frac >= HDMI_FRAC_MAX_GXL)
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool meson_hdmi_pll_find_params(struct meson_vpu_priv *priv,
 | 
			
		||||
				       unsigned int freq,
 | 
			
		||||
				       unsigned int *m,
 | 
			
		||||
				       unsigned int *frac,
 | 
			
		||||
				       unsigned int *od)
 | 
			
		||||
{
 | 
			
		||||
	/* Cycle from /16 to /2 */
 | 
			
		||||
	for (*od = 16 ; *od > 1 ; *od >>= 1) {
 | 
			
		||||
		*m = meson_hdmi_pll_get_m(priv, freq * *od);
 | 
			
		||||
		if (!*m)
 | 
			
		||||
			continue;
 | 
			
		||||
		*frac = meson_hdmi_pll_get_frac(priv, *m, freq * *od);
 | 
			
		||||
 | 
			
		||||
		debug("PLL params for %dkHz: m=%x frac=%x od=%d\n",
 | 
			
		||||
		      freq, *m, *frac, *od);
 | 
			
		||||
 | 
			
		||||
		if (meson_hdmi_pll_validate_params(priv, *m, *frac))
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* pll_freq is the frequency after the OD dividers */
 | 
			
		||||
bool meson_vclk_dmt_supported_freq(struct meson_vpu_priv *priv,
 | 
			
		||||
				   unsigned int freq)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int od, m, frac;
 | 
			
		||||
 | 
			
		||||
	/* In DMT mode, path after PLL is always /10 */
 | 
			
		||||
	freq *= 10;
 | 
			
		||||
 | 
			
		||||
	if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* pll_freq is the frequency after the OD dividers */
 | 
			
		||||
static void meson_hdmi_pll_generic_set(struct meson_vpu_priv *priv,
 | 
			
		||||
				       unsigned int pll_freq)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int od, m, frac, od1, od2, od3;
 | 
			
		||||
 | 
			
		||||
	if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
 | 
			
		||||
		od3 = 1;
 | 
			
		||||
		if (od < 4) {
 | 
			
		||||
			od1 = 2;
 | 
			
		||||
			od2 = 1;
 | 
			
		||||
		} else {
 | 
			
		||||
			od2 = od / 4;
 | 
			
		||||
			od1 = od / od2;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		debug("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n",
 | 
			
		||||
		      pll_freq, m, frac, od1, od2, od3);
 | 
			
		||||
 | 
			
		||||
		meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("Fatal, unable to find parameters for PLL freq %d\n",
 | 
			
		||||
	       pll_freq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meson_vclk_set(struct meson_vpu_priv *priv, unsigned int pll_base_freq,
 | 
			
		||||
	       unsigned int od1, unsigned int od2, unsigned int od3,
 | 
			
		||||
	       unsigned int vid_pll_div, unsigned int vclk_div,
 | 
			
		||||
	       unsigned int hdmi_tx_div, unsigned int venc_div,
 | 
			
		||||
	       bool hdmi_use_enci)
 | 
			
		||||
{
 | 
			
		||||
	/* Set HDMI-TX sys clock */
 | 
			
		||||
	hhi_update_bits(HHI_HDMI_CLK_CNTL,
 | 
			
		||||
			CTS_HDMI_SYS_SEL_MASK, 0);
 | 
			
		||||
	hhi_update_bits(HHI_HDMI_CLK_CNTL,
 | 
			
		||||
			CTS_HDMI_SYS_DIV_MASK, 0);
 | 
			
		||||
	hhi_update_bits(HHI_HDMI_CLK_CNTL,
 | 
			
		||||
			CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
 | 
			
		||||
 | 
			
		||||
	/* Set HDMI PLL rate */
 | 
			
		||||
	if (!od1 && !od2 && !od3) {
 | 
			
		||||
		meson_hdmi_pll_generic_set(priv, pll_base_freq);
 | 
			
		||||
	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
 | 
			
		||||
		switch (pll_base_freq) {
 | 
			
		||||
		case 2970000:
 | 
			
		||||
			meson_hdmi_pll_set_params(priv, 0x3d, 0xe00,
 | 
			
		||||
						  od1, od2, od3);
 | 
			
		||||
			break;
 | 
			
		||||
		case 4320000:
 | 
			
		||||
			meson_hdmi_pll_set_params(priv, 0x5a, 0,
 | 
			
		||||
						  od1, od2, od3);
 | 
			
		||||
			break;
 | 
			
		||||
		case 5940000:
 | 
			
		||||
			meson_hdmi_pll_set_params(priv, 0x7b, 0xc00,
 | 
			
		||||
						  od1, od2, od3);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 | 
			
		||||
		   meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
 | 
			
		||||
		switch (pll_base_freq) {
 | 
			
		||||
		case 2970000:
 | 
			
		||||
			meson_hdmi_pll_set_params(priv, 0x7b, 0x300,
 | 
			
		||||
						  od1, od2, od3);
 | 
			
		||||
			break;
 | 
			
		||||
		case 4320000:
 | 
			
		||||
			meson_hdmi_pll_set_params(priv, 0xb4, 0,
 | 
			
		||||
						  od1, od2, od3);
 | 
			
		||||
			break;
 | 
			
		||||
		case 5940000:
 | 
			
		||||
			meson_hdmi_pll_set_params(priv, 0xf7, 0x200,
 | 
			
		||||
						  od1, od2, od3);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Setup vid_pll divider */
 | 
			
		||||
	meson_vid_pll_set(priv, vid_pll_div);
 | 
			
		||||
 | 
			
		||||
	/* Set VCLK div */
 | 
			
		||||
	hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
			VCLK_SEL_MASK, 0);
 | 
			
		||||
	hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
			VCLK_DIV_MASK, vclk_div - 1);
 | 
			
		||||
 | 
			
		||||
	/* Set HDMI-TX source */
 | 
			
		||||
	switch (hdmi_tx_div) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		/* enable vclk_div1 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV1_EN, VCLK_DIV1_EN);
 | 
			
		||||
 | 
			
		||||
		/* select vclk_div1 for HDMI-TX */
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_CLK_CNTL,
 | 
			
		||||
				HDMI_TX_PIXEL_SEL_MASK, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case 2:
 | 
			
		||||
		/* enable vclk_div2 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV2_EN, VCLK_DIV2_EN);
 | 
			
		||||
 | 
			
		||||
		/* select vclk_div2 for HDMI-TX */
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_CLK_CNTL,
 | 
			
		||||
				HDMI_TX_PIXEL_SEL_MASK,
 | 
			
		||||
				1 << HDMI_TX_PIXEL_SEL_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
	case 4:
 | 
			
		||||
		/* enable vclk_div4 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV4_EN, VCLK_DIV4_EN);
 | 
			
		||||
 | 
			
		||||
		/* select vclk_div4 for HDMI-TX */
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_CLK_CNTL,
 | 
			
		||||
				HDMI_TX_PIXEL_SEL_MASK,
 | 
			
		||||
				2 << HDMI_TX_PIXEL_SEL_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
	case 6:
 | 
			
		||||
		/* enable vclk_div6 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV6_EN, VCLK_DIV6_EN);
 | 
			
		||||
 | 
			
		||||
		/* select vclk_div6 for HDMI-TX */
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_CLK_CNTL,
 | 
			
		||||
				HDMI_TX_PIXEL_SEL_MASK,
 | 
			
		||||
				3 << HDMI_TX_PIXEL_SEL_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
	case 12:
 | 
			
		||||
		/* enable vclk_div12 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV12_EN, VCLK_DIV12_EN);
 | 
			
		||||
 | 
			
		||||
		/* select vclk_div12 for HDMI-TX */
 | 
			
		||||
		hhi_update_bits(HHI_HDMI_CLK_CNTL,
 | 
			
		||||
				HDMI_TX_PIXEL_SEL_MASK,
 | 
			
		||||
				4 << HDMI_TX_PIXEL_SEL_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	hhi_update_bits(HHI_VID_CLK_CNTL2,
 | 
			
		||||
			HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN);
 | 
			
		||||
 | 
			
		||||
	/* Set ENCI/ENCP Source */
 | 
			
		||||
	switch (venc_div) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		/* enable vclk_div1 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV1_EN, VCLK_DIV1_EN);
 | 
			
		||||
 | 
			
		||||
		if (hdmi_use_enci)
 | 
			
		||||
			/* select vclk_div1 for enci */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCI_SEL_MASK, 0);
 | 
			
		||||
		else
 | 
			
		||||
			/* select vclk_div1 for encp */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCP_SEL_MASK, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case 2:
 | 
			
		||||
		/* enable vclk_div2 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV2_EN, VCLK_DIV2_EN);
 | 
			
		||||
 | 
			
		||||
		if (hdmi_use_enci)
 | 
			
		||||
			/* select vclk_div2 for enci */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCI_SEL_MASK,
 | 
			
		||||
					1 << CTS_ENCI_SEL_SHIFT);
 | 
			
		||||
		else
 | 
			
		||||
			/* select vclk_div2 for encp */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCP_SEL_MASK,
 | 
			
		||||
					1 << CTS_ENCP_SEL_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
	case 4:
 | 
			
		||||
		/* enable vclk_div4 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV4_EN, VCLK_DIV4_EN);
 | 
			
		||||
 | 
			
		||||
		if (hdmi_use_enci)
 | 
			
		||||
			/* select vclk_div4 for enci */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCI_SEL_MASK,
 | 
			
		||||
					2 << CTS_ENCI_SEL_SHIFT);
 | 
			
		||||
		else
 | 
			
		||||
			/* select vclk_div4 for encp */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCP_SEL_MASK,
 | 
			
		||||
					2 << CTS_ENCP_SEL_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
	case 6:
 | 
			
		||||
		/* enable vclk_div6 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV6_EN, VCLK_DIV6_EN);
 | 
			
		||||
 | 
			
		||||
		if (hdmi_use_enci)
 | 
			
		||||
			/* select vclk_div6 for enci */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCI_SEL_MASK,
 | 
			
		||||
					3 << CTS_ENCI_SEL_SHIFT);
 | 
			
		||||
		else
 | 
			
		||||
			/* select vclk_div6 for encp */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCP_SEL_MASK,
 | 
			
		||||
					3 << CTS_ENCP_SEL_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
	case 12:
 | 
			
		||||
		/* enable vclk_div12 gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL,
 | 
			
		||||
				VCLK_DIV12_EN, VCLK_DIV12_EN);
 | 
			
		||||
 | 
			
		||||
		if (hdmi_use_enci)
 | 
			
		||||
			/* select vclk_div12 for enci */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCI_SEL_MASK,
 | 
			
		||||
					4 << CTS_ENCI_SEL_SHIFT);
 | 
			
		||||
		else
 | 
			
		||||
			/* select vclk_div12 for encp */
 | 
			
		||||
			hhi_update_bits(HHI_VID_CLK_DIV,
 | 
			
		||||
					CTS_ENCP_SEL_MASK,
 | 
			
		||||
					4 << CTS_ENCP_SEL_SHIFT);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hdmi_use_enci)
 | 
			
		||||
		/* Enable ENCI clock gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL2,
 | 
			
		||||
				CTS_ENCI_EN, CTS_ENCI_EN);
 | 
			
		||||
	else
 | 
			
		||||
		/* Enable ENCP clock gate */
 | 
			
		||||
		hhi_update_bits(HHI_VID_CLK_CNTL2,
 | 
			
		||||
				CTS_ENCP_EN, CTS_ENCP_EN);
 | 
			
		||||
 | 
			
		||||
	hhi_update_bits(HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void meson_vclk_setup(struct meson_vpu_priv *priv, unsigned int target,
 | 
			
		||||
			     unsigned int vclk_freq, unsigned int venc_freq,
 | 
			
		||||
			     unsigned int dac_freq, bool hdmi_use_enci)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int freq;
 | 
			
		||||
	unsigned int hdmi_tx_div;
 | 
			
		||||
	unsigned int venc_div;
 | 
			
		||||
 | 
			
		||||
	if (target == MESON_VCLK_TARGET_CVBS) {
 | 
			
		||||
		meson_venci_cvbs_clock_config(priv);
 | 
			
		||||
		return;
 | 
			
		||||
	} else if (target == MESON_VCLK_TARGET_DMT) {
 | 
			
		||||
		/* The DMT clock path is fixed after the PLL:
 | 
			
		||||
		 * - automatic PLL freq + OD management
 | 
			
		||||
		 * - vid_pll_div = VID_PLL_DIV_5
 | 
			
		||||
		 * - vclk_div = 2
 | 
			
		||||
		 * - hdmi_tx_div = 1
 | 
			
		||||
		 * - venc_div = 1
 | 
			
		||||
		 * - encp encoder
 | 
			
		||||
		 */
 | 
			
		||||
		meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
 | 
			
		||||
			       VID_PLL_DIV_5, 2, 1, 1, false);
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hdmi_tx_div = vclk_freq / dac_freq;
 | 
			
		||||
 | 
			
		||||
	if (hdmi_tx_div == 0) {
 | 
			
		||||
		printf("Fatal Error, invalid HDMI-TX freq %d\n",
 | 
			
		||||
		       dac_freq);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	venc_div = vclk_freq / venc_freq;
 | 
			
		||||
 | 
			
		||||
	if (venc_div == 0) {
 | 
			
		||||
		printf("Fatal Error, invalid HDMI venc freq %d\n",
 | 
			
		||||
		       venc_freq);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (vclk_freq) {
 | 
			
		||||
	case 54000:
 | 
			
		||||
		if (hdmi_use_enci)
 | 
			
		||||
			freq = MESON_VCLK_HDMI_ENCI_54000;
 | 
			
		||||
		else
 | 
			
		||||
			freq = MESON_VCLK_HDMI_DDR_54000;
 | 
			
		||||
		break;
 | 
			
		||||
	case 74250:
 | 
			
		||||
		freq = MESON_VCLK_HDMI_74250;
 | 
			
		||||
		break;
 | 
			
		||||
	case 148500:
 | 
			
		||||
		if (dac_freq != 148500)
 | 
			
		||||
			freq = MESON_VCLK_HDMI_DDR_148500;
 | 
			
		||||
		else
 | 
			
		||||
			freq = MESON_VCLK_HDMI_148500;
 | 
			
		||||
		break;
 | 
			
		||||
	case 297000:
 | 
			
		||||
		freq = MESON_VCLK_HDMI_297000;
 | 
			
		||||
		break;
 | 
			
		||||
	case 594000:
 | 
			
		||||
		freq = MESON_VCLK_HDMI_594000;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		printf("Fatal Error, invalid HDMI vclk freq %d\n",
 | 
			
		||||
		       vclk_freq);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	meson_vclk_set(priv, params[freq].pll_base_freq,
 | 
			
		||||
		       params[freq].pll_od1, params[freq].pll_od2,
 | 
			
		||||
		       params[freq].pll_od3, params[freq].vid_pll_div,
 | 
			
		||||
		       params[freq].vclk_div, hdmi_tx_div, venc_div,
 | 
			
		||||
		       hdmi_use_enci);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void meson_vpu_setup_vclk(struct udevice *dev,
 | 
			
		||||
			  const struct display_timing *mode, bool is_cvbs)
 | 
			
		||||
{
 | 
			
		||||
	struct meson_vpu_priv *priv = dev_get_priv(dev);
 | 
			
		||||
	unsigned int vclk_freq;
 | 
			
		||||
 | 
			
		||||
	if (is_cvbs)
 | 
			
		||||
		return meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
 | 
			
		||||
					0, 0, 0, false);
 | 
			
		||||
 | 
			
		||||
	vclk_freq = mode->pixelclock.typ / 1000;
 | 
			
		||||
 | 
			
		||||
	return meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT,
 | 
			
		||||
				vclk_freq, vclk_freq, vclk_freq, false);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1464
									
								
								drivers/video/meson/meson_venc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1464
									
								
								drivers/video/meson/meson_venc.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										211
									
								
								drivers/video/meson/meson_vpu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								drivers/video/meson/meson_vpu.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,211 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Amlogic Meson Video Processing Unit driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2018 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "meson_vpu.h"
 | 
			
		||||
#include <power-domain.h>
 | 
			
		||||
#include <efi_loader.h>
 | 
			
		||||
#include <dm/device-internal.h>
 | 
			
		||||
#include <dm/uclass-internal.h>
 | 
			
		||||
#include <fdt_support.h>
 | 
			
		||||
#include <linux/sizes.h>
 | 
			
		||||
#include <asm/arch/mem.h>
 | 
			
		||||
#include "meson_registers.h"
 | 
			
		||||
#include "simplefb_common.h"
 | 
			
		||||
 | 
			
		||||
#define MESON_VPU_OVERSCAN SZ_64K
 | 
			
		||||
 | 
			
		||||
/* Static variable for use in meson_vpu_rsv_fb() */
 | 
			
		||||
static struct meson_framebuffer {
 | 
			
		||||
	u64 base;
 | 
			
		||||
	u64 fb_size;
 | 
			
		||||
	unsigned int xsize;
 | 
			
		||||
	unsigned int ysize;
 | 
			
		||||
	bool is_cvbs;
 | 
			
		||||
} meson_fb = { 0 };
 | 
			
		||||
 | 
			
		||||
static int meson_vpu_setup_mode(struct udevice *dev, struct udevice *disp)
 | 
			
		||||
{
 | 
			
		||||
	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
 | 
			
		||||
	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 | 
			
		||||
	struct display_timing timing;
 | 
			
		||||
	bool is_cvbs = false;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (disp) {
 | 
			
		||||
		ret = display_read_timing(disp, &timing);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			debug("%s: Failed to read timings\n", __func__);
 | 
			
		||||
			goto cvbs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		uc_priv->xsize = timing.hactive.typ;
 | 
			
		||||
		uc_priv->ysize = timing.vactive.typ;
 | 
			
		||||
 | 
			
		||||
		ret = display_enable(disp, 0, &timing);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto cvbs;
 | 
			
		||||
	} else {
 | 
			
		||||
cvbs:
 | 
			
		||||
		/* CVBS has a fixed 720x480i (NTSC) and 720x576i (PAL) */
 | 
			
		||||
		is_cvbs = true;
 | 
			
		||||
		timing.flags = DISPLAY_FLAGS_INTERLACED;
 | 
			
		||||
		uc_priv->xsize = 720;
 | 
			
		||||
		uc_priv->ysize = 576;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uc_priv->bpix = VPU_MAX_LOG2_BPP;
 | 
			
		||||
 | 
			
		||||
	meson_fb.is_cvbs = is_cvbs;
 | 
			
		||||
	meson_fb.xsize = uc_priv->xsize;
 | 
			
		||||
	meson_fb.ysize = uc_priv->ysize;
 | 
			
		||||
 | 
			
		||||
	/* Move the framebuffer to the end of addressable ram */
 | 
			
		||||
	meson_fb.fb_size = ALIGN(meson_fb.xsize * meson_fb.ysize *
 | 
			
		||||
				 ((1 << VPU_MAX_LOG2_BPP) / 8) +
 | 
			
		||||
				 MESON_VPU_OVERSCAN, EFI_PAGE_SIZE);
 | 
			
		||||
	meson_fb.base = gd->bd->bi_dram[0].start +
 | 
			
		||||
			gd->bd->bi_dram[0].size - meson_fb.fb_size;
 | 
			
		||||
 | 
			
		||||
	/* Override the framebuffer address */
 | 
			
		||||
	uc_plat->base = meson_fb.base;
 | 
			
		||||
 | 
			
		||||
	meson_vpu_setup_plane(dev, timing.flags & DISPLAY_FLAGS_INTERLACED);
 | 
			
		||||
	meson_vpu_setup_venc(dev, &timing, is_cvbs);
 | 
			
		||||
	meson_vpu_setup_vclk(dev, &timing, is_cvbs);
 | 
			
		||||
 | 
			
		||||
	video_set_flush_dcache(dev, 1);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct udevice_id meson_vpu_ids[] = {
 | 
			
		||||
	{ .compatible = "amlogic,meson-gxbb-vpu", .data = VPU_COMPATIBLE_GXBB },
 | 
			
		||||
	{ .compatible = "amlogic,meson-gxl-vpu", .data = VPU_COMPATIBLE_GXL },
 | 
			
		||||
	{ .compatible = "amlogic,meson-gxm-vpu", .data = VPU_COMPATIBLE_GXM },
 | 
			
		||||
	{ }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int meson_vpu_probe(struct udevice *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct meson_vpu_priv *priv = dev_get_priv(dev);
 | 
			
		||||
	struct power_domain pd;
 | 
			
		||||
	struct udevice *disp;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* Before relocation we don't need to do anything */
 | 
			
		||||
	if (!(gd->flags & GD_FLG_RELOC))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	priv->dev = dev;
 | 
			
		||||
 | 
			
		||||
	priv->io_base = dev_remap_addr_index(dev, 0);
 | 
			
		||||
	if (!priv->io_base)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	priv->hhi_base = dev_remap_addr_index(dev, 1);
 | 
			
		||||
	if (!priv->hhi_base)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	priv->dmc_base = dev_remap_addr_index(dev, 2);
 | 
			
		||||
	if (!priv->dmc_base)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	ret = power_domain_get(dev, &pd);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = power_domain_on(&pd);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	meson_vpu_init(dev);
 | 
			
		||||
 | 
			
		||||
	/* probe the display */
 | 
			
		||||
	ret = uclass_get_device(UCLASS_DISPLAY, 0, &disp);
 | 
			
		||||
 | 
			
		||||
	return meson_vpu_setup_mode(dev, ret ? NULL : disp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int meson_vpu_bind(struct udevice *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
 | 
			
		||||
 | 
			
		||||
	plat->size = VPU_MAX_WIDTH * VPU_MAX_HEIGHT *
 | 
			
		||||
		(1 << VPU_MAX_LOG2_BPP) / 8;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_VIDEO_DT_SIMPLEFB)
 | 
			
		||||
static void meson_vpu_setup_simplefb(void *fdt)
 | 
			
		||||
{
 | 
			
		||||
	const char *pipeline = NULL;
 | 
			
		||||
	u64 mem_start, mem_size;
 | 
			
		||||
	int offset, ret;
 | 
			
		||||
 | 
			
		||||
	if (meson_fb.is_cvbs)
 | 
			
		||||
		pipeline = "vpu-cvbs";
 | 
			
		||||
	else
 | 
			
		||||
		pipeline = "vpu-hdmi";
 | 
			
		||||
 | 
			
		||||
	offset = meson_simplefb_fdt_match(fdt, pipeline);
 | 
			
		||||
	if (offset < 0) {
 | 
			
		||||
		eprintf("Cannot setup simplefb: node not found\n");
 | 
			
		||||
 | 
			
		||||
		/* If simplefb is missing, add it as reserved memory */
 | 
			
		||||
		meson_board_add_reserved_memory(fdt, meson_fb.base,
 | 
			
		||||
						meson_fb.fb_size);
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * SimpleFB will try to iomap the framebuffer, so we can't use
 | 
			
		||||
	 * fdt_add_mem_rsv on the memory area. Instead, the FB is stored
 | 
			
		||||
	 * at the end of the RAM and we strip this portion from the kernel
 | 
			
		||||
	 * allowed region
 | 
			
		||||
	 */
 | 
			
		||||
	mem_start = gd->bd->bi_dram[0].start;
 | 
			
		||||
	mem_size = gd->bd->bi_dram[0].size - meson_fb.fb_size;
 | 
			
		||||
	ret = fdt_fixup_memory_banks(fdt, &mem_start, &mem_size, 1);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		eprintf("Cannot setup simplefb: Error reserving memory\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = fdt_setup_simplefb_node(fdt, offset, meson_fb.base,
 | 
			
		||||
				      meson_fb.xsize, meson_fb.ysize,
 | 
			
		||||
				      meson_fb.xsize * 4, "x8r8g8b8");
 | 
			
		||||
	if (ret)
 | 
			
		||||
		eprintf("Cannot setup simplefb: Error setting properties\n");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void meson_vpu_rsv_fb(void *fdt)
 | 
			
		||||
{
 | 
			
		||||
	if (!meson_fb.base || !meson_fb.xsize || !meson_fb.ysize)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_EFI_LOADER)
 | 
			
		||||
	efi_add_memory_map(meson_fb.base, meson_fb.fb_size >> EFI_PAGE_SHIFT,
 | 
			
		||||
			   EFI_RESERVED_MEMORY_TYPE, false);
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(CONFIG_VIDEO_DT_SIMPLEFB)
 | 
			
		||||
	meson_vpu_setup_simplefb(fdt);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
U_BOOT_DRIVER(meson_vpu) = {
 | 
			
		||||
	.name = "meson_vpu",
 | 
			
		||||
	.id = UCLASS_VIDEO,
 | 
			
		||||
	.of_match = meson_vpu_ids,
 | 
			
		||||
	.probe = meson_vpu_probe,
 | 
			
		||||
	.bind = meson_vpu_bind,
 | 
			
		||||
	.priv_auto_alloc_size = sizeof(struct meson_vpu_priv),
 | 
			
		||||
	.flags  = DM_FLAG_PRE_RELOC,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										97
									
								
								drivers/video/meson/meson_vpu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								drivers/video/meson/meson_vpu.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/*
 | 
			
		||||
 * Amlogic Meson Video Processing Unit driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2018 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MESON_VPU_H__
 | 
			
		||||
#define __MESON_VPU_H__
 | 
			
		||||
 | 
			
		||||
#include <common.h>
 | 
			
		||||
#include <dm.h>
 | 
			
		||||
#include <video.h>
 | 
			
		||||
#include <display.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include "meson_registers.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	/* Maximum size we support */
 | 
			
		||||
	VPU_MAX_WIDTH		= 3840,
 | 
			
		||||
	VPU_MAX_HEIGHT		= 2160,
 | 
			
		||||
	VPU_MAX_LOG2_BPP	= VIDEO_BPP32,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum vpu_compatible {
 | 
			
		||||
	VPU_COMPATIBLE_GXBB = 0,
 | 
			
		||||
	VPU_COMPATIBLE_GXL = 1,
 | 
			
		||||
	VPU_COMPATIBLE_GXM = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct meson_vpu_priv {
 | 
			
		||||
	struct udevice *dev;
 | 
			
		||||
	void __iomem *io_base;
 | 
			
		||||
	void __iomem *hhi_base;
 | 
			
		||||
	void __iomem *dmc_base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline bool meson_vpu_is_compatible(struct meson_vpu_priv *priv,
 | 
			
		||||
					   enum vpu_compatible family)
 | 
			
		||||
{
 | 
			
		||||
	enum vpu_compatible compat = dev_get_driver_data(priv->dev);
 | 
			
		||||
 | 
			
		||||
	return compat == family;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define hhi_update_bits(offset, mask, value) \
 | 
			
		||||
	writel_bits(mask, value, priv->hhi_base + offset)
 | 
			
		||||
 | 
			
		||||
#define hhi_write(offset, value) \
 | 
			
		||||
	writel(value, priv->hhi_base + offset)
 | 
			
		||||
 | 
			
		||||
#define hhi_read(offset) \
 | 
			
		||||
	readl(priv->hhi_base + offset)
 | 
			
		||||
 | 
			
		||||
#define dmc_update_bits(offset, mask, value) \
 | 
			
		||||
	writel_bits(mask, value, priv->dmc_base + offset)
 | 
			
		||||
 | 
			
		||||
#define dmc_write(offset, value) \
 | 
			
		||||
	writel(value, priv->dmc_base + offset)
 | 
			
		||||
 | 
			
		||||
#define dmc_read(offset) \
 | 
			
		||||
	readl(priv->dmc_base + offset)
 | 
			
		||||
 | 
			
		||||
#define MESON_CANVAS_ID_OSD1	0x4e
 | 
			
		||||
 | 
			
		||||
/* Canvas configuration. */
 | 
			
		||||
#define MESON_CANVAS_WRAP_NONE	0x00
 | 
			
		||||
#define	MESON_CANVAS_WRAP_X	0x01
 | 
			
		||||
#define	MESON_CANVAS_WRAP_Y	0x02
 | 
			
		||||
 | 
			
		||||
#define	MESON_CANVAS_BLKMODE_LINEAR	0x00
 | 
			
		||||
#define	MESON_CANVAS_BLKMODE_32x32	0x01
 | 
			
		||||
#define	MESON_CANVAS_BLKMODE_64x64	0x02
 | 
			
		||||
 | 
			
		||||
void meson_canvas_setup(struct meson_vpu_priv *priv,
 | 
			
		||||
			u32 canvas_index, u32 addr,
 | 
			
		||||
			u32 stride, u32 height,
 | 
			
		||||
			unsigned int wrap,
 | 
			
		||||
			unsigned int blkmode);
 | 
			
		||||
 | 
			
		||||
/* Mux VIU/VPP to ENCI */
 | 
			
		||||
#define MESON_VIU_VPP_MUX_ENCI	0x5
 | 
			
		||||
/* Mux VIU/VPP to ENCP */
 | 
			
		||||
#define MESON_VIU_VPP_MUX_ENCP	0xA
 | 
			
		||||
 | 
			
		||||
void meson_vpp_setup_mux(struct meson_vpu_priv *priv, unsigned int mux);
 | 
			
		||||
void meson_vpu_init(struct udevice *dev);
 | 
			
		||||
void meson_vpu_setup_plane(struct udevice *dev, bool is_interlaced);
 | 
			
		||||
bool meson_venc_hdmi_supported_mode(const struct display_timing *mode);
 | 
			
		||||
void meson_vpu_setup_venc(struct udevice *dev,
 | 
			
		||||
			  const struct display_timing *mode, bool is_cvbs);
 | 
			
		||||
bool meson_vclk_dmt_supported_freq(struct meson_vpu_priv *priv,
 | 
			
		||||
				   unsigned int freq);
 | 
			
		||||
void meson_vpu_setup_vclk(struct udevice *dev,
 | 
			
		||||
			  const struct display_timing *mode, bool is_cvbs);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										440
									
								
								drivers/video/meson/meson_vpu_init.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										440
									
								
								drivers/video/meson/meson_vpu_init.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,440 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Amlogic Meson Video Processing Unit driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2018 BayLibre, SAS.
 | 
			
		||||
 * Author: Neil Armstrong <narmstrong@baylibre.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define DEBUG
 | 
			
		||||
 | 
			
		||||
#include "meson_vpu.h"
 | 
			
		||||
 | 
			
		||||
/* HHI Registers */
 | 
			
		||||
#define HHI_VDAC_CNTL0		0x2F4 /* 0xbd offset in data sheet */
 | 
			
		||||
#define HHI_VDAC_CNTL1		0x2F8 /* 0xbe offset in data sheet */
 | 
			
		||||
#define HHI_HDMI_PHY_CNTL0	0x3a0 /* 0xe8 offset in data sheet */
 | 
			
		||||
 | 
			
		||||
/* OSDx_CTRL_STAT2 */
 | 
			
		||||
#define OSD_REPLACE_EN		BIT(14)
 | 
			
		||||
#define OSD_REPLACE_SHIFT	6
 | 
			
		||||
 | 
			
		||||
void meson_vpp_setup_mux(struct meson_vpu_priv *priv, unsigned int mux)
 | 
			
		||||
{
 | 
			
		||||
	writel(mux, priv->io_base + _REG(VPU_VIU_VENC_MUX_CTRL));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned int vpp_filter_coefs_4point_bspline[] = {
 | 
			
		||||
	0x15561500, 0x14561600, 0x13561700, 0x12561800,
 | 
			
		||||
	0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
 | 
			
		||||
	0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200,
 | 
			
		||||
	0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700,
 | 
			
		||||
	0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01,
 | 
			
		||||
	0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201,
 | 
			
		||||
	0x05473301, 0x05463401, 0x04453601, 0x04433702,
 | 
			
		||||
	0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02,
 | 
			
		||||
	0x033d3d03
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void meson_vpp_write_scaling_filter_coefs(struct meson_vpu_priv *priv,
 | 
			
		||||
						 const unsigned int *coefs,
 | 
			
		||||
						 bool is_horizontal)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	writel(is_horizontal ? BIT(8) : 0,
 | 
			
		||||
	       priv->io_base + _REG(VPP_OSD_SCALE_COEF_IDX));
 | 
			
		||||
	for (i = 0; i < 33; i++)
 | 
			
		||||
		writel(coefs[i],
 | 
			
		||||
		       priv->io_base + _REG(VPP_OSD_SCALE_COEF));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const u32 vpp_filter_coefs_bicubic[] = {
 | 
			
		||||
	0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300,
 | 
			
		||||
	0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
 | 
			
		||||
	0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
 | 
			
		||||
	0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
 | 
			
		||||
	0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
 | 
			
		||||
	0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
 | 
			
		||||
	0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
 | 
			
		||||
	0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
 | 
			
		||||
	0xf84848f8
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_vpu_priv *priv,
 | 
			
		||||
						    const unsigned int *coefs,
 | 
			
		||||
						    bool is_horizontal)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	writel(is_horizontal ? BIT(8) : 0,
 | 
			
		||||
	       priv->io_base + _REG(VPP_SCALE_COEF_IDX));
 | 
			
		||||
	for (i = 0; i < 33; i++)
 | 
			
		||||
		writel(coefs[i],
 | 
			
		||||
		       priv->io_base + _REG(VPP_SCALE_COEF));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* OSD csc defines */
 | 
			
		||||
 | 
			
		||||
enum viu_matrix_sel_e {
 | 
			
		||||
	VIU_MATRIX_OSD_EOTF = 0,
 | 
			
		||||
	VIU_MATRIX_OSD,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum viu_lut_sel_e {
 | 
			
		||||
	VIU_LUT_OSD_EOTF = 0,
 | 
			
		||||
	VIU_LUT_OSD_OETF,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
 | 
			
		||||
#define MATRIX_5X3_COEF_SIZE 24
 | 
			
		||||
 | 
			
		||||
#define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2))
 | 
			
		||||
#define EOTF_COEFF_SIZE 10
 | 
			
		||||
#define EOTF_COEFF_RIGHTSHIFT 1
 | 
			
		||||
 | 
			
		||||
static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
 | 
			
		||||
	0, 0, 0, /* pre offset */
 | 
			
		||||
	COEFF_NORM(0.181873),	COEFF_NORM(0.611831),	COEFF_NORM(0.061765),
 | 
			
		||||
	COEFF_NORM(-0.100251),	COEFF_NORM(-0.337249),	COEFF_NORM(0.437500),
 | 
			
		||||
	COEFF_NORM(0.437500),	COEFF_NORM(-0.397384),	COEFF_NORM(-0.040116),
 | 
			
		||||
	0, 0, 0, /* 10'/11'/12' */
 | 
			
		||||
	0, 0, 0, /* 20'/21'/22' */
 | 
			
		||||
	64, 512, 512, /* offset */
 | 
			
		||||
	0, 0, 0 /* mode, right_shift, clip_en */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*  eotf matrix: bypass */
 | 
			
		||||
static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
 | 
			
		||||
	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),
 | 
			
		||||
	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),
 | 
			
		||||
	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),
 | 
			
		||||
	EOTF_COEFF_RIGHTSHIFT /* right shift */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void meson_viu_set_osd_matrix(struct meson_vpu_priv *priv,
 | 
			
		||||
				     enum viu_matrix_sel_e m_select,
 | 
			
		||||
				     int *m, bool csc_on)
 | 
			
		||||
{
 | 
			
		||||
	if (m_select == VIU_MATRIX_OSD) {
 | 
			
		||||
		/* osd matrix, VIU_MATRIX_0 */
 | 
			
		||||
		writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
 | 
			
		||||
		       priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
 | 
			
		||||
		writel(m[2] & 0xfff,
 | 
			
		||||
		       priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
 | 
			
		||||
		writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
 | 
			
		||||
		       priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
 | 
			
		||||
		writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
 | 
			
		||||
		       priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
 | 
			
		||||
		writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
 | 
			
		||||
		       priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
 | 
			
		||||
		writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
 | 
			
		||||
		       priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
 | 
			
		||||
 | 
			
		||||
		if (m[21]) {
 | 
			
		||||
			writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
 | 
			
		||||
			       priv->io_base +
 | 
			
		||||
					_REG(VIU_OSD1_MATRIX_COEF22_30));
 | 
			
		||||
			writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
 | 
			
		||||
			       priv->io_base +
 | 
			
		||||
					_REG(VIU_OSD1_MATRIX_COEF31_32));
 | 
			
		||||
			writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
 | 
			
		||||
			       priv->io_base +
 | 
			
		||||
					_REG(VIU_OSD1_MATRIX_COEF40_41));
 | 
			
		||||
			writel(m[17] & 0x1fff, priv->io_base +
 | 
			
		||||
			       _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
 | 
			
		||||
		} else {
 | 
			
		||||
			writel((m[11] & 0x1fff) << 16, priv->io_base +
 | 
			
		||||
			       _REG(VIU_OSD1_MATRIX_COEF22_30));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
 | 
			
		||||
		       priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
 | 
			
		||||
		writel(m[20] & 0xfff,
 | 
			
		||||
		       priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
 | 
			
		||||
 | 
			
		||||
		writel_bits(3 << 30, m[21] << 30,
 | 
			
		||||
			    priv->io_base +
 | 
			
		||||
			    _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
 | 
			
		||||
		writel_bits(7 << 16, m[22] << 16,
 | 
			
		||||
			    priv->io_base +
 | 
			
		||||
			    _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
 | 
			
		||||
 | 
			
		||||
		/* 23 reserved for clipping control */
 | 
			
		||||
		writel_bits(BIT(0), csc_on ? BIT(0) : 0,
 | 
			
		||||
			    priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
 | 
			
		||||
		writel_bits(BIT(1), 0,
 | 
			
		||||
			    priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
 | 
			
		||||
	} else if (m_select == VIU_MATRIX_OSD_EOTF) {
 | 
			
		||||
		int i;
 | 
			
		||||
 | 
			
		||||
		/* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
 | 
			
		||||
		for (i = 0; i < 5; i++)
 | 
			
		||||
			writel(((m[i * 2] & 0x1fff) << 16) |
 | 
			
		||||
				(m[i * 2 + 1] & 0x1fff), priv->io_base +
 | 
			
		||||
				_REG(VIU_OSD1_EOTF_CTL + i + 1));
 | 
			
		||||
 | 
			
		||||
		writel_bits(BIT(30), csc_on ? BIT(30) : 0,
 | 
			
		||||
			    priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
 | 
			
		||||
		writel_bits(BIT(31), csc_on ? BIT(31) : 0,
 | 
			
		||||
			    priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define OSD_EOTF_LUT_SIZE 33
 | 
			
		||||
#define OSD_OETF_LUT_SIZE 41
 | 
			
		||||
 | 
			
		||||
static void meson_viu_set_osd_lut(struct meson_vpu_priv *priv,
 | 
			
		||||
				  enum viu_lut_sel_e lut_sel,
 | 
			
		||||
				  unsigned int *r_map, unsigned int *g_map,
 | 
			
		||||
				  unsigned int *b_map,
 | 
			
		||||
				  bool csc_on)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int addr_port;
 | 
			
		||||
	unsigned int data_port;
 | 
			
		||||
	unsigned int ctrl_port;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (lut_sel == VIU_LUT_OSD_EOTF) {
 | 
			
		||||
		addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
 | 
			
		||||
		data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
 | 
			
		||||
		ctrl_port = VIU_OSD1_EOTF_CTL;
 | 
			
		||||
	} else if (lut_sel == VIU_LUT_OSD_OETF) {
 | 
			
		||||
		addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
 | 
			
		||||
		data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
 | 
			
		||||
		ctrl_port = VIU_OSD1_OETF_CTL;
 | 
			
		||||
	} else {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lut_sel == VIU_LUT_OSD_OETF) {
 | 
			
		||||
		writel(0, priv->io_base + _REG(addr_port));
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 20; i++)
 | 
			
		||||
			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
 | 
			
		||||
			       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
 | 
			
		||||
		       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 20; i++)
 | 
			
		||||
			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
 | 
			
		||||
			       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 20; i++)
 | 
			
		||||
			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
 | 
			
		||||
			       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		writel(b_map[OSD_OETF_LUT_SIZE - 1],
 | 
			
		||||
		       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		if (csc_on)
 | 
			
		||||
			writel_bits(0x7 << 29, 7 << 29,
 | 
			
		||||
				    priv->io_base + _REG(ctrl_port));
 | 
			
		||||
		else
 | 
			
		||||
			writel_bits(0x7 << 29, 0,
 | 
			
		||||
				    priv->io_base + _REG(ctrl_port));
 | 
			
		||||
	} else if (lut_sel == VIU_LUT_OSD_EOTF) {
 | 
			
		||||
		writel(0, priv->io_base + _REG(addr_port));
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 20; i++)
 | 
			
		||||
			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
 | 
			
		||||
			       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
 | 
			
		||||
		       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 20; i++)
 | 
			
		||||
			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
 | 
			
		||||
			       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 20; i++)
 | 
			
		||||
			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
 | 
			
		||||
			       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		writel(b_map[OSD_EOTF_LUT_SIZE - 1],
 | 
			
		||||
		       priv->io_base + _REG(data_port));
 | 
			
		||||
 | 
			
		||||
		if (csc_on)
 | 
			
		||||
			writel_bits(7 << 27, 7 << 27,
 | 
			
		||||
				    priv->io_base + _REG(ctrl_port));
 | 
			
		||||
		else
 | 
			
		||||
			writel_bits(7 << 27, 0,
 | 
			
		||||
				    priv->io_base + _REG(ctrl_port));
 | 
			
		||||
 | 
			
		||||
		writel_bits(BIT(31), BIT(31),
 | 
			
		||||
			    priv->io_base + _REG(ctrl_port));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* eotf lut: linear */
 | 
			
		||||
static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
 | 
			
		||||
	0x0000,	0x0200,	0x0400, 0x0600,
 | 
			
		||||
	0x0800, 0x0a00, 0x0c00, 0x0e00,
 | 
			
		||||
	0x1000, 0x1200, 0x1400, 0x1600,
 | 
			
		||||
	0x1800, 0x1a00, 0x1c00, 0x1e00,
 | 
			
		||||
	0x2000, 0x2200, 0x2400, 0x2600,
 | 
			
		||||
	0x2800, 0x2a00, 0x2c00, 0x2e00,
 | 
			
		||||
	0x3000, 0x3200, 0x3400, 0x3600,
 | 
			
		||||
	0x3800, 0x3a00, 0x3c00, 0x3e00,
 | 
			
		||||
	0x4000
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* osd oetf lut: linear */
 | 
			
		||||
static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
 | 
			
		||||
	0, 0, 0, 0,
 | 
			
		||||
	0, 32, 64, 96,
 | 
			
		||||
	128, 160, 196, 224,
 | 
			
		||||
	256, 288, 320, 352,
 | 
			
		||||
	384, 416, 448, 480,
 | 
			
		||||
	512, 544, 576, 608,
 | 
			
		||||
	640, 672, 704, 736,
 | 
			
		||||
	768, 800, 832, 864,
 | 
			
		||||
	896, 928, 960, 992,
 | 
			
		||||
	1023, 1023, 1023, 1023,
 | 
			
		||||
	1023
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void meson_viu_load_matrix(struct meson_vpu_priv *priv)
 | 
			
		||||
{
 | 
			
		||||
	/* eotf lut bypass */
 | 
			
		||||
	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
 | 
			
		||||
			      eotf_33_linear_mapping, /* R */
 | 
			
		||||
			      eotf_33_linear_mapping, /* G */
 | 
			
		||||
			      eotf_33_linear_mapping, /* B */
 | 
			
		||||
			      false);
 | 
			
		||||
 | 
			
		||||
	/* eotf matrix bypass */
 | 
			
		||||
	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
 | 
			
		||||
				 eotf_bypass_coeff,
 | 
			
		||||
				 false);
 | 
			
		||||
 | 
			
		||||
	/* oetf lut bypass */
 | 
			
		||||
	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
 | 
			
		||||
			      oetf_41_linear_mapping, /* R */
 | 
			
		||||
			      oetf_41_linear_mapping, /* G */
 | 
			
		||||
			      oetf_41_linear_mapping, /* B */
 | 
			
		||||
			      false);
 | 
			
		||||
 | 
			
		||||
	/* osd matrix RGB709 to YUV709 limit */
 | 
			
		||||
	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
 | 
			
		||||
				 RGB709_to_YUV709l_coeff,
 | 
			
		||||
				 true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void meson_vpu_init(struct udevice *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct meson_vpu_priv *priv = dev_get_priv(dev);
 | 
			
		||||
	u32 reg;
 | 
			
		||||
 | 
			
		||||
	/* vpu initialization */
 | 
			
		||||
	writel(0x210000, priv->io_base + _REG(VPU_RDARB_MODE_L1C1));
 | 
			
		||||
	writel(0x10000, priv->io_base + _REG(VPU_RDARB_MODE_L1C2));
 | 
			
		||||
	writel(0x900000, priv->io_base + _REG(VPU_RDARB_MODE_L2C1));
 | 
			
		||||
	writel(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
 | 
			
		||||
 | 
			
		||||
	/* Disable CVBS VDAC */
 | 
			
		||||
	hhi_write(HHI_VDAC_CNTL0, 0);
 | 
			
		||||
	hhi_write(HHI_VDAC_CNTL1, 8);
 | 
			
		||||
 | 
			
		||||
	/* Power Down Dacs */
 | 
			
		||||
	writel(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
 | 
			
		||||
 | 
			
		||||
	/* Disable HDMI PHY */
 | 
			
		||||
	hhi_write(HHI_HDMI_PHY_CNTL0, 0);
 | 
			
		||||
 | 
			
		||||
	/* Disable HDMI */
 | 
			
		||||
	writel_bits(0x3, 0, priv->io_base + _REG(VPU_HDMI_SETTING));
 | 
			
		||||
 | 
			
		||||
	/* Disable all encoders */
 | 
			
		||||
	writel(0, priv->io_base + _REG(ENCI_VIDEO_EN));
 | 
			
		||||
	writel(0, priv->io_base + _REG(ENCP_VIDEO_EN));
 | 
			
		||||
	writel(0, priv->io_base + _REG(ENCL_VIDEO_EN));
 | 
			
		||||
 | 
			
		||||
	/* Disable VSync IRQ */
 | 
			
		||||
	writel(0, priv->io_base + _REG(VENC_INTCTRL));
 | 
			
		||||
 | 
			
		||||
	/* set dummy data default YUV black */
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
 | 
			
		||||
		writel(0x108080, priv->io_base + _REG(VPP_DUMMY_DATA1));
 | 
			
		||||
	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) {
 | 
			
		||||
		writel_bits(0xff << 16, 0xff << 16,
 | 
			
		||||
			    priv->io_base + _REG(VIU_MISC_CTRL1));
 | 
			
		||||
		writel(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL));
 | 
			
		||||
		writel(0x1020080,
 | 
			
		||||
		       priv->io_base + _REG(VPP_DUMMY_DATA1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Initialize vpu fifo control registers */
 | 
			
		||||
	writel(readl(priv->io_base + _REG(VPP_OFIFO_SIZE)) |
 | 
			
		||||
			0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE));
 | 
			
		||||
	writel(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES));
 | 
			
		||||
 | 
			
		||||
	/* Turn off preblend */
 | 
			
		||||
	writel_bits(VPP_PREBLEND_ENABLE, 0,
 | 
			
		||||
		    priv->io_base + _REG(VPP_MISC));
 | 
			
		||||
 | 
			
		||||
	/* Turn off POSTBLEND */
 | 
			
		||||
	writel_bits(VPP_POSTBLEND_ENABLE, 0,
 | 
			
		||||
		    priv->io_base + _REG(VPP_MISC));
 | 
			
		||||
 | 
			
		||||
	/* Force all planes off */
 | 
			
		||||
	writel_bits(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND |
 | 
			
		||||
		    VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND |
 | 
			
		||||
		    VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0,
 | 
			
		||||
		    priv->io_base + _REG(VPP_MISC));
 | 
			
		||||
 | 
			
		||||
	/* Setup default VD settings */
 | 
			
		||||
	writel(4096,
 | 
			
		||||
	       priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END));
 | 
			
		||||
	writel(4096,
 | 
			
		||||
	       priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
 | 
			
		||||
 | 
			
		||||
	/* Disable Scalers */
 | 
			
		||||
	writel(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
 | 
			
		||||
	writel(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
 | 
			
		||||
	writel(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
 | 
			
		||||
	writel(4 | (4 << 8) | BIT(15),
 | 
			
		||||
	       priv->io_base + _REG(VPP_SC_MISC));
 | 
			
		||||
 | 
			
		||||
	/* Write in the proper filter coefficients. */
 | 
			
		||||
	meson_vpp_write_scaling_filter_coefs(priv,
 | 
			
		||||
				vpp_filter_coefs_4point_bspline, false);
 | 
			
		||||
	meson_vpp_write_scaling_filter_coefs(priv,
 | 
			
		||||
				vpp_filter_coefs_4point_bspline, true);
 | 
			
		||||
 | 
			
		||||
	/* Write the VD proper filter coefficients. */
 | 
			
		||||
	meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
 | 
			
		||||
						false);
 | 
			
		||||
	meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
 | 
			
		||||
						true);
 | 
			
		||||
 | 
			
		||||
	/* Disable OSDs */
 | 
			
		||||
	writel_bits(BIT(0) | BIT(21), 0,
 | 
			
		||||
		    priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
 | 
			
		||||
	writel_bits(BIT(0) | BIT(21), 0,
 | 
			
		||||
		    priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
 | 
			
		||||
 | 
			
		||||
	/* On GXL/GXM, Use the 10bit HDR conversion matrix */
 | 
			
		||||
	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
 | 
			
		||||
	    meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
 | 
			
		||||
		meson_viu_load_matrix(priv);
 | 
			
		||||
 | 
			
		||||
	/* Initialize OSD1 fifo control register */
 | 
			
		||||
	reg = BIT(0) |	/* Urgent DDR request priority */
 | 
			
		||||
	      (4 << 5) | /* hold_fifo_lines */
 | 
			
		||||
	      (3 << 10) | /* burst length 64 */
 | 
			
		||||
	      (32 << 12) | /* fifo_depth_val: 32*8=256 */
 | 
			
		||||
	      (2 << 22) | /* 4 words in 1 burst */
 | 
			
		||||
	      (2 << 24);
 | 
			
		||||
	writel(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
 | 
			
		||||
	writel(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
 | 
			
		||||
 | 
			
		||||
	/* Set OSD alpha replace value */
 | 
			
		||||
	writel_bits(0xff << OSD_REPLACE_SHIFT,
 | 
			
		||||
		    0xff << OSD_REPLACE_SHIFT,
 | 
			
		||||
		    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
 | 
			
		||||
	writel_bits(0xff << OSD_REPLACE_SHIFT,
 | 
			
		||||
		    0xff << OSD_REPLACE_SHIFT,
 | 
			
		||||
		    priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								drivers/video/meson/simplefb_common.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								drivers/video/meson/simplefb_common.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0+
 | 
			
		||||
/*
 | 
			
		||||
 * Common code for Amlogic 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>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <fdtdec.h>
 | 
			
		||||
 | 
			
		||||
int meson_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,
 | 
			
		||||
					       "amlogic,simple-framebuffer");
 | 
			
		||||
	while (offset >= 0) {
 | 
			
		||||
		ret = fdt_stringlist_search(blob, offset, "amlogic,pipeline",
 | 
			
		||||
					    pipeline);
 | 
			
		||||
		if (ret == 0)
 | 
			
		||||
			break;
 | 
			
		||||
		offset = fdt_node_offset_by_compatible(blob, offset,
 | 
			
		||||
						"amlogic,simple-framebuffer");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return offset;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								drivers/video/meson/simplefb_common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								drivers/video/meson/simplefb_common.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0+ */
 | 
			
		||||
/*
 | 
			
		||||
 * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __SIMPLEFB_COMMON_H
 | 
			
		||||
#define __SIMPLEFB_COMMON_H
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meson_simplefb_fdt_match() - match a meson simplefb node
 | 
			
		||||
 *
 | 
			
		||||
 * Match a meson 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 meson_simplefb_fdt_match(void *blob, const char *pipeline);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -16,6 +16,26 @@
 | 
			
		||||
#define GICC_BASE			0xc4302000
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* For splashscreen */
 | 
			
		||||
#ifdef CONFIG_DM_VIDEO
 | 
			
		||||
#define CONFIG_VIDEO_BMP_RLE8
 | 
			
		||||
#define CONFIG_BMP_16BPP
 | 
			
		||||
#define CONFIG_BMP_24BPP
 | 
			
		||||
#define CONFIG_BMP_32BPP
 | 
			
		||||
#define CONFIG_SPLASH_SCREEN
 | 
			
		||||
#define CONFIG_SPLASH_SCREEN_ALIGN
 | 
			
		||||
#define STDOUT_CFG "vidconsole,serial"
 | 
			
		||||
#else
 | 
			
		||||
#define STDOUT_CFG "serial"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_USB_KEYBOARD
 | 
			
		||||
#define STDIN_CFG "usbkbd,serial"
 | 
			
		||||
#define CONFIG_PREBOOT "usb start"
 | 
			
		||||
#else
 | 
			
		||||
#define STDIN_CFG "serial"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define CONFIG_CPU_ARMV8
 | 
			
		||||
#define CONFIG_REMAKE_ELF
 | 
			
		||||
#define CONFIG_ENV_SIZE			0x2000
 | 
			
		||||
@ -59,6 +79,9 @@
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_EXTRA_ENV_SETTINGS
 | 
			
		||||
#define CONFIG_EXTRA_ENV_SETTINGS \
 | 
			
		||||
	"stdin=" STDIN_CFG "\0" \
 | 
			
		||||
	"stdout=" STDOUT_CFG "\0" \
 | 
			
		||||
	"stderr=" STDOUT_CFG "\0" \
 | 
			
		||||
	"fdt_addr_r=0x08008000\0" \
 | 
			
		||||
	"scriptaddr=0x08000000\0" \
 | 
			
		||||
	"kernel_addr_r=0x08080000\0" \
 | 
			
		||||
 | 
			
		||||
@ -174,6 +174,34 @@
 | 
			
		||||
#define HDMI_MC_LOCKONCLOCK                     0x4006
 | 
			
		||||
#define HDMI_MC_HEACPHY_RST                     0x4007
 | 
			
		||||
 | 
			
		||||
/* Color Space  Converter Registers */
 | 
			
		||||
#define HDMI_CSC_CFG                            0x4100
 | 
			
		||||
#define HDMI_CSC_SCALE                          0x4101
 | 
			
		||||
#define HDMI_CSC_COEF_A1_MSB                    0x4102
 | 
			
		||||
#define HDMI_CSC_COEF_A1_LSB                    0x4103
 | 
			
		||||
#define HDMI_CSC_COEF_A2_MSB                    0x4104
 | 
			
		||||
#define HDMI_CSC_COEF_A2_LSB                    0x4105
 | 
			
		||||
#define HDMI_CSC_COEF_A3_MSB                    0x4106
 | 
			
		||||
#define HDMI_CSC_COEF_A3_LSB                    0x4107
 | 
			
		||||
#define HDMI_CSC_COEF_A4_MSB                    0x4108
 | 
			
		||||
#define HDMI_CSC_COEF_A4_LSB                    0x4109
 | 
			
		||||
#define HDMI_CSC_COEF_B1_MSB                    0x410A
 | 
			
		||||
#define HDMI_CSC_COEF_B1_LSB                    0x410B
 | 
			
		||||
#define HDMI_CSC_COEF_B2_MSB                    0x410C
 | 
			
		||||
#define HDMI_CSC_COEF_B2_LSB                    0x410D
 | 
			
		||||
#define HDMI_CSC_COEF_B3_MSB                    0x410E
 | 
			
		||||
#define HDMI_CSC_COEF_B3_LSB                    0x410F
 | 
			
		||||
#define HDMI_CSC_COEF_B4_MSB                    0x4110
 | 
			
		||||
#define HDMI_CSC_COEF_B4_LSB                    0x4111
 | 
			
		||||
#define HDMI_CSC_COEF_C1_MSB                    0x4112
 | 
			
		||||
#define HDMI_CSC_COEF_C1_LSB                    0x4113
 | 
			
		||||
#define HDMI_CSC_COEF_C2_MSB                    0x4114
 | 
			
		||||
#define HDMI_CSC_COEF_C2_LSB                    0x4115
 | 
			
		||||
#define HDMI_CSC_COEF_C3_MSB                    0x4116
 | 
			
		||||
#define HDMI_CSC_COEF_C3_LSB                    0x4117
 | 
			
		||||
#define HDMI_CSC_COEF_C4_MSB                    0x4118
 | 
			
		||||
#define HDMI_CSC_COEF_C4_LSB                    0x4119
 | 
			
		||||
 | 
			
		||||
/* I2C Master Registers (E-DDC) */
 | 
			
		||||
#define HDMI_I2CM_SLAVE                         0x7E00
 | 
			
		||||
#define HDMI_I2CM_ADDRESS                       0x7E01
 | 
			
		||||
@ -416,7 +444,11 @@ enum {
 | 
			
		||||
	HDMI_AUD_INPUTCLKFS_128 = 0x0,
 | 
			
		||||
 | 
			
		||||
	/* mc_clkdis field values */
 | 
			
		||||
	HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
 | 
			
		||||
	HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
 | 
			
		||||
	HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
 | 
			
		||||
	HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
 | 
			
		||||
	HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
 | 
			
		||||
	HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
 | 
			
		||||
	HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
 | 
			
		||||
 | 
			
		||||
@ -444,6 +476,27 @@ enum {
 | 
			
		||||
	HDMI_I2CM_DIV_FAST_MODE = 0x8,
 | 
			
		||||
	HDMI_I2CM_DIV_STD_MODE = 0x0,
 | 
			
		||||
	HDMI_I2CM_SOFTRSTZ_MASK = 0x1,
 | 
			
		||||
 | 
			
		||||
	/* CSC_CFG field values */
 | 
			
		||||
	HDMI_CSC_CFG_INTMODE_MASK = 0x30,
 | 
			
		||||
	HDMI_CSC_CFG_INTMODE_OFFSET = 4,
 | 
			
		||||
	HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
 | 
			
		||||
	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
 | 
			
		||||
	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
 | 
			
		||||
	HDMI_CSC_CFG_DECMODE_MASK = 0x3,
 | 
			
		||||
	HDMI_CSC_CFG_DECMODE_OFFSET = 0,
 | 
			
		||||
	HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
 | 
			
		||||
	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
 | 
			
		||||
	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
 | 
			
		||||
	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
 | 
			
		||||
 | 
			
		||||
	/* CSC_SCALE field values */
 | 
			
		||||
	HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
 | 
			
		||||
	HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
 | 
			
		||||
	HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
 | 
			
		||||
	HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
 | 
			
		||||
	HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
 | 
			
		||||
	HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct hdmi_mpll_config {
 | 
			
		||||
@ -463,6 +516,24 @@ struct hdmi_phy_config {
 | 
			
		||||
	u32 vlev_ctr;   /* voltage level control */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct hdmi_vmode {
 | 
			
		||||
	bool mdataenablepolarity;
 | 
			
		||||
 | 
			
		||||
	unsigned int mpixelclock;
 | 
			
		||||
	unsigned int mpixelrepetitioninput;
 | 
			
		||||
	unsigned int mpixelrepetitionoutput;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct hdmi_data_info {
 | 
			
		||||
	unsigned int enc_in_bus_format;
 | 
			
		||||
	unsigned int enc_out_bus_format;
 | 
			
		||||
	unsigned int enc_in_encoding;
 | 
			
		||||
	unsigned int enc_out_encoding;
 | 
			
		||||
	unsigned int pix_repet_factor;
 | 
			
		||||
	unsigned int hdcp_enable;
 | 
			
		||||
	struct hdmi_vmode video_mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dw_hdmi {
 | 
			
		||||
	ulong ioaddr;
 | 
			
		||||
	const struct hdmi_mpll_config *mpll_cfg;
 | 
			
		||||
@ -470,8 +541,11 @@ struct dw_hdmi {
 | 
			
		||||
	u8 i2c_clk_high;
 | 
			
		||||
	u8 i2c_clk_low;
 | 
			
		||||
	u8 reg_io_width;
 | 
			
		||||
	struct hdmi_data_info hdmi_data;
 | 
			
		||||
 | 
			
		||||
	int (*phy_set)(struct dw_hdmi *hdmi, uint mpixelclock);
 | 
			
		||||
	void (*write_reg)(struct dw_hdmi *hdmi, u8 val, int offset);
 | 
			
		||||
	u8 (*read_reg)(struct dw_hdmi *hdmi, int offset);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										156
									
								
								include/media_bus_format.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								include/media_bus_format.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,156 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 | 
			
		||||
/*
 | 
			
		||||
 * Media Bus API header
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License version 2 as
 | 
			
		||||
 * published by the Free Software Foundation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LINUX_MEDIA_BUS_FORMAT_H
 | 
			
		||||
#define __LINUX_MEDIA_BUS_FORMAT_H
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These bus formats uniquely identify data formats on the data bus. Format 0
 | 
			
		||||
 * is reserved, MEDIA_BUS_FMT_FIXED shall be used by host-client pairs, where
 | 
			
		||||
 * the data format is fixed. Additionally, "2X8" means that one pixel is
 | 
			
		||||
 * transferred in two 8-bit samples, "BE" or "LE" specify in which order those
 | 
			
		||||
 * samples are transferred over the bus: "LE" means that the least significant
 | 
			
		||||
 * bits are transferred first, "BE" means that the most significant bits are
 | 
			
		||||
 * transferred first, and "PADHI" and "PADLO" define which bits - low or high,
 | 
			
		||||
 * in the incomplete high byte, are filled with padding bits.
 | 
			
		||||
 *
 | 
			
		||||
 * The bus formats are grouped by type, bus_width, bits per component, samples
 | 
			
		||||
 * per pixel and order of subsamples. Numerical values are sorted using generic
 | 
			
		||||
 * numerical sort order (8 thus comes before 10).
 | 
			
		||||
 *
 | 
			
		||||
 * As their value can't change when a new bus format is inserted in the
 | 
			
		||||
 * enumeration, the bus formats are explicitly given a numerical value. The next
 | 
			
		||||
 * free values for each category are listed below, update them when inserting
 | 
			
		||||
 * new pixel codes.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define MEDIA_BUS_FMT_FIXED			0x0001
 | 
			
		||||
 | 
			
		||||
/* RGB - next is	0x101b */
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB444_1X12		0x1016
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE	0x1001
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE	0x1002
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE	0x1003
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE	0x1004
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB565_1X16		0x1017
 | 
			
		||||
#define MEDIA_BUS_FMT_BGR565_2X8_BE		0x1005
 | 
			
		||||
#define MEDIA_BUS_FMT_BGR565_2X8_LE		0x1006
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB565_2X8_BE		0x1007
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB565_2X8_LE		0x1008
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB666_1X18		0x1009
 | 
			
		||||
#define MEDIA_BUS_FMT_RBG888_1X24		0x100e
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB666_1X24_CPADHI	0x1015
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG		0x1010
 | 
			
		||||
#define MEDIA_BUS_FMT_BGR888_1X24		0x1013
 | 
			
		||||
#define MEDIA_BUS_FMT_GBR888_1X24		0x1014
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB888_1X24		0x100a
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB888_2X12_BE		0x100b
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB888_2X12_LE		0x100c
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB888_1X7X4_SPWG		0x1011
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA	0x1012
 | 
			
		||||
#define MEDIA_BUS_FMT_ARGB8888_1X32		0x100d
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB888_1X32_PADHI		0x100f
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB101010_1X30		0x1018
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB121212_1X36		0x1019
 | 
			
		||||
#define MEDIA_BUS_FMT_RGB161616_1X48		0x101a
 | 
			
		||||
 | 
			
		||||
/* YUV (including grey) - next is	0x202d */
 | 
			
		||||
#define MEDIA_BUS_FMT_Y8_1X8			0x2001
 | 
			
		||||
#define MEDIA_BUS_FMT_UV8_1X8			0x2015
 | 
			
		||||
#define MEDIA_BUS_FMT_UYVY8_1_5X8		0x2002
 | 
			
		||||
#define MEDIA_BUS_FMT_VYUY8_1_5X8		0x2003
 | 
			
		||||
#define MEDIA_BUS_FMT_YUYV8_1_5X8		0x2004
 | 
			
		||||
#define MEDIA_BUS_FMT_YVYU8_1_5X8		0x2005
 | 
			
		||||
#define MEDIA_BUS_FMT_UYVY8_2X8			0x2006
 | 
			
		||||
#define MEDIA_BUS_FMT_VYUY8_2X8			0x2007
 | 
			
		||||
#define MEDIA_BUS_FMT_YUYV8_2X8			0x2008
 | 
			
		||||
#define MEDIA_BUS_FMT_YVYU8_2X8			0x2009
 | 
			
		||||
#define MEDIA_BUS_FMT_Y10_1X10			0x200a
 | 
			
		||||
#define MEDIA_BUS_FMT_Y10_2X8_PADHI_LE		0x202c
 | 
			
		||||
#define MEDIA_BUS_FMT_UYVY10_2X10		0x2018
 | 
			
		||||
#define MEDIA_BUS_FMT_VYUY10_2X10		0x2019
 | 
			
		||||
#define MEDIA_BUS_FMT_YUYV10_2X10		0x200b
 | 
			
		||||
#define MEDIA_BUS_FMT_YVYU10_2X10		0x200c
 | 
			
		||||
#define MEDIA_BUS_FMT_Y12_1X12			0x2013
 | 
			
		||||
#define MEDIA_BUS_FMT_UYVY12_2X12		0x201c
 | 
			
		||||
#define MEDIA_BUS_FMT_VYUY12_2X12		0x201d
 | 
			
		||||
#define MEDIA_BUS_FMT_YUYV12_2X12		0x201e
 | 
			
		||||
#define MEDIA_BUS_FMT_YVYU12_2X12		0x201f
 | 
			
		||||
#define MEDIA_BUS_FMT_UYVY8_1X16		0x200f
 | 
			
		||||
#define MEDIA_BUS_FMT_VYUY8_1X16		0x2010
 | 
			
		||||
#define MEDIA_BUS_FMT_YUYV8_1X16		0x2011
 | 
			
		||||
#define MEDIA_BUS_FMT_YVYU8_1X16		0x2012
 | 
			
		||||
#define MEDIA_BUS_FMT_YDYUYDYV8_1X16		0x2014
 | 
			
		||||
#define MEDIA_BUS_FMT_UYVY10_1X20		0x201a
 | 
			
		||||
#define MEDIA_BUS_FMT_VYUY10_1X20		0x201b
 | 
			
		||||
#define MEDIA_BUS_FMT_YUYV10_1X20		0x200d
 | 
			
		||||
#define MEDIA_BUS_FMT_YVYU10_1X20		0x200e
 | 
			
		||||
#define MEDIA_BUS_FMT_VUY8_1X24			0x2024
 | 
			
		||||
#define MEDIA_BUS_FMT_YUV8_1X24			0x2025
 | 
			
		||||
#define MEDIA_BUS_FMT_UYYVYY8_0_5X24		0x2026
 | 
			
		||||
#define MEDIA_BUS_FMT_UYVY12_1X24		0x2020
 | 
			
		||||
#define MEDIA_BUS_FMT_VYUY12_1X24		0x2021
 | 
			
		||||
#define MEDIA_BUS_FMT_YUYV12_1X24		0x2022
 | 
			
		||||
#define MEDIA_BUS_FMT_YVYU12_1X24		0x2023
 | 
			
		||||
#define MEDIA_BUS_FMT_YUV10_1X30		0x2016
 | 
			
		||||
#define MEDIA_BUS_FMT_UYYVYY10_0_5X30		0x2027
 | 
			
		||||
#define MEDIA_BUS_FMT_AYUV8_1X32		0x2017
 | 
			
		||||
#define MEDIA_BUS_FMT_UYYVYY12_0_5X36		0x2028
 | 
			
		||||
#define MEDIA_BUS_FMT_YUV12_1X36		0x2029
 | 
			
		||||
#define MEDIA_BUS_FMT_YUV16_1X48		0x202a
 | 
			
		||||
#define MEDIA_BUS_FMT_UYYVYY16_0_5X48		0x202b
 | 
			
		||||
 | 
			
		||||
/* Bayer - next is	0x3021 */
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR8_1X8		0x3001
 | 
			
		||||
#define MEDIA_BUS_FMT_SGBRG8_1X8		0x3013
 | 
			
		||||
#define MEDIA_BUS_FMT_SGRBG8_1X8		0x3002
 | 
			
		||||
#define MEDIA_BUS_FMT_SRGGB8_1X8		0x3014
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8		0x3015
 | 
			
		||||
#define MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8		0x3016
 | 
			
		||||
#define MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8		0x3017
 | 
			
		||||
#define MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8		0x3018
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8		0x300b
 | 
			
		||||
#define MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8		0x300c
 | 
			
		||||
#define MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8		0x3009
 | 
			
		||||
#define MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8		0x300d
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE	0x3003
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE	0x3004
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE	0x3005
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE	0x3006
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR10_1X10		0x3007
 | 
			
		||||
#define MEDIA_BUS_FMT_SGBRG10_1X10		0x300e
 | 
			
		||||
#define MEDIA_BUS_FMT_SGRBG10_1X10		0x300a
 | 
			
		||||
#define MEDIA_BUS_FMT_SRGGB10_1X10		0x300f
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR12_1X12		0x3008
 | 
			
		||||
#define MEDIA_BUS_FMT_SGBRG12_1X12		0x3010
 | 
			
		||||
#define MEDIA_BUS_FMT_SGRBG12_1X12		0x3011
 | 
			
		||||
#define MEDIA_BUS_FMT_SRGGB12_1X12		0x3012
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR14_1X14		0x3019
 | 
			
		||||
#define MEDIA_BUS_FMT_SGBRG14_1X14		0x301a
 | 
			
		||||
#define MEDIA_BUS_FMT_SGRBG14_1X14		0x301b
 | 
			
		||||
#define MEDIA_BUS_FMT_SRGGB14_1X14		0x301c
 | 
			
		||||
#define MEDIA_BUS_FMT_SBGGR16_1X16		0x301d
 | 
			
		||||
#define MEDIA_BUS_FMT_SGBRG16_1X16		0x301e
 | 
			
		||||
#define MEDIA_BUS_FMT_SGRBG16_1X16		0x301f
 | 
			
		||||
#define MEDIA_BUS_FMT_SRGGB16_1X16		0x3020
 | 
			
		||||
 | 
			
		||||
/* JPEG compressed formats - next is	0x4002 */
 | 
			
		||||
#define MEDIA_BUS_FMT_JPEG_1X8			0x4001
 | 
			
		||||
 | 
			
		||||
/* Vendor specific formats - next is	0x5002 */
 | 
			
		||||
 | 
			
		||||
/* S5C73M3 sensor specific interleaved UYVY and JPEG */
 | 
			
		||||
#define MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8		0x5001
 | 
			
		||||
 | 
			
		||||
/* HSV - next is	0x6002 */
 | 
			
		||||
#define MEDIA_BUS_FMT_AHSV8888_1X32		0x6001
 | 
			
		||||
 | 
			
		||||
#endif /* __LINUX_MEDIA_BUS_FORMAT_H */
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user