Robolightning Posted November 5 Posted November 5 Hello! I could find quite a bit of information about the analog video output for OrangePi Zero 2W on Armbian under Ubuntu. On Android TV-OUT works. Are there any plans to add this feature to Armbian? It is very critical for me. If no one plans to do this now, then I would be extremely grateful for advice from experts on how to port / modify existing drivers, perhaps take something from the AndroidTV 12 code, where the video output works? I am a developer, but I have not previously dealt with driver development for Linux, but if I understand in which direction to act, then using ChatGPT sooner or later I should be able to cope. I would be very grateful for any help! 0 Quote
robertoj Posted November 6 Posted November 6 We dont know any other linux that can output TV out from the h618 chip Orange pi zero with a current armbian OS, can output analog TV 0 Quote
Robolightning Posted November 6 Author Posted November 6 AndroidTV 12 can, isn't? Are you about OrangePi Zero, or Zero 2W, that can? 0 Quote
robertoj Posted November 8 Posted November 8 The orange pi zero with the latest armbian can output analog TV The other zeros (3, 2W) can't (with Linux) It would be great if new developers can find the android code and port it to Linux. 0 Quote
Robolightning Posted November 9 Author Posted November 9 Thanks. Android source code is presented on OrangePi official website. I'm trying to port driver last weeks, but it's not easy for me, I'm never work with drivers early. At this reason I would be really greatful any help from experts 0 Quote
robertoj Posted November 9 Posted November 9 Maybe you can use devmem2 so you can manipulate registers from a userspace application, like some legendary developers did in the past I also worked updating the patches needed to bring TV out to the orange pi zero with newer kernels. Maybe it can be a reference. https://github.com/robertojguerra/orangepi-zero-full-setup/blob/main/README2.md https://forum.armbian.com/topic/6582-orange-pi-zero-h2h3-tv-out-on-mainline-working/ https://linux-sunxi.org/images/2/24/H616_User_Manual_V1.0_cleaned.pdf 0 Quote
Nick A Posted November 9 Posted November 9 (edited) I have been looking at the code and there's been a lot of changes between H3/H5 and H616/H618 SOC's. H616/H618 now has a TVE_TOP register. H616/H618 uses the first DAC and moved the DAC MAP to TVE_TOP. https://linux-sunxi.org/images/2/24/H616_User_Manual_V1.0_cleaned.pdf Module Name Base Address TVE_TOP 0x06520000 TVE 0x06524000 Register Name Offset Description TVE_DAC_MAP 0x0020 TV Encoder DAC MAP Register TVE_DAC_STATUS 0x0024 TV Encoder DAC STAUTS Register TVE_DAC_CFG0 0x0028 TV Encoder DAC CFG0 Register TVE_DAC_CFG1 0x002C TV Encoder DAC CFG1 Register TVE_DAC_CFG2 0x0030 TV Encoder DAC CFG2 Register TVE_DAC_CFG3 0x0034 TV Encoder DAC CFG2 Register TVE_DAC_TEST 0x00F0 TV Encoder DAC TEST Register H3/H5 TV Encoder Enable Register use to handle the DAC mapping. If you look at the two pdf's you can see the changes. https://linux-sunxi.org/images/1/1e/Allwinner_A10_User_manual_V1.5.pdf Module Name Base Address TVE 0x01C0A000 Register Name Offset Description TVE_000_REG 0x0000 TV Encoder Enable Register We need to modify the kernel TVE driver. https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/sun4i/sun4i_tv.c #define SUN4I_TVE_TOP_DAC_MAP 0x020 #define SUN4I_TVE_TOP_EN_DAC_MAP_MASK GENMASK(6, 4) #define SUN4I_TVE_TOP_EN_DAC_MAP(dac, out) (((out) & 0xf) << (dac + 1) * 4) #define SUN4I_TVE_TOP_DAC_TEST 0x0F0 if (tv->quirks->hastvtop) { /* Enable and map the DAC to the output */ regmap_update_bits(tv->top_regs, SUN4I_TVE_TOP_DAC_MAP, SUN4I_TVE_TOP_EN_DAC_MAP_MASK, SUN4I_TVE_TOP_EN_DAC_MAP(0, 1) | SUN4I_TVE_TOP_EN_DAC_MAP(1, 2) | SUN4I_TVE_TOP_EN_DAC_MAP(2, 3) | SUN4I_TVE_TOP_EN_DAC_MAP(3, 4)); } else { /* Enable and map the DAC to the output */ regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG, SUN4I_TVE_EN_DAC_MAP_MASK, SUN4I_TVE_EN_DAC_MAP(0, 1) | SUN4I_TVE_EN_DAC_MAP(1, 2) | SUN4I_TVE_EN_DAC_MAP(2, 3) | SUN4I_TVE_EN_DAC_MAP(3, 4)); } I still need to modify this part... /* Configure the DAC for a composite output */ regmap_write(tv->regs, SUN4I_TVE_DAC0_REG, SUN4I_TVE_DAC0_DAC_EN(0) | (tv_mode->dac3_en ? SUN4I_TVE_DAC0_DAC_EN(3) : 0) | SUN4I_TVE_DAC0_INTERNAL_DAC_37_5_OHMS | SUN4I_TVE_DAC0_CHROMA_0_75 | SUN4I_TVE_DAC0_LUMA_0_4 | SUN4I_TVE_DAC0_CLOCK_INVERT | (tv_mode->dac_bit25_en ? BIT(25) : 0) | BIT(30)); To access the TVE_TOP DAC MAP Register we need to first enable the TVE_TOP clocks. (in function sun4i_tv_bind()) static const struct regmap_config sun4i_tv_top_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .max_register = SUN4I_TVE_TOP_DAC_TEST, .name = "tv-top", }; /* tve top */ if (tv->quirks->hastvtop) { top_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(top_regs)) { dev_err(dev, "Couldn't map the TV TOP registers\n"); return PTR_ERR(top_regs); } tv->top_regs = devm_regmap_init_mmio(dev, top_regs, &sun4i_tv_top_regmap_config); if (IS_ERR(tv->top_regs)) { dev_err(dev, "Couldn't create the TV TOP regmap\n"); return PTR_ERR(tv->top_regs); } tv->top_reset = devm_reset_control_get(dev, "rst_bus_tve_top"); if (IS_ERR(tv->top_reset)) { dev_err(dev, "Couldn't get our reset line\n"); return PTR_ERR(tv->top_reset); } ret = reset_control_deassert(tv->top_reset); if (ret) { dev_err(dev, "Couldn't deassert our reset line\n"); return ret; } tv->top_clk = devm_clk_get(dev, "clk_bus_tve_top"); if (IS_ERR(tv->top_clk)) { dev_err(dev, "Couldn't get the TV TOP clock\n"); ret = PTR_ERR(tv->top_clk); goto err_assert_reset; } clk_prepare_enable(tv->top_clk); } This is from the H616 user manual. Figure 7- 10. DAC Calibration 10-bit calibration value is burned into efuse. Every time software can read the 10-bit calibration value from efuse, to control BIAS current and BIAS current switch, then a specific BIAS current is generated to calibrate maximum output voltage of DAC. We need to extract the DAC calibration value (tvout 32) from SID. https://linux-sunxi.org/SID_Register_Guide hexdump -C /sys/bus/nvmem/devices/sunxi-sid0/nvmem H6 Name Offset Size Description CHIPID 0x00 128 bit Chip-ID, also known as SID BROM_CONFIG 0x10 32 bit unknown, "16 bits config, 16 bits try" THERMAL_SENSOR 0x14 64 bit Thermal sensor calibration data TF_ZONE 0x1c 128 bit unknown, probably reserved for Trusted Firmware OEM_PROGRAM 0x2c 160 bit unknown, "emac 16 + tvout 32 + reserv 112" Add quirks for h616. Not sure if .unknown is needed?? static const struct sun4i_tv_quirks h616_quirks = { .calibration = 0x?????????????, .unknown = 1, .hastvtop = true, }; static const struct of_device_id sun4i_tv_of_table[] = { { .compatible = "allwinner,sun4i-a10-tv-encoder", .data = &a10_quirks }, { .compatible = "allwinner,sun8i-h3-tv-encoder", .data = &h3_quirks }, { .compatible = "allwinner,sun50i-h5-tv-encoder", .data = &h5_quirks }, { .compatible = "allwinner,sun50i-h616-tv-encoder", .data = &h616_quirks }, { /* sentinel */ }, }; The dtsi might look similar to this. Not sure if it's correct. I think we need to add <&ccu CLK_TVE> to tcon_tv0 clocks. tcon_tv0: lcd-controller@6515000 { compatible = "allwinner,sun50i-h6-tcon-tv", "allwinner,sun8i-r40-tcon-tv"; reg = <0x06515000 0x1000>; interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; clocks = <&ccu CLK_BUS_TCON_TV0>, <&tcon_top CLK_TCON_TOP_TV0>; clock-names = "ahb", "tcon-ch1"; resets = <&ccu RST_BUS_TCON_TV0>; reset-names = "lcd"; ports { #address-cells = <1>; #size-cells = <0>; tcon_tv0_in: port@0 { reg = <0>; tcon_tv0_in_tcon_top_mixer0: endpoint@0 { reg = <0>; remote-endpoint = <&tcon_top_mixer0_out_tcon_tv0>; }; }; tcon_tv0_out: port@1 { #address-cells = <1>; #size-cells = <0>; reg = <1>; tcon_tv0_out_tve: endpoint@0 { reg = <0>; remote-endpoint = <&tve_in_tcon_tv0>; }; tcon_tv0_out_tcon_top: endpoint@1 { reg = <1>; remote-endpoint = <&tcon_top_hdmi_in_tcon_tv0>; }; }; }; }; tve: tv-encoder@6520000 { compatible = "allwinner,sun50i-h616-tv-encoder"; reg = <0x06520000 0x100>, <0x06524000 0x3fc>; clocks =<&ccu CLK_BUS_TVE_TOP>, <&ccu CLK_BUS_TVE0>; clock-names = "clk_bus_tve_top", "clk_bus_tve"; resets = <&ccu RST_BUS_TVE_TOP>, <&ccu RST_BUS_TVE0>; reset-names = "rst_bus_tve_top", "rst_bus_tve"; status = "disabled"; port { tve_in_tcon_tv0: endpoint { remote-endpoint = <&tcon_tv0_out_tve>; }; }; }; I haven't looked into the mixer1 part of the patch. Not sure if H616/H618 has one. I can't find the base address in the H616 user manual. BSP kernel code that might help us. https://github.com/AvaotaSBC/linux/tree/main/bsp/drivers/video/sunxi/disp2/tv https://github.com/AvaotaSBC/linux/tree/main/bsp/drivers/video/sunxi/disp2/disp/de Edited November 11 by Nick A 0 Quote
jernej Posted November 11 Posted November 11 On 11/9/2024 at 7:41 PM, Nick A said: I haven't looked into the mixer1 part of the patch. Not sure if H616/H618 has one. I can't find the base address in the H616 user manual. It has, all H family has 2 mixers. Addresses are hidden in DE BSP source code, but not as absolute address, only as relative. In any case, you don't need second mixer if you won't use any other display output. Note that there is no documentation for DE3.3. There is documentation for DE3 on linux-sunxi.org, which is older, but nevertheless similar core. Still, BSP source code will give you best info, even if it's sometimes hard to understand. In any case, you seem to be on right track to get it working. I strongly suggest that you dump register values of all components involved in pipeline from working BSP solution (most likely Android image) and compare to them to register values dump from your mainline based system. This includes TVE, TCON top and also very importantly, clocks and resets. One extremely useful trick for diagnostics is to use TCON test patterns. Those patterns are directly generated in TCON and then piped to encoder, TVE in this case. It allows you to test TVE without worrying about mixer and if it's properly routed through TCON top. Those test patterns can be enabled by setting TCON register 0x40 to, for example, 1, which will get you well know color check pattern. Note that your solution with TV TOP included in same driver as TVE will work here, but it's not appropriate solution for upstream. TV TOP should be standalone driver like TCON TOP... 0 Quote
Robolightning Posted November 14 Author Posted November 14 My repo with try to port it from Android source codes and ChatGPT. Maybe it will help you: https://github.com/StableKite/OPiZero2WTVOutDriver 0 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.