diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi index 9c61122ee37..522413c94f1 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi @@ -97,7 +97,7 @@ pinctrl-names = "default"; }; -&gpio0 { +gpio0_lo: &gpio0 { status = "okay"; }; diff --git a/doc/releases/migration-guide-4.2.rst b/doc/releases/migration-guide-4.2.rst index 32f10e71653..649b2d15492 100644 --- a/doc/releases/migration-guide-4.2.rst +++ b/doc/releases/migration-guide-4.2.rst @@ -37,9 +37,21 @@ Boards Device Drivers and Devicetree ***************************** +Ethernet +======== + * Removed Kconfig option ``ETH_STM32_HAL_MII`` (:github:`86074`). PHY interface type is now selected via the ``phy-connection-type`` property in the device tree. +GPIO +==== + +* To support the RP2350B, which has many pins, the RaspberryPi-GPIO configuration has + been changed. The previous role of :dtcompatible:`raspberrypi,rpi-gpio` has been migrated to + :dtcompatible:`raspberrypi,rpi-gpio-port`, and :dtcompatible:`raspberrypi,rpi-gpio` is + now left as a placeholder and mapper. + The labels have also been changed along, so no changes are necessary for regular use. + Bluetooth ********* diff --git a/drivers/gpio/Kconfig.rpi_pico b/drivers/gpio/Kconfig.rpi_pico index 64370be497c..8d75fea4472 100644 --- a/drivers/gpio/Kconfig.rpi_pico +++ b/drivers/gpio/Kconfig.rpi_pico @@ -3,7 +3,7 @@ config GPIO_RPI_PICO default y - depends on DT_HAS_RASPBERRYPI_PICO_GPIO_ENABLED + depends on DT_HAS_RASPBERRYPI_PICO_GPIO_PORT_ENABLED select PICOSDK_USE_GPIO select PINCTRL bool "Raspberry Pi Pico GPIO driver" diff --git a/drivers/gpio/gpio_rpi_pico.c b/drivers/gpio/gpio_rpi_pico.c index 2e2e592eee8..198820f9244 100644 --- a/drivers/gpio/gpio_rpi_pico.c +++ b/drivers/gpio/gpio_rpi_pico.c @@ -16,28 +16,115 @@ #include -#define DT_DRV_COMPAT raspberrypi_pico_gpio +#define DT_DRV_COMPAT raspberrypi_pico_gpio_port #define ALL_EVENTS (GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE \ | GPIO_IRQ_LEVEL_LOW | GPIO_IRQ_LEVEL_HIGH) +#define GPIO_RPI_PINS_PER_PORT 32 + +#define ADDR_IS_ZERO(n, x) (DT_INST_REG_ADDR(n) == 0) | +#define ADDR_IS_NON_ZERO(n, x) (DT_INST_REG_ADDR(n) != 0) | +#define GPIO_RPI_LO_AVAILABLE (DT_INST_FOREACH_STATUS_OKAY_VARGS(ADDR_IS_ZERO) 0) +#define GPIO_RPI_HI_AVAILABLE (DT_INST_FOREACH_STATUS_OKAY_VARGS(ADDR_IS_NON_ZERO) 0) + +#if GPIO_RPI_HI_AVAILABLE +#define PORT_NO(port) ((((struct gpio_rpi_config *)port->config)->high_dev != NULL) ? 0 : 1) +#else +#define PORT_NO(port) ((int)port & 0) /* generate zero and suppress unused warning */ +#endif + struct gpio_rpi_config { struct gpio_driver_config common; void (*bank_config_func)(void); +#if GPIO_RPI_HI_AVAILABLE + const struct device *high_dev; +#endif }; struct gpio_rpi_data { struct gpio_driver_data common; sys_slist_t callbacks; - uint32_t int_enabled_mask; uint32_t single_ended_mask; uint32_t open_drain_mask; }; +static inline void gpio_set_dir_out_masked_n(uint n, uint32_t mask) +{ + if (!n) { + gpio_set_dir_out_masked(mask); + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hi_oe_set(mask); +#else + sio_hw->gpio_hi_oe_set = mask; +#endif + } +} + +static inline void gpio_set_dir_in_masked_n(uint n, uint32_t mask) +{ + if (!n) { + gpio_set_dir_in_masked(mask); + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hi_oe_clr(mask); +#else + sio_hw->gpio_hi_oe_clr = mask; +#endif + } +} + +static inline void gpio_set_dir_masked_n(uint n, uint32_t mask, uint32_t value) +{ + if (!n) { + gpio_set_dir_masked(mask, value); + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hi_oe_xor((gpioc_hi_oe_get() ^ value) & mask); +#else + sio_hw->gpio_oe_togl = (sio_hw->gpio_hi_oe ^ value) & mask; +#endif + } +} + +static inline uint32_t gpio_get_all_n(uint n) +{ + if (!n) { + return gpio_get_all(); + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + return gpioc_hi_in_get(); +#else + return sio_hw->gpio_hi_in; +#endif + } + + return 0; +} + +static inline void gpio_toggle_dir_masked_n(uint n, uint32_t mask) +{ + if (!n) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_lo_oe_xor(mask); +#else + sio_hw->gpio_oe_togl = mask; +#endif + } else if (n == 1) { +#if PICO_USE_GPIO_COPROCESSOR + gpioc_hi_oe_xor(mask); +#else + sio_hw->gpio_hi_oe_togl = mask; +#endif + } +} + static int gpio_rpi_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { + const int offset = GPIO_RPI_PINS_PER_PORT * PORT_NO(dev); struct gpio_rpi_data *data = dev->data; if (flags == GPIO_DISCONNECTED) { @@ -51,17 +138,15 @@ static int gpio_rpi_configure(const struct device *dev, return 0; } - gpio_set_pulls(pin, - (flags & GPIO_PULL_UP) != 0U, - (flags & GPIO_PULL_DOWN) != 0U); + gpio_set_pulls(pin + offset, (flags & GPIO_PULL_UP) != 0U, (flags & GPIO_PULL_DOWN) != 0U); /* Avoid gpio_init, since that also clears previously set direction/high/low */ - gpio_set_function(pin, GPIO_FUNC_SIO); + gpio_set_function(pin + offset, GPIO_FUNC_SIO); if (flags & GPIO_INPUT) { - gpio_set_dir(pin, GPIO_IN); + gpio_set_dir(pin + offset, GPIO_IN); } else { - gpio_set_input_enabled(pin, false); + gpio_set_input_enabled(pin + offset, false); } if (flags & GPIO_OUTPUT) { @@ -75,21 +160,21 @@ static int gpio_rpi_configure(const struct device *dev, */ if (flags & GPIO_LINE_OPEN_DRAIN) { data->open_drain_mask |= BIT(pin); - gpio_put(pin, 0); - gpio_set_dir(pin, flags & GPIO_OUTPUT_INIT_LOW); + gpio_put(pin + offset, 0); + gpio_set_dir(pin + offset, flags & GPIO_OUTPUT_INIT_LOW); } else { data->open_drain_mask &= ~(BIT(pin)); - gpio_put(pin, 1); - gpio_set_dir(pin, flags & GPIO_OUTPUT_INIT_HIGH); + gpio_put(pin + offset, 1); + gpio_set_dir(pin + offset, flags & GPIO_OUTPUT_INIT_HIGH); } } else { data->single_ended_mask &= ~(BIT(pin)); if (flags & GPIO_OUTPUT_INIT_HIGH) { - gpio_put(pin, 1); + gpio_put(pin + offset, 1); } else if (flags & GPIO_OUTPUT_INIT_LOW) { - gpio_put(pin, 0); + gpio_put(pin + offset, 0); } - gpio_set_dir(pin, GPIO_OUT); + gpio_set_dir(pin + offset, GPIO_OUT); } } @@ -99,20 +184,21 @@ static int gpio_rpi_configure(const struct device *dev, #ifdef CONFIG_GPIO_GET_CONFIG static int gpio_rpi_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *flags) { + const int offset = GPIO_RPI_PINS_PER_PORT * PORT_NO(dev); struct gpio_rpi_data *data = dev->data; *flags = 0; /* RP2xxxx supports Bus Keeper mode where both pull-up and pull-down are enabled. */ - if (gpio_is_pulled_up(pin)) { + if (gpio_is_pulled_up(pin + offset)) { *flags |= GPIO_PULL_UP; } - if (gpio_is_pulled_down(pin)) { + if (gpio_is_pulled_down(pin + offset)) { *flags |= GPIO_PULL_DOWN; } - if (gpio_get_dir(pin)) { - *flags |= gpio_get_out_level(pin) ? GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW; + if (gpio_get_dir(pin + offset)) { + *flags |= gpio_get_out_level(pin + offset) ? GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW; if (data->single_ended_mask & BIT(pin)) { *flags |= data->open_drain_mask & BIT(pin) ? GPIO_OPEN_DRAIN : GPIO_PUSH_PULL; @@ -127,9 +213,10 @@ static int gpio_rpi_get_config(const struct device *dev, gpio_pin_t pin, gpio_fl } #endif -static int gpio_rpi_port_get_raw(const struct device *dev, uint32_t *value) +static int gpio_rpi_port_get_raw(const struct device *port, uint32_t *value) { - *value = gpio_get_all(); + *value = gpio_get_all_n(PORT_NO(port)); + return 0; } @@ -137,12 +224,16 @@ static int gpio_rpi_port_set_masked_raw(const struct device *port, uint32_t mask, uint32_t value) { struct gpio_rpi_data *data = port->data; + /* First handle push-pull pins: */ - gpio_put_masked(mask & ~data->single_ended_mask, value); + gpio_put_masked_n(PORT_NO(port), mask & ~data->single_ended_mask, value); /* Then handle open-drain pins: */ - gpio_set_dir_masked(mask & data->single_ended_mask & data->open_drain_mask, ~value); + gpio_set_dir_masked_n(PORT_NO(port), mask & data->single_ended_mask & data->open_drain_mask, + ~value); /* Then handle open-source pins: */ - gpio_set_dir_masked(mask & data->single_ended_mask & ~data->open_drain_mask, value); + gpio_set_dir_masked_n(PORT_NO(port), + mask & data->single_ended_mask & ~data->open_drain_mask, value); + return 0; } @@ -150,12 +241,16 @@ static int gpio_rpi_port_set_bits_raw(const struct device *port, uint32_t pins) { struct gpio_rpi_data *data = port->data; + /* First handle push-pull pins: */ - gpio_set_mask(pins & ~data->single_ended_mask); + gpio_set_mask_n(PORT_NO(port), pins & ~data->single_ended_mask); /* Then handle open-drain pins: */ - gpio_set_dir_in_masked(pins & data->single_ended_mask & data->open_drain_mask); + gpio_set_dir_in_masked_n(PORT_NO(port), + pins & data->single_ended_mask & data->open_drain_mask); /* Then handle open-source pins: */ - gpio_set_dir_out_masked(pins & data->single_ended_mask & ~data->open_drain_mask); + gpio_set_dir_out_masked_n(PORT_NO(port), + pins & data->single_ended_mask & ~data->open_drain_mask); + return 0; } @@ -163,12 +258,16 @@ static int gpio_rpi_port_clear_bits_raw(const struct device *port, uint32_t pins) { struct gpio_rpi_data *data = port->data; + /* First handle push-pull pins: */ - gpio_clr_mask(pins & ~data->single_ended_mask); + gpio_clr_mask_n(PORT_NO(port), pins & ~data->single_ended_mask); /* Then handle open-drain pins: */ - gpio_set_dir_out_masked(pins & data->single_ended_mask & data->open_drain_mask); + gpio_set_dir_out_masked_n(PORT_NO(port), + pins & data->single_ended_mask & data->open_drain_mask); /* Then handle open-source pins: */ - gpio_set_dir_in_masked(pins & data->single_ended_mask & ~data->open_drain_mask); + gpio_set_dir_in_masked_n(PORT_NO(port), + pins & data->single_ended_mask & ~data->open_drain_mask); + return 0; } @@ -176,13 +275,12 @@ static int gpio_rpi_port_toggle_bits(const struct device *port, uint32_t pins) { struct gpio_rpi_data *data = port->data; + /* First handle push-pull pins: */ - gpio_xor_mask(pins & ~data->single_ended_mask); + gpio_xor_mask_n(PORT_NO(port), pins & ~data->single_ended_mask); /* Then handle single-ended pins: */ - /* (unfortunately there's no pico-sdk api call that can be used for this, - * but it's possible by accessing the registers directly) - */ - sio_hw->gpio_oe_togl = (pins & data->single_ended_mask); + gpio_toggle_dir_masked_n(PORT_NO(port), pins & data->single_ended_mask); + return 0; } @@ -191,10 +289,10 @@ static int gpio_rpi_pin_interrupt_configure(const struct device *dev, enum gpio_int_mode mode, enum gpio_int_trig trig) { - struct gpio_rpi_data *data = dev->data; + const int offset = GPIO_RPI_PINS_PER_PORT * PORT_NO(dev); uint32_t events = 0; - gpio_set_irq_enabled(pin, ALL_EVENTS, false); + gpio_set_irq_enabled(pin + offset, ALL_EVENTS, false); if (mode != GPIO_INT_DISABLE) { if (mode & GPIO_INT_EDGE) { if (trig & GPIO_INT_LOW_0) { @@ -211,9 +309,9 @@ static int gpio_rpi_pin_interrupt_configure(const struct device *dev, events |= GPIO_IRQ_LEVEL_HIGH; } } - gpio_set_irq_enabled(pin, events, true); + gpio_set_irq_enabled(pin + offset, events, true); } - WRITE_BIT(data->int_enabled_mask, pin, mode != GPIO_INT_DISABLE); + return 0; } @@ -296,6 +394,18 @@ static void gpio_rpi_isr(const struct device *dev) events = (*status_reg >> 4 * (pin % 8)) & ALL_EVENTS; if (events) { gpio_acknowledge_irq(pin, ALL_EVENTS); + +#if GPIO_RPI_HI_AVAILABLE + if (pin >= GPIO_RPI_PINS_PER_PORT) { + const struct gpio_rpi_config *config = dev->config; + struct gpio_rpi_data *high_data = config->high_dev->data; + + gpio_fire_callbacks(&high_data->callbacks, config->high_dev, + BIT(pin - GPIO_RPI_PINS_PER_PORT)); + continue; + } +#endif + gpio_fire_callbacks(&data->callbacks, dev, BIT(pin)); } } @@ -305,31 +415,56 @@ static int gpio_rpi_bank_init(const struct device *dev) { const struct gpio_rpi_config *config = dev->config; - config->bank_config_func(); + if (config->bank_config_func != NULL) { + config->bank_config_func(); + } + return 0; } -#define GPIO_RPI_INIT(idx) \ - static void bank_##idx##_config_func(void) \ - { \ - IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), \ - gpio_rpi_isr, DEVICE_DT_INST_GET(idx), 0); \ - irq_enable(DT_INST_IRQN(idx)); \ - } \ - static const struct gpio_rpi_config gpio_rpi_##idx##_config = { \ - .bank_config_func = bank_##idx##_config_func, \ - .common = \ - { \ - .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \ - } \ - }; \ - \ - static struct gpio_rpi_data gpio_rpi_##idx##_data; \ - \ - DEVICE_DT_INST_DEFINE(idx, gpio_rpi_bank_init, NULL, \ - &gpio_rpi_##idx##_data, \ - &gpio_rpi_##idx##_config, \ - POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ - &gpio_rpi_driver_api); +#define GPIO_REG_0U 1 +#define IS_GPIO_RPI_LO_NODE(n) UTIL_CAT(GPIO_REG_, DT_REG_ADDR(n)) + +#define DEVICE_IF_GPIO_RPI_HI_NODE(n) COND_CODE_1(IS_GPIO_RPI_LO_NODE(n), (), (DEVICE_DT_GET(n))) + +#define FIND_GPIO_RPI_HI_DEVICE(n) \ + COND_CODE_1(UTIL_CAT(GPIO_REG_, DT_REG_ADDR(n)), \ + (DT_FOREACH_CHILD(DT_PARENT(n), DEVICE_IF_GPIO_RPI_HI_NODE)), (NULL)) + +#if GPIO_RPI_HI_AVAILABLE +#define GPIO_RPI_INIT_HIGH_DEV(idx) .high_dev = FIND_GPIO_RPI_HI_DEVICE(DT_DRV_INST(idx)), +#else +#define GPIO_RPI_INIT_HIGH_DEV(idx) +#endif + +#define GPIO_RPI_INIT(idx) \ + BUILD_ASSERT(DT_CHILD_NUM(DT_INST_PARENT(idx)) > 0 && \ + DT_CHILD_NUM(DT_INST_PARENT(idx)) <= 2, \ + "raspberrypi,pico-gpio node must have one or two child node."); \ + BUILD_ASSERT(GPIO_RPI_LO_AVAILABLE, \ + "raspberrypi,pico-gpio node must have reg=0 child node."); \ + IF_ENABLED(IS_GPIO_RPI_LO_NODE(DT_DRV_INST(idx)), ( \ + static void bank_##idx##_config_func(void) \ + { \ + IRQ_CONNECT(DT_IRQN(DT_INST_PARENT(idx)), \ + DT_IRQ(DT_INST_PARENT(idx), priority), \ + gpio_rpi_isr, DEVICE_DT_INST_GET(idx), 0); \ + irq_enable(DT_IRQN(DT_INST_PARENT(idx))); \ + } \ + )) \ + static const struct gpio_rpi_config gpio_rpi_##idx##_config = { \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \ + }, \ + IF_ENABLED(IS_GPIO_RPI_LO_NODE(DT_DRV_INST(idx)), ( \ + .bank_config_func = bank_##idx##_config_func, \ + )) \ + GPIO_RPI_INIT_HIGH_DEV(idx) \ + }; \ + static struct gpio_rpi_data gpio_rpi_##idx##_data; \ + \ + DEVICE_DT_INST_DEFINE(idx, gpio_rpi_bank_init, NULL, &gpio_rpi_##idx##_data, \ + &gpio_rpi_##idx##_config, POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_rpi_driver_api); DT_INST_FOREACH_STATUS_OKAY(GPIO_RPI_INIT) diff --git a/dts/arm/raspberrypi/rpi_pico/rp2040.dtsi b/dts/arm/raspberrypi/rpi_pico/rp2040.dtsi index 6398674e0e0..9c20584c710 100644 --- a/dts/arm/raspberrypi/rpi_pico/rp2040.dtsi +++ b/dts/arm/raspberrypi/rpi_pico/rp2040.dtsi @@ -238,14 +238,27 @@ "gpin0", "gpin1"; }; - gpio0: gpio@40014000 { + gpio0_map: gpio@40014000 { compatible = "raspberrypi,pico-gpio"; reg = <0x40014000 DT_SIZE_K(4)>; interrupts = <13 RPI_PICO_DEFAULT_IRQ_PRIORITY>; - gpio-controller; + + gpio-map-mask = <0xffffffe0 0xffffffc0>; + gpio-map-pass-thru = <0x1f 0x3f>; + gpio-map = <0x0 0x0 &gpio0 0x0 0x0>; + #gpio-cells = <2>; - status = "disabled"; - ngpios = <30>; + #address-cells = <1>; + #size-cells = <0>; + + gpio0: gpio-port@0 { + compatible = "raspberrypi,pico-gpio-port"; + reg = <0x0>; + status = "disabled"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <30>; + }; }; uart0: uart@40034000 { diff --git a/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi b/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi index 687cafc19aa..4ddf435a7bc 100644 --- a/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi +++ b/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi @@ -235,13 +235,36 @@ "gpin0", "gpin1"; }; - gpio0: gpio@40028000 { + gpio0_map: gpio@40028000 { compatible = "raspberrypi,pico-gpio"; reg = <0x40028000 DT_SIZE_K(4)>; interrupts = <21 RPI_PICO_DEFAULT_IRQ_PRIORITY>; - gpio-controller; + + gpio-map-mask = <0xffffffe0 0xffffffc0>; + gpio-map-pass-thru = <0x1f 0x3f>; + gpio-map = <0x00 0x0 &gpio0 0x0 0x0 + 0x20 0x0 &gpio0_hi 0x0 0x0>; #gpio-cells = <2>; - status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + + gpio0: gpio-port@0 { + compatible = "raspberrypi,pico-gpio-port"; + reg = <0x0>; + status = "disabled"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + }; + + gpio0_hi: gpio-port@1 { + compatible = "raspberrypi,pico-gpio-port"; + reg = <0x1>; + status = "disabled"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + }; }; uart0: uart@40070000 { diff --git a/dts/bindings/gpio/raspberrypi,pico-gpio-port.yaml b/dts/bindings/gpio/raspberrypi,pico-gpio-port.yaml new file mode 100644 index 00000000000..fb4c9e4e737 --- /dev/null +++ b/dts/bindings/gpio/raspberrypi,pico-gpio-port.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2021, Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +description: Raspberry Pi Pico GPIO Port + +compatible: "raspberrypi,pico-gpio-port" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/raspberrypi,pico-gpio.yaml b/dts/bindings/gpio/raspberrypi,pico-gpio.yaml index 89afb5084b5..dc441964a7b 100644 --- a/dts/bindings/gpio/raspberrypi,pico-gpio.yaml +++ b/dts/bindings/gpio/raspberrypi,pico-gpio.yaml @@ -1,19 +1,8 @@ -# Copyright (c) 2021, Yonatan Schachter +# Copyright (c) 2024 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 description: Raspberry Pi Pico GPIO compatible: "raspberrypi,pico-gpio" -include: [gpio-controller.yaml, base.yaml] - -properties: - reg: - required: true - - "#gpio-cells": - const: 2 - -gpio-cells: - - pin - - flags +include: [gpio-nexus.yaml, base.yaml]