arne48 / tinkerboard_io

Yet another library to use the 40pin header of the Asus Tinker Board.
GNU General Public License v3.0
11 stars 1 forks source link

GPIO is not working #4

Closed yma326 closed 5 years ago

yma326 commented 5 years ago

Thanks for Arne Hitzmann's code. I tested with the GPIO input and output examples and they didn't work, I can not change the outputs state or read the inputs change. It came back to normal if I ran "gpio readall" provided by TinkerBoard first. It turns out that the clock gating controls for the GPIOs are not turned on in the original initialization code, these controls are off after reset. Here is the change I made to fix the problem, add below code right before "retcode = 1;" in int tinkerboard_init(void)

define CRU_CLKGATE14_CON 0x0198

define CRU_CLKGATE17_CON 0x01a4

// void gpio_clk_enable(void) // from https://github.com/TinkerBoard/gpio_lib_c/blob/sbc/tinkerboard/c/wiringPi/wiringTB.c int write_bit, reg_offset, bank; for( bank = 0 ; bank <= 8 ; bank++){ write_bit = (bank != 0) ? bank : 4; reg_offset = (bank != 0) ? CRU_CLKGATE14_CON : CRU_CLKGATE17_CON; (_rk3288_cru_block_base + reg_offset/4) = ((_rk3288_cru_block_base + reg_offset/4) & ~(0x1 << write_bit)) | (0x1 << (16 + write_bit)); }

retcode = 1;

arne48 commented 5 years ago

Thanks for pointing out this issue. I didn't noticed this behavior yet. Which image do you use? I will have a closer look at this as soon as I have time for it and adopt your fix. Also thank you for providing a possible fix already.

arne48 commented 5 years ago

It took me way longer to find some time to have a look into this. For my test I used the most recent image provided by ASUS (linaro-stretch-alip-v2.0.8.zip), as you didn't specified it further. With this image I could verify that the GPIOs are not initialized correctly. However, an old version of ASUS' image (v1.8), I still had, is not affected. After an additional test on my own Armbian build I will integrate this fix into tinkerboard_io, to keep it compatible with ASUS' images. Thanks @yma326 for posting this issue.

yma326 commented 5 years ago

The image for my Tinker board is "ARMBIAN 5.50 testing Debian GNU/Linux 9 (stretch) 4.14.52-rockchip", I can not find the original zip file and link at this moment. I know for sure the problem was caused by clock gating controls initialization. There is a Chinese document provided by RK3288 manufacturer, it mentions that the gpio clock must be on before change gpio settings, quote "pinctrl: rockchip: only enable gpio clock when it setting, gpio can keep state even the clock disable, for save power consumption, only enable gpio clock when it setting". They should put this information into TRM instead of a side note. Also according to TRM, all gpio clock are off after reset. We don't need to turn on gpio clock in application level if the kernel already did this job.

arne48 commented 5 years ago

I added the setting of the gpio block clock gates to the initialization https://github.com/arne48/tinkerboard_io/commit/15cb2efe0f46d3f950e7c1b0c4bd464d14aa7bad. ASUS is enabling all 9 blocks, even though we just use 0 and 5-8, but for consistency I replicated the behavior of ASUS.

@yma326 can you please try my implementation and confirm that it is working for you as well?

In regards to the pinctrl-rockchip: I had a look into the kernel driver, and indeed they only enable the clock for the moment they interact with a gpio pinctrl-rockchip.c:3507. Unfortunately this means if the rockchip gpio driver is used while tinkerboard_io is running a gpio can lose its clock because the clock gates are just enabled once during initialization, and pinctrl-rockchip is disabling it after each interaction. The reset value (0) of the gpio blocks' clock gates, however, should activate them on reset as the register's logic is active-low according to the TRM.

yma326 commented 5 years ago

I tested your new code, it works good now, Thank you! Yes, your are right, all gpio clocks are enabled after reset, they are active-low according to TRM. It is better that we enable clocks on the application level.