PaddleStroke Posted December 8, 2017 Posted December 8, 2017 Hi there, Is there a way to make an automatic switch between AV and HDMI when HDMI connector is connected/disconnected? ie By default AV composite signal is ON, if HDMI is detected while booting, then video and sound are output to HDMI instead of AV/L/R output. I read that if both TV out and HDMI are enable at the same time it can result in artifacts on HDMI and for that reason TV was disabled by default. So is there a way to detect if HDMI is plugged in, and if so disable TV out. I would say it needs 2 .bin files with each config, but how to detect if HDMI is present before loading .bin and load the right .bin according to situation? Also is it possible to rotate display by 90 or 180° ? Would it be possible to have : - by default AV with 180° rotation - if HDMI detected then HDMI without rotation? Thanks! (for H2+/H3 board)
jernej Posted December 8, 2017 Posted December 8, 2017 2 hours ago, PaddleStroke said: Also is it possible to rotate display by 90 or 180° ? Probably, but it is not HW accelerated on H3. About other things, something can be done, IF you rebuild kernel with CONFIG_SWITCH or CONFIG_ANDROID_SWITCH enabled. That way you will get few files, which will have different content, based on TV or HDMI hot plug detection status. Not sure where those files will be located, but it will be probably somewhere in /sys or /proc. Code for that is located here: https://github.com/armbian/linux/blob/sun8i/drivers/video/sunxi/disp2/hdmi/drv_hdmi.c#L491-L510 https://github.com/armbian/linux/blob/sun8i/drivers/video/sunxi/disp2/tv/drv_tv.c#L31-L82 In script.bin you would need enabled both, hdmi and tv, or else you won't get status notification. Final step would be writing simple daemon, which will monitor aforementioned files and react on content change accordingly. There is simple way how to enable/disable TV/HDMI display from userspace on running system, but you would need root access. Since you already need to recompile the kernel, you should patch this part of code to have access rights 0666, so root rights are not needed The procedure how to turn on/off hdmi/tv can be found here Just instead "disp" use "disp0" and "disp1" respectively. There is another procedure if this doesn't work. I'm not sure if work described above is worth the hassle, but your strategy may work. 1
PaddleStroke Posted July 11, 2018 Author Posted July 11, 2018 Thanks for your reply jernej! I could fix my rotate problem by hardware modification of the LCD. However I have not yet got the HDMI/AV switch working. I think I have a total lack of understanding on how drv_hdmi and drv_tv work. Also I don't understand how this CONFIG_SWITCH works. But is it not possible to just use a simple daemon that would do something like : define last_read_HPD = 0 While 1 HDMI_HPD = read status directly from registry if HDMI_HPD =! last_read_HPD if HDMI_HPD = 1 turn OFF disp1 as you describe here turn ON disp0 if HDMI_HPD = 0 turn OFF disp0 turn ON disp1 last_read_HPD = HDMI_HPD However I don't know how to read the HDMI_HPD status. I checked the H3 datasheet but can't find HPD registry address. I have found there (line 114) a function that seem to be doing just that but I can't understand how it works. 114 static int sunxi_dw_hdmi_get_plug_in_status(void) 115 { 116 struct sunxi_hdmi_phy * const phy = 117 (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); 118 119 return !!(readl(&phy->status) & (1 << 19)); 120 } I can't find where is defined SUNXI_HDMI_BASE (and so it's value) to get the exact address. Also I don't understand the return. Do you know how to read HPD status from the daemon? Do you think this simple methode would work? Thanks!
jernej Posted July 11, 2018 Posted July 11, 2018 That can work only if /dev/mem (or kmem?) access is permissive, i.e. it is allowed to access device memory regions from userspace. Additionally, daemon has to be run as root (maybe you can drop priviliges later?). That being said, it can work. HDMI PHY status register is 32 bit wide, located at 0x01ef0038 and as you can see from above snippet, you have to check bit 19. 1
PaddleStroke Posted July 13, 2018 Author Posted July 13, 2018 Thanks! Quote /dev/mem (or kmem?) access is permissive, i.e. it is allowed to access device memory regions from userspace. Is this the same with access rights 0666 ? If not how to enable this access? Also do you know how to read from registers? From my reading we can use dev/mem file right? In pyA20 there's an example but I am not sure to understand how it works. and how this mem file is structured. Any hints how to read a specific register address from it?
PaddleStroke Posted July 19, 2018 Author Posted July 19, 2018 I found how to modify pyA20 to check the register value. I added this to gpio_lib.c and gpio_lib.h, then some other things in gpio.c to declare the new module. - added in gpio_lib.h #define HDMI_PHY_BASE 0x01ef0038 - added in gpio_lib.c int get_HDMI_HPD() { if (SUNXI_PHY_BASE == 0) return -1; uint32_t reg = (uint32_t *)SUNXI_PHY_BASE; return (reg & ( 1 << 19))>> 19; } However I still can't read the hpd status. At the beginning it just returned me 1, if HDMI connected or not. Then to further investigate I modified the function to : int get_HDMI_HPD() { if (SUNXI_PHY_BASE == 0) return -1; uint32_t reg = (uint32_t *)SUNXI_PHY_BASE; return reg & 1048575; #1048575 because it's 11111111111111111111 in binary. } So I could read the 20 first bits of the register, and see what happens. Then I have some very strange results. The value returned does not depend if HDMI is connected or not. So when I run my python script, it initialize pyA20 (so the mmap to dev/mem) Then whenever I check get_HDMI_HPD() I have the same number returned again and again. Even if I unconnect HDMI. For example - return = 11010010000000111000 (= 860216 in dec) - disconnect HDMI - return = 11010010000000111000 (= 860216 in dec) - wait 10 minutes - return = 11010010000000111000 (= 860216 in dec) Then if I close the python script and open again (so mmap is reinitialized) the number change : - return = 01010111000000111000 (356408) - disconnect HDMI - return = 01010111000000111000 (356408) ... I tested several times and each time mmap is reinitialized the number changes. HDMI has no effect what so ever. 11010010000000111000 860216 10111101000000111000 774200 11011111000000111000 913464 11001010000000111000 827448 01010111000000111000 356408 00000001000000111000 4152 the mmap seem correct : int sunxi_gpio_init(void) { int fd; unsigned int addr_start, addr_offset; unsigned int PageSize, PageMask; void *pc; void *pc2; fd = open("/dev/mem", O_RDWR); if (fd < 0) return -1; //mmap for GPIO PageSize = sysconf(_SC_PAGESIZE); PageMask = (~(PageSize - 1)); addr_start = SW_PORTC_IO_BASE & PageMask; addr_offset = SW_PORTC_IO_BASE & ~PageMask; pc = (void *)mmap(0, PageSize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr_start); if (pc == MAP_FAILED) return -1; SUNXI_PIO_BASE = (unsigned int)pc; SUNXI_PIO_BASE += addr_offset; //mmap for HPD addr_start = HDMI_PHY_BASE & PageMask; addr_offset = HDMI_PHY_BASE & ~PageMask; pc2 = (void *)mmap(0, PageSize * 2, PROT_READ, MAP_SHARED, fd, addr_start); if (pc2 == MAP_FAILED) return -1; SUNXI_PHY_BASE = (unsigned int)pc2; SUNXI_PHY_BASE += addr_offset; close(fd); return 0; } Do you see something wrong in my mmap? I used the same syntax with the GPIO mmap, and I tested the GPIO are still working correctly, even if the getHPD always give the same result. Are you sure about the register address for HPD? Or maybe it's not in the dev/mem file, I don't know how this file works. Is it the full register values? Enclosed are the modified pyA20 files. gpio.c gpio_lib.c gpio_lib.h
jernej Posted July 22, 2018 Posted July 22, 2018 Address is correct. I would suggest you first find devmem2 program (source is all over the net). It does almost exactly what you want, but universally (you give it physical address on command line which you want to read). 1
PaddleStroke Posted October 24, 2018 Author Posted October 24, 2018 Thanks!! It's indeed working with devmem2. There should have been something wrong in my mmap before. When I run devmem2 the value change when HDMI is connected or not. No HDMI : 266f0 0000 0000 0000 0010 0110 0110 1111 0000 HDMI : a66F0 0000 0000 0000 1010 0110 0110 1111 0000 The method you gave here, is working for legacy 3.4.113 correct? So I should do : Switch from TV (TNSC) to HDMI sudo su cd /sys/kernel/debug/dispdbg/ echo "switch" > command echo "disp" > name echo "4 5" > param echo "1" > start Why is it "4 5" ? Is it not as follow : "screen0_output_type screen0_output_mode" In script.bin HDMI output type is "3", "4" being VGA. (source here) Switch from HDMI to TV (TNSC) sudo su cd /sys/kernel/debug/dispdbg/ echo "switch" > command echo "disp" > name echo "2 14" > param echo "1" > start Or should I first disable the previous video output with : sudo su cd /sys/kernel/debug/dispdbg/ echo "switch" > command echo "disp" > name echo "0" > param echo "1" > start Or should I used disp0 and disp1 as you suggest? Then it would be as follow : Switch from TV (TNSC) to HDMI sudo su cd /sys/kernel/debug/dispdbg/ echo "switch" > command echo "disp1" > name echo "0 14" > param echo "1" > start echo "switch" > command echo "disp0" > name echo "4 5" > param echo "1" > start Switch from HDMI to TV (TNSC) sudo su cd /sys/kernel/debug/dispdbg/ echo "switch" > command echo "disp0" > name echo "0 5" > param echo "1" > start echo "switch" > command echo "disp1" > name echo "2 14" > param echo "1" > start PS : for those that might be interested, here is how to install devmem2 If you have internet access just do the following : wget http://free-electrons.com/pub/mirror/devmem2.c gcc ./devmem2.c sudo mv ./a.out /usr/local/bin/devmem2 Then to run devmem2 to read a value type : sudo devmem2 0x01EF0038 You can replace 0x01EF0038 by the address you want to read.
PaddleStroke Posted October 24, 2018 Author Posted October 24, 2018 Ok after few tests : Currently my script.bin is as follow : [disp_init] disp_mode = 1 #(tv mode) screen0_output_type = 3 screen0_output_mode = 5 screen1_output_type = 2 screen1_output_mode = 14 hdmi_used = 0 tv_used = 1 Using "disp" --> does not work Using "disp1" --> works echo "switch" > command echo "disp1" > name echo "0" > param echo "1" > start --> turn off my TV signal. However enabling HDMI instead does not work. I tried : echo "switch" > command echo "disp1" > name echo "4 5" > param echo "1" > start and with "3 5" both don't work. It just turns OFF the TV signal but HDMI is not turning ON. I guess it's because HDMI should be set on disp0 and not disp1? Is there any documentation about this dispdbg commands? Can't find any on google. Then as I have no longer video signal I don't know how to know what happens afterwards and have to reboot the unit.
PaddleStroke Posted October 24, 2018 Author Posted October 24, 2018 on another topic, I found this about LCD rotation : http://linux-sunxi.org/Display Quote Rotation You can rotate the framebuffer by supplying fbcon=rotate:<n> kernel parameter, where n can be one of the following. 0 - normal orientation (0 degree) 1 - clockwise orientation (90 degrees) 2 - upside down orientation (180 degrees) 3 - counterclockwise orientation (270 degrees) Alternatively you could echo <n> to /sys/class/graphics/fbcon/rotate after kernel has booted. For more see Documentation/fb/fbcon.txt in kernel tree. Can someone explain me what it means "supply" a kernel parameter and how to do it? Also I tried to echo on a booted device. sudo su cd /sys/class/graphics/fbcon echo "2" > rotate But nothing happenned, no error message. I am missing something? I am not sure to understand differences between sunxi-linux and armbian and how they interact...
jernej Posted October 24, 2018 Posted October 24, 2018 44 minutes ago, PaddleStroke said: But nothing happenned, no error message. I am missing something? I guess this functionality doesn't work on H3. I have seen something like that for A64 with Allwinner provided changes to X11 driver which used "transform" HW, which exists primarly on A series SoCs (and maybe few others). But I might be wrong...
PaddleStroke Posted October 25, 2018 Author Posted October 25, 2018 16 hours ago, jernej said: I guess this functionality doesn't work on H3. I have seen something like that for A64 with Allwinner provided changes to X11 driver which used "transform" HW, which exists primarly on A series SoCs (and maybe few others). But I might be wrong... Thanks for feedback, anyway I found a way to hardware rotate LCD now. It was just for curiosity. What about the dispdbg commands? Do you know where I can find documentation about that? Or the source code of these commands? Any idea how to disable disp1 and enable disp0 ? I think perhaps it's not working because the switch command only changes the screen_output_type and mode but is not actually enabling/disabling screen0/screen1 I tried to enable both disp in my script.bin with : [disp_init] disp_init_enable = 1 disp_mode = 2 # dual head screen0_output_type = 0 # 0 should be NONE screen0_output_mode = 5 screen1_output_type = 2 screen1_output_mode = 14 But then I have not any signal on either screen. Maybe disp_mode= 4 (clone(screen0, screen1, fb0) (2 screens, one standard framebuffer) ) would work? Also I am not sure how to enable HDMI after disable TV (as I don't have screen anymore...). So I tried to make a bash file but not sure the syntax is correct. Can you tell me if something is wrong in the syntax? #!/bin/bash cd /sys/kernel/debug/dispdbg/ echo "switch" > command echo "disp1" > name echo "0 14" > param echo "1" > start sleep 2 cd /sys/kernel/debug/dispdbg/ echo "switch" > command echo "disp0" > name echo "4 5" > param echo "1" > start
jernej Posted October 25, 2018 Posted October 25, 2018 8 hours ago, PaddleStroke said: What about the dispdbg commands? Do you know where I can find documentation about that? Or the source code of these commands? No documentation whatsoever, except maybe in Chinese. I found commands in source code here. I already forgot everything related to those commands, so I suggest you take a look at code linked above.
PaddleStroke Posted October 26, 2018 Author Posted October 26, 2018 14 hours ago, jernej said: No documentation whatsoever, except maybe in Chinese. I found commands in source code here. I already forgot everything related to those commands, so I suggest you take a look at code linked above. Thanks for feedback! In chinese, do you mean that those commands are hardware coded in the allwinner chip? It's not something that is coded in armbian? I can handle chinese documentation if you have any. Or if you confirm allwinner could help I'll ask them, but I am not sure what to ask them right now as I thought it was a armbian feature.
jernej Posted October 26, 2018 Posted October 26, 2018 9 hours ago, PaddleStroke said: In chinese, do you mean that those commands are hardware coded in the allwinner chip? It's not something that is coded in armbian? I meant chinese pdfs. SDK releases sometimes have some documentation, but it is almost always in chinese. And before you ask, I don't now where to find it. It is already years when I last saw any kind of H3 SDK documentation. BTW, these last post have everything I remember from head. I don't want to spend any time with 3.4 BSP kernel.
Recommended Posts