# HG changeset patch # User Paul Boddie # Date 1708960693 -3600 # Node ID bde5d7799e655dcc836634f4f59a81e693703c26 # Parent 95b2d7c12fa35840db4bb0432672761b039f36cb Added support for shadow GPIO (PZ) registers. diff -r 95b2d7c12fa3 -r bde5d7799e65 pkg/devices/lib/gpio/include/gpio-x1600.h --- a/pkg/devices/lib/gpio/include/gpio-x1600.h Fri Feb 23 22:53:30 2024 +0100 +++ b/pkg/devices/lib/gpio/include/gpio-x1600.h Mon Feb 26 16:18:13 2024 +0100 @@ -2,7 +2,7 @@ * GPIO driver for Ingenic X1600. * (See below for additional copyright and licensing notices.) * - * Copyright (C) 2017, 2018, 2023 Paul Boddie + * Copyright (C) 2017, 2018, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -46,7 +46,12 @@ class Gpio_x1600_irq_pin : public Hw::Gpio_irq_pin { unsigned _pin; - Hw::Register_block<32> _regs; + + // Register blocks for the conventional and optional shadow registers. + + Hw::Register_block<32> _regs, _shadow_regs; + uint8_t _port_number; + bool _shadow; // Convenience method for obtaining the bit corresponding to a pin. @@ -56,6 +61,10 @@ void write_reg_pin(unsigned reg); public: + Gpio_x1600_irq_pin(unsigned pin, Hw::Register_block<32> const ®s, + Hw::Register_block<32> const &shadow_regs, + uint8_t port_number); + Gpio_x1600_irq_pin(unsigned pin, Hw::Register_block<32> const ®s); void do_mask(); @@ -68,12 +77,20 @@ class Gpio_x1600_chip : public Hw::Gpio_chip { private: - Hw::Register_block<32> _regs; + // Register blocks for the conventional and optional shadow registers. + + Hw::Register_block<32> _regs, _shadow_regs; l4_addr_t _start, _end; unsigned _nr_pins; l4_uint32_t _pull_ups, _pull_downs; + // Optional shadow port configuration. + + l4_addr_t _shadow_start, _shadow_end; + uint8_t _port_number; + bool _shadow; + // Convenience method for obtaining the bit corresponding to a pin. l4_uint32_t _pin_bit(unsigned pin) @@ -98,10 +115,14 @@ } } + void write_reg_pin(unsigned reg, unsigned pin); + public: Gpio_x1600_chip(l4_addr_t start, l4_addr_t end, - unsigned nr_pins, - l4_uint32_t pull_ups, l4_uint32_t pull_downs); + unsigned nr_pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs, + l4_addr_t shadow_start = 0, l4_addr_t shadow_end = 0, + uint8_t port_number = 0); // Obtain the number of pins. @@ -149,7 +170,12 @@ EXTERN_C_BEGIN void *x1600_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins, - l4_uint32_t pull_ups, l4_uint32_t pull_downs); + l4_uint32_t pull_ups, l4_uint32_t pull_downs); + +void *x1600_gpio_init_shadow(l4_addr_t start, l4_addr_t end, unsigned pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs, + l4_addr_t shadow_start, l4_addr_t shadow_end, + uint8_t port_number); void x1600_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value); void x1600_gpio_config_pull(void *gpio, unsigned pin, unsigned mode); diff -r 95b2d7c12fa3 -r bde5d7799e65 pkg/devices/lib/gpio/src/x1600.cc --- a/pkg/devices/lib/gpio/src/x1600.cc Fri Feb 23 22:53:30 2024 +0100 +++ b/pkg/devices/lib/gpio/src/x1600.cc Mon Feb 26 16:18:13 2024 +0100 @@ -106,8 +106,15 @@ // IRQ control for each GPIO pin. +Gpio_x1600_irq_pin::Gpio_x1600_irq_pin(unsigned pin, Hw::Register_block<32> const ®s, + Hw::Register_block<32> const &shadow_regs, + uint8_t port_number) +: _pin(pin), _regs(regs), _shadow_regs(shadow_regs), _port_number(port_number), + _shadow(true) +{} + Gpio_x1600_irq_pin::Gpio_x1600_irq_pin(unsigned pin, Hw::Register_block<32> const ®s) -: _pin(pin), _regs(regs) +: _pin(pin), _regs(regs), _shadow(false) {} void @@ -116,7 +123,10 @@ // Write the pin bit to the register, setting or clearing the pin // depending on the register chosen. - _regs[reg] = _pin_bit(_pin); + if (_shadow) + _shadow_regs[reg] = _pin_bit(_pin); + else + _regs[reg] = _pin_bit(_pin); } void Gpio_x1600_irq_pin::do_mask() @@ -142,11 +152,10 @@ // not atomic, that's why we first mask the IRQ and if it was // enabled we unmask it after we have changed the mode - /* NOTE: The X1600 provides a special port Z that allows changes to be made - and then committed atomically using PzGID2LD. This is not currently - used. */ + // The X1600 provides a special port Z that allows changes to be made and then + // committed atomically using PzGID2LD. - if (enabled()) + if (!_shadow && enabled()) do_mask(); // Do the PxINT, PxPAT1 and PxPAT0 configuration. @@ -178,7 +187,9 @@ return false; } - if (enabled()) + if (_shadow) + _shadow_regs[Shadow_transfer] = _port_number; + else if (enabled()) do_unmask(); return true; @@ -205,13 +216,37 @@ // Initialise the GPIO controller. Gpio_x1600_chip::Gpio_x1600_chip(l4_addr_t start, l4_addr_t end, - unsigned nr_pins, - l4_uint32_t pull_ups, l4_uint32_t pull_downs) + unsigned nr_pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs, + l4_addr_t shadow_start, l4_addr_t shadow_end, + uint8_t port_number) : _start(start), _end(end), _nr_pins(nr_pins), - _pull_ups(pull_ups), _pull_downs(pull_downs) + _pull_ups(pull_ups), _pull_downs(pull_downs), + _shadow_start(shadow_start), _shadow_end(shadow_end), + _port_number(port_number) { _regs = new Hw::Mmio_register_block<32>(_start); + + if (_shadow_start) + { + _shadow_regs = new Hw::Mmio_register_block<32>(_shadow_start); + _shadow = true; + } + else + _shadow = false; +} + +void +Gpio_x1600_chip::write_reg_pin(unsigned reg, unsigned pin) +{ + // Write the pin bit to the register, setting or clearing the pin + // depending on the register chosen. + + if (_shadow) + _shadow_regs[reg] = _pin_bit(pin); + else + _regs[reg] = _pin_bit(pin); } // Return the value of a pin. @@ -281,22 +316,25 @@ switch (mode) { case Input: - _regs[Port_int_clear] = _pin_bit(pin); - _regs[Port_gpio_set] = _pin_bit(pin); - _regs[Port_dir_set] = _pin_bit(pin); + write_reg_pin(Port_int_clear, pin); + write_reg_pin(Port_gpio_set, pin); + write_reg_pin(Port_dir_set, pin); break; case Output: - _regs[Port_int_clear] = _pin_bit(pin); - _regs[Port_gpio_set] = _pin_bit(pin); - _regs[Port_dir_clear] = _pin_bit(pin); + write_reg_pin(Port_int_clear, pin); + write_reg_pin(Port_gpio_set, pin); + write_reg_pin(Port_dir_clear, pin); break; case Irq: - _regs[Port_int_set] = _pin_bit(pin); + write_reg_pin(Port_int_set, pin); // Other details depend on the actual trigger mode. break; default: break; } + + if (_shadow) + _shadow_regs[Shadow_transfer] = _port_number; } // Pull-up/down configuration for a pin. @@ -342,22 +380,25 @@ // Support two different outputs. case Hw::Gpio_chip::Function_gpio: - _regs[Port_int_clear] = _pin_bit(pin); - _regs[Port_gpio_set] = _pin_bit(pin); - _regs[value & 1 ? Port_data_set : Port_data_clear] = _pin_bit(pin); + write_reg_pin(Port_int_clear, pin); + write_reg_pin(Port_gpio_set, pin); + write_reg_pin(value & 1 ? Port_data_set : Port_data_clear, pin); break; // Support four different device functions. case Hw::Gpio_chip::Function_alt: - _regs[Port_int_clear] = _pin_bit(pin); - _regs[Port_gpio_clear] = _pin_bit(pin); - _regs[value & 2 ? Port_group1_set : Port_group1_clear] = _pin_bit(pin); - _regs[value & 1 ? Port_group0_set : Port_group0_clear] = _pin_bit(pin); + write_reg_pin(Port_int_clear, pin); + write_reg_pin(Port_gpio_clear, pin); + write_reg_pin(value & 2 ? Port_group1_set : Port_group1_clear, pin); + write_reg_pin(value & 1 ? Port_group0_set : Port_group0_clear, pin); break; default: throw -L4_EINVAL; } + + if (_shadow) + _shadow_regs[Shadow_transfer] = _port_number; } // Obtain a pin's configuration from a register in the supplied value. @@ -418,7 +459,10 @@ if (pin >= _nr_pins) throw -L4_EINVAL; - return new Gpio_x1600_irq_pin(pin, _regs); + if (_shadow) + return new Gpio_x1600_irq_pin(pin, _regs, _shadow_regs, _port_number); + else + return new Gpio_x1600_irq_pin(pin, _regs); } // Pin function configuration for multiple pins. @@ -448,11 +492,20 @@ // C language interface functions. void *x1600_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins, - l4_uint32_t pull_ups, l4_uint32_t pull_downs) + l4_uint32_t pull_ups, l4_uint32_t pull_downs) { return (void *) new Gpio_x1600_chip(start, end, pins, pull_ups, pull_downs); } +void *x1600_gpio_init_shadow(l4_addr_t start, l4_addr_t end, unsigned pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs, + l4_addr_t shadow_start, l4_addr_t shadow_end, + uint8_t port_number) +{ + return (void *) new Gpio_x1600_chip(start, end, pins, pull_ups, pull_downs, + shadow_start, shadow_end, port_number); +} + void x1600_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) { static_cast(gpio)->setup(pin, mode, value); diff -r 95b2d7c12fa3 -r bde5d7799e65 pkg/landfall-examples/Control --- a/pkg/landfall-examples/Control Fri Feb 23 22:53:30 2024 +0100 +++ b/pkg/landfall-examples/Control Mon Feb 26 16:18:13 2024 +0100 @@ -1,3 +1,3 @@ provides: landfall-examples -requires: crtn l4re l4re_c mag-gfx devices +requires: crtn l4re l4re_c mag-gfx devices libfsclient libfsserver Maintainer: paul@boddie.org.uk diff -r 95b2d7c12fa3 -r bde5d7799e65 pkg/landfall-examples/hw_info/common.h --- a/pkg/landfall-examples/hw_info/common.h Fri Feb 23 22:53:30 2024 +0100 +++ b/pkg/landfall-examples/hw_info/common.h Mon Feb 26 16:18:13 2024 +0100 @@ -102,7 +102,12 @@ /* GPIO adapter functions. */ void *gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins, - l4_uint32_t pull_ups, l4_uint32_t pull_downs); + l4_uint32_t pull_ups, l4_uint32_t pull_downs); + +void *gpio_init_shadow(l4_addr_t start, l4_addr_t end, unsigned pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs, + l4_addr_t shadow_start, l4_addr_t shadow_end, + uint8_t port_number); void gpio_setup(void *gpio, unsigned pin, unsigned mode, int value); diff -r 95b2d7c12fa3 -r bde5d7799e65 pkg/landfall-examples/hw_info/hw_info.c --- a/pkg/landfall-examples/hw_info/hw_info.c Fri Feb 23 22:53:30 2024 +0100 +++ b/pkg/landfall-examples/hw_info/hw_info.c Mon Feb 26 16:18:13 2024 +0100 @@ -2006,8 +2006,11 @@ printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end); for (port = 0; port < num_gpio_ports; port++) - gpio[port] = gpio_init(gpio_base + port * 0x100, gpio_base + (port + 1) * 0x100, - 32, gpio_ports[port].pull_ups, gpio_ports[port].pull_downs); + gpio[port] = gpio_init_shadow(gpio_base + port * 0x100, gpio_base + (port + 1) * 0x100, + 32, + gpio_ports[port].pull_ups, gpio_ports[port].pull_downs, + gpio_base + 0x700, gpio_base + 0x700, + port); printf("Access I2C...\n"); diff -r 95b2d7c12fa3 -r bde5d7799e65 pkg/landfall-examples/hw_info/jz4780.c --- a/pkg/landfall-examples/hw_info/jz4780.c Fri Feb 23 22:53:30 2024 +0100 +++ b/pkg/landfall-examples/hw_info/jz4780.c Mon Feb 26 16:18:13 2024 +0100 @@ -193,6 +193,15 @@ return jz4780_gpio_init(start, end, pins, pull_ups, pull_downs); } +void *gpio_init_shadow(l4_addr_t start, l4_addr_t end, unsigned pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs, + l4_addr_t shadow_start, l4_addr_t shadow_end, + uint8_t port_number) +{ + (void) shadow_start; (void) shadow_end; (void) port_number; + return jz4780_gpio_init(start, end, pins, pull_ups, pull_downs); +} + void gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) { jz4780_gpio_setup(gpio, pin, mode, value); diff -r 95b2d7c12fa3 -r bde5d7799e65 pkg/landfall-examples/hw_info/x1600.c --- a/pkg/landfall-examples/hw_info/x1600.c Fri Feb 23 22:53:30 2024 +0100 +++ b/pkg/landfall-examples/hw_info/x1600.c Mon Feb 26 16:18:13 2024 +0100 @@ -182,6 +182,15 @@ return x1600_gpio_init(start, end, pins, pull_ups, pull_downs); } +void *gpio_init_shadow(l4_addr_t start, l4_addr_t end, unsigned pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs, + l4_addr_t shadow_start, l4_addr_t shadow_end, + uint8_t port_number) +{ + return x1600_gpio_init_shadow(start, end, pins, pull_ups, pull_downs, + shadow_start, shadow_end, port_number); +} + void gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) { x1600_gpio_setup(gpio, pin, mode, value);