Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boards/arm/rpi_pico/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ co-processors that are designed for I/O operations. The PIOs run
a custom instruction set, generated from a custom assembly language.
PIO programs are assembled using `pioasm`, a tool provided by Raspberry Pi.

Zephyr does not (currently) assemble PIO programs. Rather, they should be
Zephyr does not assemble PIO programs. Rather, they should be
manually assembled and embedded in source code. An example of how this is done
can be found at `drivers/serial/uart_rpi_pico_pio.c`.

Expand Down
1 change: 1 addition & 0 deletions drivers/misc/pio_rpi_pico/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Copyright (c) 2023 Ionut Pavel <[email protected]>
# Copyright (c) 2023 TOKITA Hiroshi <[email protected]>
# SPDX-License-Identifier: Apache-2.0

Expand Down
19 changes: 17 additions & 2 deletions drivers/misc/pio_rpi_pico/Kconfig
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
# Copyright (c) 2023 Ionut Pavel <[email protected]>
# Copyright (c) 2023 TOKITA Hiroshi <[email protected]>
# SPDX-License-Identifier: Apache-2.0

config PIO_RPI_PICO
bool "RaspberryPi Pico PIO"
default y
depends on DT_HAS_RASPBERRYPI_PICO_PIO_ENABLED
depends on RESET
select PICOSDK_USE_PIO

if PIO_RPI_PICO

module = PIO_RPI_PICO
module-str = pio_rpi_pico
source "subsys/logging/Kconfig.template.log_config"

config PIO_RPI_PICO_INSTR_COUNT
int "Number of Program Instructions for each PIO"
default 32 if SOC_RP2040

config PIO_RPI_PICO_SM_COUNT
int "Number of State Machine instances for each PIO"
default 4 if SOC_RP2040

endif
221 changes: 199 additions & 22 deletions drivers/misc/pio_rpi_pico/pio_rpi_pico.c
Original file line number Diff line number Diff line change
@@ -1,53 +1,230 @@
/*
/**
* Copyright (c) 2023, Ionut Pavel <[email protected]>
* Copyright (c) 2023 Tokita, Hiroshi <[email protected]>
* Copyright (c) 2023 Yonatan Schachter
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <hardware/structs/pio.h>
#include <zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h>
#include <zephyr/drivers/pinctrl.h>

#define DT_DRV_COMPAT raspberrypi_pico_pio
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(pio_rpi_pico, CONFIG_PIO_RPI_PICO_LOG_LEVEL);

#define DT_DRV_COMPAT raspberrypi_pico_pio

typedef void (*pio_rpi_pico_irq_config_func_t)(void);

struct pio_rpi_pico_irq_config {
pio_rpi_pico_irq_config_func_t irq_config;
uint irq_map;
};

struct pio_rpi_pico_config {
PIO pio;
const struct pio_rpi_pico_irq_config *irq_configs;
sys_slist_t *irq_lists;
uint8_t irq_cnt;
};

int pio_rpi_pico_allocate_sm(const struct device *dev, size_t *sm)
struct pio_rpi_pico_data {
/**
* The maximum shared instruction scheme is SM count dependent.
*/
const char *shared_key[CONFIG_PIO_RPI_PICO_SM_COUNT / 2];
uint8_t shared_instr[CONFIG_PIO_RPI_PICO_SM_COUNT / 2];

uint8_t alloc_sm;
uint8_t alloc_instr;
};

int pio_rpi_pico_alloc_sm(const struct device *dev, size_t count, uint8_t *sm)
{
const struct pio_rpi_pico_config *config = dev->config;
int retval;
struct pio_rpi_pico_data *data = dev->data;
size_t available;

retval = pio_claim_unused_sm(config->pio, false);
if (retval < 0) {
return -EBUSY;
__ASSERT_NO_MSG(sm);
__ASSERT_NO_MSG(count);

available = CONFIG_PIO_RPI_PICO_SM_COUNT - data->alloc_sm;

if (available < count) {
return -EIO;
}

*sm = (size_t)retval;
*sm = data->alloc_sm;
data->alloc_sm += (uint8_t)count;

return 0;
}

PIO pio_rpi_pico_get_pio(const struct device *dev)
int pio_rpi_pico_alloc_instr(const struct device *dev, size_t count, uint8_t *instr)
{
struct pio_rpi_pico_data *data = dev->data;
size_t available;

__ASSERT_NO_MSG(instr);
__ASSERT_NO_MSG(count);

available = CONFIG_PIO_RPI_PICO_INSTR_COUNT - data->alloc_instr;

if (available < count) {
return -ENOMEM;
}

*instr = data->alloc_instr;
data->alloc_instr += (uint8_t)count;

return 0;
}

int pio_rpi_pico_alloc_shared_instr(const struct device *dev, const char *key,
size_t count, uint8_t *instr)
{
struct pio_rpi_pico_data *data = dev->data;
uint8_t i;
int rc;

__ASSERT_NO_MSG(dev);
__ASSERT_NO_MSG(key);
__ASSERT_NO_MSG(instr);
__ASSERT_NO_MSG(count);

for (i = 0u; i < (CONFIG_PIO_RPI_PICO_SM_COUNT / 2); i++) {

if (!data->shared_key[i]) {
rc = pio_rpi_pico_alloc_instr(dev, count, instr);
if (rc < 0) {
return rc;
}

data->shared_instr[i] = *instr;
data->shared_key[i] = key;
return 0;

} else if (strcmp(data->shared_key[i], key) == 0) {
*instr = data->shared_instr[i];
return -EALREADY;
}
}

return -ENOMEM;
}

void pio_rpi_pico_irq_register(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg)
{
const struct pio_rpi_pico_config *config = dev->config;

return config->pio;
__ASSERT_NO_MSG(dev);
__ASSERT_NO_MSG(cfg);
__ASSERT_NO_MSG(cfg->irq_idx < config->irq_cnt);

sys_slist_append(&config->irq_lists[cfg->irq_idx], (sys_snode_t *)cfg);
}

void pio_rpi_pico_irq_enable(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg)
{
const struct pio_rpi_pico_config *config = dev->config;

__ASSERT_NO_MSG(dev);
__ASSERT_NO_MSG(cfg);
__ASSERT_NO_MSG(cfg->irq_idx < config->irq_cnt);

cfg->enabled = true;

/* Just enable the line. Doesn't really matter if already enabled */
irq_enable(config->irq_configs[cfg->irq_idx].irq_map);
}

void pio_rpi_pico_irq_disable(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg)
{
const struct pio_rpi_pico_config *config = dev->config;
struct pio_rpi_pico_irq_cfg *irq_cfg;
sys_snode_t *pnode;

__ASSERT_NO_MSG(dev);
__ASSERT_NO_MSG(cfg);
__ASSERT_NO_MSG(cfg->irq_idx < config->irq_cnt);

cfg->enabled = false;

/* Return if not last one */
SYS_SLIST_FOR_EACH_NODE(&config->irq_lists[cfg->irq_idx], pnode) {
irq_cfg = CONTAINER_OF(pnode, struct pio_rpi_pico_irq_cfg, node);
if ((irq_cfg != cfg) && irq_cfg->enabled) {
return;
}
}

irq_disable(config->irq_configs[cfg->irq_idx].irq_map);
}

static int pio_rpi_pico_init(const struct device *dev)
{
const struct pio_rpi_pico_config *config = dev->config;
uint8_t i;

for (i = 0u; i < config->irq_cnt; i++) {
sys_slist_init(&config->irq_lists[i]);
config->irq_configs[i].irq_config();
}

return 0;
}

#define RPI_PICO_PIO_INIT(idx) \
static const struct pio_rpi_pico_config pio_rpi_pico_config_##idx = { \
.pio = (PIO)DT_INST_REG_ADDR(idx), \
}; \
\
DEVICE_DT_INST_DEFINE(idx, &pio_rpi_pico_init, NULL, NULL, \
&pio_rpi_pico_config_##idx, PRE_KERNEL_2, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL);
static void pio_rpi_pico_irq(sys_slist_t *irq_list)
{
struct pio_rpi_pico_irq_cfg *irq_cfg;
sys_snode_t *pnode;

SYS_SLIST_FOR_EACH_NODE(irq_list, pnode) {
irq_cfg = CONTAINER_OF(pnode, struct pio_rpi_pico_irq_cfg, node);
if (irq_cfg->enabled) {
irq_cfg->irq_func(irq_cfg->irq_param);
}
}
}

#define PIO_RPI_PICO_IRQ_CONFIG_FUNC(idx, inst) \
static void pio_rpi_pico_irq_config##inst##_##idx(void) \
{ \
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, idx, irq), \
DT_INST_IRQ_BY_IDX(inst, idx, priority), \
pio_rpi_pico_irq, \
&pio_rpi_pico_irq_data##inst[idx], (0)); \
}

#define PIO_RPI_PICO_IRQ_CONFIG_DATA(idx, inst) \
{ \
.irq_config = pio_rpi_pico_irq_config##inst##_##idx, \
.irq_map = DT_INST_IRQ_BY_IDX(inst, idx, irq), \
}

#define PIO_RPI_PICO_INIT(inst) \
static sys_slist_t pio_rpi_pico_irq_data##inst[DT_NUM_IRQS(DT_DRV_INST(inst))]; \
LISTIFY(DT_NUM_IRQS(DT_DRV_INST(inst)), PIO_RPI_PICO_IRQ_CONFIG_FUNC, (), inst) \
\
static struct pio_rpi_pico_data pio_rpi_pico_data##inst; \
\
static const struct pio_rpi_pico_irq_config \
pio_rpi_pico_irq_config##inst[DT_NUM_IRQS(DT_DRV_INST(inst))] = \
{LISTIFY(DT_NUM_IRQS(DT_DRV_INST(inst)), PIO_RPI_PICO_IRQ_CONFIG_DATA, (,), inst)}; \
\
static const struct pio_rpi_pico_config pio_rpi_pico_config##inst = { \
.irq_configs = pio_rpi_pico_irq_config##inst, \
.irq_lists = pio_rpi_pico_irq_data##inst, \
.irq_cnt = DT_NUM_IRQS(DT_DRV_INST(inst)), \
}; \
\
DEVICE_DT_INST_DEFINE(inst, &pio_rpi_pico_init, \
NULL, \
&pio_rpi_pico_data##inst, \
&pio_rpi_pico_config##inst, \
PRE_KERNEL_1, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
NULL);

DT_INST_FOREACH_STATUS_OKAY(RPI_PICO_PIO_INIT)
DT_INST_FOREACH_STATUS_OKAY(PIO_RPI_PICO_INIT);
3 changes: 1 addition & 2 deletions drivers/serial/Kconfig.rpi_pico
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,5 @@ config UART_RPI_PICO_PIO
default y
depends on DT_HAS_RASPBERRYPI_PICO_UART_PIO_ENABLED
select SERIAL_HAS_DRIVER
select PICOSDK_USE_PIO
select PICOSDK_USE_CLAIM
select SERIAL_SUPPORT_INTERRUPT
depends on RESET
Loading