From ea4836381af10b232b731230db97692eec3b0ac4 Mon Sep 17 00:00:00 2001 From: Germain Haugou Date: Tue, 29 Apr 2025 08:31:00 +0200 Subject: [PATCH] hyperbus: added support for multiple transfers in hyperbus driver --- .../pulp/drivers/hyperbus/hyperbus-v3.c | 382 +++++++++++------- rtos/pulpos/pulp/include/pos/data/hyperbus.h | 13 +- 2 files changed, 254 insertions(+), 141 deletions(-) diff --git a/rtos/pulpos/pulp/drivers/hyperbus/hyperbus-v3.c b/rtos/pulpos/pulp/drivers/hyperbus/hyperbus-v3.c index 73e83782..72fe27d2 100644 --- a/rtos/pulpos/pulp/drivers/hyperbus/hyperbus-v3.c +++ b/rtos/pulpos/pulp/drivers/hyperbus/hyperbus-v3.c @@ -14,28 +14,77 @@ * limitations under the License. */ -/* +/* * Authors: Nazareno Bruschi, Unibo (nazareno.bruschi@unibo.it) */ #include "pmsis.h" -static PI_L2 pos_hyper_t pos_hyper[HYPER_NB_CS * ARCHI_UDMA_NB_HYPER]; +static PI_L2 pos_hyper_t pos_hyper[ARCHI_UDMA_NB_HYPER]; +static PI_L2 pos_hyper_cs_t pos_hyper_cs[HYPER_NB_CS * ARCHI_UDMA_NB_HYPER]; static PI_L2 int hyper_open_count=0; static PI_L2 int hyper_channel; static PI_L2 pos_udma_channel_t hyper_tx_channel; static PI_L2 pos_udma_channel_t hyper_rx_channel; -static void pos_hyper_setup(pos_hyper_t *hyper) +#define HYPER_PENDING_READ 0 +#define HYPER_PENDING_READ_2D 1 +#define HYPER_PENDING_WRITE 2 +#define HYPER_PENDING_WRITE_2D 3 +#define HYPER_PENDING_READ_BI2D 4 +#define HYPER_PENDING_WRITE_BI2D 5 + +static void __pi_hyper_read_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t arg0, uint32_t arg1, uint32_t arg2); +static void __pi_hyper_read_2d_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4); +static void __pi_hyper_write_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t arg0, uint32_t arg1, uint32_t arg2); +static void __pi_hyper_write_2d_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4); +static void __pi_hyper_read_bi2d_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5); +static void __pi_hyper_write_bi2d_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5); + +static void (*__pi_hyper_exec_handlers[])(pos_hyper_t *hyper, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) = +{ + (void (*)(pos_hyper_t *hyper, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))__pi_hyper_read_exec, + (void (*)(pos_hyper_t *hyper, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))__pi_hyper_read_2d_exec, + (void (*)(pos_hyper_t *hyper, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))__pi_hyper_write_exec, + (void (*)(pos_hyper_t *hyper, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))__pi_hyper_write_2d_exec, + (void (*)(pos_hyper_t *hyper, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))__pi_hyper_read_bi2d_exec, + (void (*)(pos_hyper_t *hyper, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))__pi_hyper_write_bi2d_exec, +}; + +static __attribute__((noinline)) void __pi_hyper_enqueue_pending(pos_hyper_t *hyper, uint32_t arg0, + uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, uint32_t arg6, pi_task_t *task, uint32_t id) +{ + task->data[0] = id; + task->data[1] = arg0; + task->data[2] = arg1; + task->data[3] = arg2; + task->data[4] = arg3; + task->data[5] = arg4; + task->data[6] = arg5; + task->data[7] = arg6; + + hyper->waiting_last->next = task; + hyper->waiting_last = task; + task->next = NULL; +} + +static inline __attribute__((always_inline)) void __pi_hyper_add_first(pos_hyper_t *hyper, pi_task_t *task) +{ + hyper->waiting_first = task; + hyper->waiting_last = task; + task->next = NULL; +} + +static void pos_hyper_setup(pos_hyper_t *hyper, int cs) { if (hyper->type == PI_HYPER_TYPE_FLASH) { - plp_hyper_setup(hyper->hyper_id, CONFIG_HYPERFLASH_EN_LATENCY_ADD, hyper->cs, CONFIG_HYPERFLASH_T_LATENCY_ACCESS); + plp_hyper_setup(hyper->hyper_id, CONFIG_HYPERFLASH_EN_LATENCY_ADD, cs, CONFIG_HYPERFLASH_T_LATENCY_ACCESS); plp_hyper_set_reg(UDMA_HYPER_BASE_ADDR(0) + REG_PAGE_BOUND, 0x04); } else if (hyper->type == PI_HYPER_TYPE_RAM) { - plp_hyper_setup(hyper->hyper_id, CONFIG_HYPERRAM_EN_LATENCY_ADD, hyper->cs, CONFIG_HYPERRAM_T_LATENCY_ACCESS); + plp_hyper_setup(hyper->hyper_id, CONFIG_HYPERRAM_EN_LATENCY_ADD, cs, CONFIG_HYPERRAM_T_LATENCY_ACCESS); plp_hyper_set_reg(UDMA_HYPER_BASE_ADDR(0) + REG_PAGE_BOUND, 0x03); } } @@ -53,69 +102,25 @@ static void pos_hyper_wait_done(pos_hyper_t *hyper) } } -void pos_hyper_enqueue(pos_udma_channel_t *channel, pi_task_t *task, uint32_t offset, uint32_t buffer, uint32_t size, uint32_t cfg) -{ - // A UDMA channel has 2 slots, enqueue the copy to the UDMA if one of them is available, otherwise - // put the transfer on hold. - if (channel->pendings[0] == NULL) - { - channel->pendings[0] = task; - plp_hyper_enqueue(offset, buffer, size, UDMA_CHANNEL_CFG_EN | cfg); - } - else if (channel->pendings[1] == NULL) - { - channel->pendings[1] = task; - plp_hyper_enqueue(offset, buffer, size, UDMA_CHANNEL_CFG_EN | cfg); - } - else - { - task->data[0] = buffer; - task->data[1] = size; - task->data[2] = cfg; - - task->data[3] = offset; - - if (channel->waitings_first == NULL) - channel->waitings_first = task; - else - channel->waitings_last->next = task; - - channel->waitings_last = task; - task->next = NULL; - } -} - void pos_hyper_handle_copy(int event, void *arg) { - pos_udma_channel_t *channel = arg; + pos_hyper_t *hyper = (pos_hyper_t *)arg; - pi_task_t *pending_1 = channel->pendings[1]; - pi_task_t *pending_0 = channel->pendings[0]; - pi_task_t *pending_first = channel->waitings_first; - channel->pendings[0] = pending_1; + pi_task_t *task = hyper->waiting_first; - if (pending_first) - { - channel->waitings_first = pending_first->next; - channel->pendings[1] = pending_first; + if (task) + { + pi_task_t *next = task->next; + hyper->waiting_first = next; - plp_hyper_enqueue(pending_first->data[3], pending_first->data[0], pending_first->data[1], UDMA_CHANNEL_CFG_EN | pending_first->data[2]); - } - else + if (next) { - channel->pendings[1] = NULL; + __pi_hyper_exec_handlers[next->data[0]](hyper, next->data[1], next->data[2], next->data[3], + next->data[4], next->data[5], next->data[6], next->data[7]); } - pos_task_push_locked(pending_0); -} - -void pos_hyper_create_channel(pos_udma_channel_t *channel, int channel_id, int soc_event) -{ - pos_soc_event_register_callback(soc_event, pos_hyper_handle_copy, (void *)channel); - channel->pendings[0] = NULL; - channel->pendings[1] = NULL; - channel->waitings_first = NULL; - channel->base = hal_udma_channel_base(channel_id); + pos_task_push_locked(task); + } } void pi_hyper_conf_init(struct pi_hyper_conf *conf) @@ -134,30 +139,34 @@ int32_t pi_hyper_open(struct pi_device *device) hyper_channel = UDMA_EVENT_ID(periph_id); int cs = conf->cs; - pos_hyper_t *hyper = &pos_hyper[hyper_id + cs]; + pos_hyper_t *hyper = &pos_hyper[hyper_id]; + pos_hyper_cs_t *hyper_cs = &pos_hyper_cs[hyper_id + cs]; - hyper->hyper_id = conf->id; - hyper->type = conf->type; - hyper->cs = cs; - hyper->tran_id = 0; + hyper_open_count++; - hyper->rx_channel = &hyper_rx_channel; - hyper->tx_channel = &hyper_tx_channel; + if (hyper_open_count == 1) + { + hyper->waiting_first = NULL; + hyper->hyper_id = conf->id; + hyper->type = conf->type; + hyper->tran_id = 0; - device->data = (void *)hyper; + hyper->rx_channel = &hyper_rx_channel; + hyper->tx_channel = &hyper_tx_channel; - if (hyper_open_count == 0) - { - pos_hyper_create_channel(hyper->rx_channel, UDMA_CHANNEL_ID(periph_id), hyper_channel + ARCHI_UDMA_HYPER_EOT_RX_EVT); - pos_hyper_create_channel(hyper->tx_channel, UDMA_CHANNEL_ID(periph_id)+1, hyper_channel + ARCHI_UDMA_HYPER_EOT_TX_EVT); - } + pos_soc_event_register_callback(hyper_channel + ARCHI_UDMA_HYPER_EOT_RX_EVT, pos_hyper_handle_copy, (void *)hyper); + pos_soc_event_register_callback(hyper_channel + ARCHI_UDMA_HYPER_EOT_TX_EVT, pos_hyper_handle_copy, (void *)hyper); - hyper_open_count++; + plp_udma_cg_set(plp_udma_cg_get() | (1<cs = cs; + hyper_cs->hyper = hyper; - soc_eu_fcEventMask_setEvent(hyper_channel+ ARCHI_UDMA_HYPER_EOT_RX_EVT); - soc_eu_fcEventMask_setEvent(hyper_channel + ARCHI_UDMA_HYPER_EOT_TX_EVT); + device->data = (void *)hyper_cs; hal_irq_restore(irq); @@ -168,7 +177,8 @@ void pi_hyper_close(struct pi_device *device) { int irq = hal_irq_disable(); - pos_hyper_t *hyper = (pos_hyper_t *)device->data; + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; struct pi_hyper_conf *conf = (struct pi_hyper_conf *)device->config; unsigned char hyper_id = conf->id; @@ -196,7 +206,9 @@ int pi_hyper_ioctl(struct pi_device *device, uint32_t cmd, void *arg) return -1; else { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; + hyper->tran_id = tran_id; } break; @@ -205,9 +217,8 @@ int pi_hyper_ioctl(struct pi_device *device, uint32_t cmd, void *arg) return 0; } -void pi_hyper_set_regs(struct pi_device *device, uint32_t cmd, void *arg) +static void __pi_hyper_set_regs(pos_hyper_t *hyper, uint32_t cmd, void *arg) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; uint32_t offset = UDMA_HYPER_BASE_ADDR(hyper->hyper_id); switch (cmd) @@ -219,7 +230,7 @@ void pi_hyper_set_regs(struct pi_device *device, uint32_t cmd, void *arg) offset += REG_EN_LATENCY_ADD; break; case PI_HYPER_T_CS_MAX: - offset += REG_T_CS_MAX; + offset += REG_T_CS_MAX; break; case PI_HYPER_MEM_SEL: offset += MEM_SEL; @@ -243,14 +254,23 @@ void pi_hyper_set_regs(struct pi_device *device, uint32_t cmd, void *arg) plp_hyper_set_ctl_param(hyper->hyper_id, (unsigned int *)arg, hyper->tran_id); break; default: - plp_hyper_set_reg(offset, *(unsigned int *)arg); + plp_hyper_set_reg(offset, *(unsigned int *)arg); break; } } +void pi_hyper_set_regs(struct pi_device *device, uint32_t cmd, void *arg) +{ + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; + + __pi_hyper_set_regs(hyper, cmd, arg); +} + int pi_hyper_ctl_status_regs(struct pi_device *device, uint32_t cmd, void *arg) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; if (arg != NULL) { @@ -275,142 +295,228 @@ void pi_hyper_read(struct pi_device *device, uint32_t hyper_addr, void *addr, ui pi_task_wait_on(&task); } -void pi_hyper_read_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, struct pi_task *task) +static void __pi_hyper_read_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t hyper_addr, uint32_t addr, + uint32_t size) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; - unsigned int twd_cmd[HYPER_NB_TWD_REGS] = {0,0,0,0,0,0}; unsigned int ctl_cmd[HYPER_NB_CTL_REGS] = {0x5, hyper_addr}; - pos_hyper_setup(hyper); + pos_hyper_setup(hyper, cs); hyper->tran_id = plp_hyper_id_alloc(hyper->hyper_id); - pi_hyper_set_regs(device, PI_HYPER_TWD, (unsigned int *)twd_cmd); - pi_hyper_set_regs(device, PI_HYPER_CTL, (unsigned int *)ctl_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_TWD, (unsigned int *)twd_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_CTL, (unsigned int *)ctl_cmd); - pos_hyper_enqueue(hyper->rx_channel, task, UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_RX(hyper->tran_id), (uint32_t)addr, size, UDMA_CHANNEL_CFG_SIZE_8); + plp_hyper_enqueue(UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_RX(hyper->tran_id), + (uint32_t)addr, size, UDMA_CHANNEL_CFG_EN | UDMA_CHANNEL_CFG_SIZE_8); +} + +void pi_hyper_read_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, struct pi_task *task) +{ + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; + + if (hyper->waiting_first != NULL) + { + __pi_hyper_enqueue_pending(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, 0, 0, 0, task, HYPER_PENDING_READ); + return; + } + + __pi_hyper_add_first(hyper, task); + + __pi_hyper_read_exec(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size); } void pi_hyper_read_2d(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t stride, uint32_t length) { pi_task_t task; pi_hyper_read_2d_async(device, hyper_addr, addr, size, stride, length, pi_task_block(&task)); - pi_task_wait_on(&task); + pi_task_wait_on(&task); } -void pi_hyper_read_2d_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t stride, uint32_t length, struct pi_task *task) +static void __pi_hyper_read_2d_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t hyper_addr, uint32_t addr, + uint32_t size, uint32_t stride, uint32_t length) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; - unsigned int twd_cmd[HYPER_NB_TWD_REGS] = {1,length,stride,0,length,stride}; unsigned int ctl_cmd[HYPER_NB_CTL_REGS] = {0x5, hyper_addr}; - pos_hyper_setup(hyper); + pos_hyper_setup(hyper, cs); hyper->tran_id = plp_hyper_id_alloc(hyper->hyper_id); - pi_hyper_set_regs(device, PI_HYPER_TWD, (unsigned int *)twd_cmd); - pi_hyper_set_regs(device, PI_HYPER_CTL, (unsigned int *)ctl_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_TWD, (unsigned int *)twd_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_CTL, (unsigned int *)ctl_cmd); - pos_hyper_enqueue(hyper->rx_channel, task, UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_RX(hyper->tran_id), (uint32_t)addr, size, UDMA_CHANNEL_CFG_SIZE_8); + plp_hyper_enqueue(UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_RX(hyper->tran_id), + (uint32_t)addr, size, UDMA_CHANNEL_CFG_EN | UDMA_CHANNEL_CFG_SIZE_8); } -void pi_hyper_read_bi2d_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t dir, uint32_t stride, uint32_t length, struct pi_task *task) +void pi_hyper_read_2d_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t stride, uint32_t length, struct pi_task *task) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; + + if (hyper->waiting_first != NULL) + { + __pi_hyper_enqueue_pending(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, stride, length, 0, task, HYPER_PENDING_READ_2D); + return; + } + __pi_hyper_add_first(hyper, task); + + __pi_hyper_read_2d_exec(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, stride, length); +} + +static void __pi_hyper_read_bi2d_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t hyper_addr, uint32_t addr, + uint32_t size, uint32_t dir, uint32_t stride, uint32_t length) +{ unsigned int twd_cmd[HYPER_NB_TWD_REGS] = {((0x0^dir) & 0x1),length,stride,((0x1^dir) & 0x1),length,stride}; unsigned int ctl_cmd[HYPER_NB_CTL_REGS] = {0x5, hyper_addr}; - pos_hyper_setup(hyper); + pos_hyper_setup(hyper, cs); hyper->tran_id = plp_hyper_id_alloc(hyper->hyper_id); - pi_hyper_set_regs(device, PI_HYPER_TWD, (unsigned int *)twd_cmd); - pi_hyper_set_regs(device, PI_HYPER_CTL, (unsigned int *)ctl_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_TWD, (unsigned int *)twd_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_CTL, (unsigned int *)ctl_cmd); - pos_hyper_enqueue(hyper->rx_channel, task, UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_RX(hyper->tran_id), (uint32_t)addr, size, UDMA_CHANNEL_CFG_SIZE_8); + plp_hyper_enqueue(UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_RX(hyper->tran_id), + (uint32_t)addr, size, UDMA_CHANNEL_CFG_EN | UDMA_CHANNEL_CFG_SIZE_8); } -void pi_hyper_write(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size) +void pi_hyper_read_bi2d_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t dir, uint32_t stride, uint32_t length, struct pi_task *task) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; - unsigned int twd_cmd[HYPER_NB_TWD_REGS] = {0,0,0,0,0,0}; - unsigned int ctl_cmd[HYPER_NB_CTL_REGS] = {0x0, hyper_addr}; - - pos_hyper_setup(hyper); - - while(plp_hyper_nb_tran(hyper->hyper_id, hyper->tran_id)>HYPER_FIFO_DEPTH-1){} + if (hyper->waiting_first != NULL) + { + __pi_hyper_enqueue_pending(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, dir, stride, length, task, HYPER_PENDING_READ_BI2D); + return; + } - pi_hyper_set_regs(device, PI_HYPER_TWD, (unsigned int *)twd_cmd); - pi_hyper_set_regs(device, PI_HYPER_CTL, (unsigned int *)ctl_cmd); - pi_hyper_set_regs(device, PI_HYPER_CFG, (unsigned short *)addr); + __pi_hyper_add_first(hyper, task); - plp_hyper_enqueue(UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_TX(hyper->tran_id), 0x0, 0x0, UDMA_CHANNEL_CFG_EN | UDMA_CHANNEL_CFG_SIZE_8); + __pi_hyper_read_bi2d_exec(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, dir, stride, length); } -void pi_hyper_write_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, struct pi_task *task) +void pi_hyper_write(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; + pi_task_t task; + pi_hyper_write_async(device, hyper_addr, addr, size, pi_task_block(&task)); + pi_task_wait_on(&task); +} +static void __pi_hyper_write_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t hyper_addr, uint32_t addr, uint32_t size) +{ unsigned int twd_cmd[HYPER_NB_TWD_REGS] = {0,0,0,0,0,0}; unsigned int ctl_cmd[HYPER_NB_CTL_REGS] = {0x1, hyper_addr}; - pos_hyper_setup(hyper); + pos_hyper_setup(hyper, cs); hyper->tran_id = plp_hyper_id_alloc(hyper->hyper_id); - pi_hyper_set_regs(device, PI_HYPER_TWD, (unsigned int *)twd_cmd); - pi_hyper_set_regs(device, PI_HYPER_CTL, (unsigned int *)ctl_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_TWD, (unsigned int *)twd_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_CTL, (unsigned int *)ctl_cmd); - pos_hyper_enqueue(hyper->tx_channel, task, UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_TX(hyper->tran_id), (uint32_t)addr, size, UDMA_CHANNEL_CFG_SIZE_8); + plp_hyper_enqueue(UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_TX(hyper->tran_id), + (uint32_t)addr, size, UDMA_CHANNEL_CFG_EN | UDMA_CHANNEL_CFG_SIZE_8); +} + +void pi_hyper_write_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, struct pi_task *task) +{ + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; + + if (hyper->waiting_first != NULL) + { + __pi_hyper_enqueue_pending(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, 0, 0, 0, task, HYPER_PENDING_WRITE); + return; + } + + __pi_hyper_add_first(hyper, task); + + __pi_hyper_write_exec(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size); } void pi_hyper_write_2d(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t stride, uint32_t length) { pi_task_t task; pi_hyper_write_2d_async(device, hyper_addr, addr, size, stride, length, pi_task_block(&task)); - pi_task_wait_on(&task); + pi_task_wait_on(&task); } -void pi_hyper_write_2d_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t stride, uint32_t length, struct pi_task *task) +static void __pi_hyper_write_2d_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t hyper_addr, uint32_t addr, + uint32_t size, uint32_t stride, uint32_t length) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; - unsigned int twd_cmd[HYPER_NB_TWD_REGS] = {1,length,stride,0,length,stride}; unsigned int ctl_cmd[HYPER_NB_CTL_REGS] = {0x1, hyper_addr}; - pos_hyper_setup(hyper); + pos_hyper_setup(hyper, cs); hyper->tran_id = plp_hyper_id_alloc(hyper->hyper_id); - pi_hyper_set_regs(device, PI_HYPER_TWD, (unsigned int *)twd_cmd); - pi_hyper_set_regs(device, PI_HYPER_CTL, (unsigned int *)ctl_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_TWD, (unsigned int *)twd_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_CTL, (unsigned int *)ctl_cmd); - pos_hyper_enqueue(hyper->tx_channel, task, UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_TX(hyper->tran_id), (uint32_t)addr, size, UDMA_CHANNEL_CFG_SIZE_8); + plp_hyper_enqueue(UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_TX(hyper->tran_id), + (uint32_t)addr, size, UDMA_CHANNEL_CFG_EN | UDMA_CHANNEL_CFG_SIZE_8); } -void pi_hyper_write_bi2d_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t dir, uint32_t stride, uint32_t length, struct pi_task *task) +void pi_hyper_write_2d_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t stride, uint32_t length, struct pi_task *task) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; + + if (hyper->waiting_first != NULL) + { + __pi_hyper_enqueue_pending(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, stride, length, 0, task, HYPER_PENDING_WRITE_2D); + return; + } + + __pi_hyper_add_first(hyper, task); + __pi_hyper_write_2d_exec(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, stride, length); +} + +static void __pi_hyper_write_bi2d_exec(pos_hyper_t *hyper, uint32_t cs, uint32_t hyper_addr, uint32_t addr, + uint32_t size, uint32_t dir, uint32_t stride, uint32_t length) +{ unsigned int twd_cmd[HYPER_NB_TWD_REGS] = {((0x0^dir) & 0x1),length,stride,((0x1^dir) & 0x1),length,stride}; unsigned int ctl_cmd[HYPER_NB_CTL_REGS] = {0x1, hyper_addr}; - pos_hyper_setup(hyper); + pos_hyper_setup(hyper, cs); hyper->tran_id = plp_hyper_id_alloc(hyper->hyper_id); - pi_hyper_set_regs(device, PI_HYPER_TWD, (unsigned int *)twd_cmd); - pi_hyper_set_regs(device, PI_HYPER_CTL, (unsigned int *)ctl_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_TWD, (unsigned int *)twd_cmd); + __pi_hyper_set_regs(hyper, PI_HYPER_CTL, (unsigned int *)ctl_cmd); - pos_hyper_enqueue(hyper->tx_channel, task, UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_TX(hyper->tran_id), (uint32_t)addr, size, UDMA_CHANNEL_CFG_SIZE_8); + plp_hyper_enqueue(UDMA_HYPER_BASE_ADDR(hyper->hyper_id) + UDMA_HYPER_CHANNEL_TX(hyper->tran_id), + (uint32_t)addr, size, UDMA_CHANNEL_CFG_EN | UDMA_CHANNEL_CFG_SIZE_8); +} + +void pi_hyper_write_bi2d_async(struct pi_device *device, uint32_t hyper_addr, void *addr, uint32_t size, uint32_t dir, uint32_t stride, uint32_t length, struct pi_task *task) +{ + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; + + if (hyper->waiting_first != NULL) + { + __pi_hyper_enqueue_pending(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, dir, stride, length, task, HYPER_PENDING_WRITE_BI2D); + return; + } + + __pi_hyper_add_first(hyper, task); + + __pi_hyper_write_bi2d_exec(hyper, hyper_cs->cs, hyper_addr, (uint32_t)addr, size, dir, stride, length); } int pi_hyper_id_alloc(struct pi_device *device) { - pos_hyper_t *hyper = (pos_hyper_t *)device->data; + pos_hyper_cs_t *hyper_cs = (pos_hyper_cs_t *)device->data; + pos_hyper_t *hyper = hyper_cs->hyper; + return plp_hyper_id_alloc(hyper->hyper_id); } diff --git a/rtos/pulpos/pulp/include/pos/data/hyperbus.h b/rtos/pulpos/pulp/include/pos/data/hyperbus.h index 67c61d12..089a9bf2 100644 --- a/rtos/pulpos/pulp/include/pos/data/hyperbus.h +++ b/rtos/pulpos/pulp/include/pos/data/hyperbus.h @@ -14,7 +14,7 @@ * limitations under the License. */ -/* +/* * Authors: Nazareno Bruschi, Unibo (nazareno.bruschi@unibo.it) */ @@ -37,12 +37,19 @@ typedef struct pos_hyper_s unsigned int baudrate; int active; pi_hyper_type_e type; - uint32_t cs; signed char hyper_id; uint32_t tran_id; + pi_task_t *waiting_first; + pi_task_t *waiting_last; } pos_hyper_t; +typedef struct pos_hyper_cs_s +{ + uint32_t cs; + pos_hyper_t *hyper; +} pos_hyper_cs_t; + #endif -#endif \ No newline at end of file +#endif