pru: BeagleBone Firmware upgrade to Debian 11.7 Bullseye (#6577)
* Porting BeagleBone to Kernel 5.10 * Fixing issue with installation for BeagleBone. This fix resolve 2 issue: 1. Conflict with AVR packages. 2. "klipper_pru" script is executed before PRU cores are ready * Adding additional steps to BeagleBone install guide. * Updating BeagleBone documentation, adding different use cases, adding buses configurations SPI, I2C, CAN, UART Signed-off-by: Oleg Gavavka <work@datalink.net.ua>
This commit is contained in:
@@ -27,7 +27,11 @@ target-y += $(OUT)pru0.elf $(OUT)pru1.elf
|
||||
$(OUT)pru0.elf: $(patsubst %.c, $(OUT)src/%.o,$(pru0-y))
|
||||
@echo " Linking $@"
|
||||
$(Q)$(CC) $(CFLAGS_klipper.elf) $^ -o $(OUT)pru0.o
|
||||
# dumping info about INTC
|
||||
$(Q)$(OBJCOPY) --dump-section '.pru_irq_map'=$(OUT)pru0.pru_irq_map.bin $(OUT)src/pru/pru0.o $(OUT)pru0.o.discard
|
||||
$(Q)$(CC) $(CFLAGS_pru0.elf) $(OUT)pru0.o -o $@
|
||||
# in previous step linker did loose info about INTC during optimization, restoring it here (P.S. pru.lds is not helping)
|
||||
$(Q)$(OBJCOPY) --add-section '.pru_irq_map'=$(OUT)pru0.pru_irq_map.bin $@
|
||||
|
||||
$(OUT)pru1.elf: $(OUT)klipper.elf
|
||||
@echo " Linking $@"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#define GPIO2BIT(PIN) (1<<((PIN) % 32))
|
||||
|
||||
struct gpio_regs {
|
||||
uint32_t pad_0[77];
|
||||
uint32_t pad_0[77]; // 77*4=308=134h
|
||||
volatile uint32_t oe;
|
||||
volatile uint32_t datain;
|
||||
volatile uint32_t dataout;
|
||||
|
||||
62
src/pru/intc_map_0.h
Normal file
62
src/pru/intc_map_0.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef _INTC_MAP_0_H_
|
||||
#define _INTC_MAP_0_H_ __attribute__((used, section(".pru_irq_map")))
|
||||
|
||||
/*
|
||||
* ======== PRU INTC Map ========
|
||||
*
|
||||
* Define the INTC mapping for interrupts going to the ICSS / ICSSG:
|
||||
* ICSS Host interrupts 0, 1
|
||||
* ICSSG Host interrupts 0, 1, 10-19
|
||||
*
|
||||
* Note that INTC interrupts going to the ARM Linux host should not be defined
|
||||
* in this file (ICSS/ICSSG Host interrupts 2-9).
|
||||
*
|
||||
* The INTC configuration for interrupts going to the ARM host should be defined
|
||||
* in the device tree node of the client driver, "interrupts" property.
|
||||
* See Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.yaml
|
||||
* entry #interrupt-cells for more.
|
||||
*
|
||||
* For example, on ICSSG:
|
||||
*
|
||||
* &client_driver0 {
|
||||
* interrupt-parent = <&icssg0_intc>;
|
||||
* interrupts = <21 2 2>, <22 3 3>;
|
||||
* interrupt-names = "interrupt_name1", "interrupt_name2";
|
||||
* };
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* .pru_irq_map is used by the RemoteProc driver during initialization. However,
|
||||
* the map is NOT used by the PRU firmware. That means DATA_SECTION and RETAIN
|
||||
* are required to prevent the PRU compiler from optimizing out .pru_irq_map.
|
||||
*/
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
#pragma DATA_SECTION(my_irq_rsc, ".pru_irq_map")
|
||||
#pragma RETAIN(my_irq_rsc)
|
||||
#define __pru_irq_map
|
||||
#else
|
||||
#define __pru_irq_map __attribute__((section(".pru_irq_map"), \
|
||||
unavailable("pru_irq_map is for usage by the host only")))
|
||||
#endif
|
||||
|
||||
struct pru_irq_rsc my_irq_rsc __pru_irq_map = {
|
||||
0, /* type = 0 */
|
||||
4, /* number of system events being mapped */
|
||||
{
|
||||
// this item (sysevt=16) is obsolete in Linux 5.10
|
||||
// {16, 2, 2}, /* {sysevt, channel, host interrupt} */
|
||||
{17, 0, 0}, /* {sysevt, channel, host interrupt} */
|
||||
{18, 0, 0}, /* {sysevt, channel, host interrupt} */
|
||||
{19, 1, 1}, /* {sysevt, channel, host interrupt} */
|
||||
// next item is responsible for timer to function,
|
||||
// it should be kept last in Linux 5.10
|
||||
// (if it will be first - gpios will not work)
|
||||
{7, 1, 1}, /* {sysevt, channel, host interrupt} */
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* _INTC_MAP_0_H_ */
|
||||
@@ -15,6 +15,12 @@
|
||||
#define WAKE_PRU1_IRQ 1
|
||||
#define WAKE_ARM_IRQ 2
|
||||
|
||||
/* Host-0 Interrupt sets bit 31 in register R31 */
|
||||
#define HOST_INT_0 ((uint32_t) 1 << 30)
|
||||
|
||||
/* Host-1 Interrupt sets bit 31 in register R31 */
|
||||
#define HOST_INT_1 ((uint32_t) 1 << 31)
|
||||
|
||||
#define R31_IRQ_OFFSET 30
|
||||
|
||||
#define R31_WRITE_IRQ_SELECT (1<<5)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <stdint.h> // uint32_t
|
||||
#include <pru/io.h> // read_r31
|
||||
#include <pru_iep.h> // CT_IEP
|
||||
#include <pru_intc.h> // CT_INTC
|
||||
|
||||
#include <rsc_types.h> // resource_table
|
||||
#include "board/misc.h" // dynmem_start
|
||||
#include "board/io.h" // readl
|
||||
@@ -75,7 +75,7 @@ timer_kick(void)
|
||||
timer_set(timer_read_time() + 50);
|
||||
CT_IEP.TMR_CMP_STS = 0xff;
|
||||
__delay_cycles(4);
|
||||
CT_INTC.SECR0 = 1 << IEP_EVENT;
|
||||
PRU_INTC.SECR0 = 1 << IEP_EVENT;
|
||||
}
|
||||
|
||||
static uint32_t in_timer_dispatch;
|
||||
@@ -83,9 +83,9 @@ static uint32_t in_timer_dispatch;
|
||||
static void
|
||||
_irq_poll(void)
|
||||
{
|
||||
uint32_t secr0 = CT_INTC.SECR0;
|
||||
uint32_t secr0 = PRU_INTC.SECR0;
|
||||
if (secr0 & (1 << KICK_PRU1_EVENT)) {
|
||||
CT_INTC.SECR0 = 1 << KICK_PRU1_EVENT;
|
||||
PRU_INTC.SECR0 = 1 << KICK_PRU1_EVENT;
|
||||
sched_wake_tasks();
|
||||
}
|
||||
if (secr0 & (1 << IEP_EVENT)) {
|
||||
@@ -93,7 +93,7 @@ _irq_poll(void)
|
||||
in_timer_dispatch = 1;
|
||||
uint32_t next = timer_dispatch_many();
|
||||
timer_set(next);
|
||||
CT_INTC.SECR0 = 1 << IEP_EVENT;
|
||||
PRU_INTC.SECR0 = 1 << IEP_EVENT;
|
||||
in_timer_dispatch = 0;
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,7 @@ console_sendf(const struct command_encoder *ce, va_list args)
|
||||
SHARED_MEM->next_encoder_args = args;
|
||||
writel(&SHARED_MEM->next_encoder, (uint32_t)ce);
|
||||
|
||||
// Signal PRU0 to transmit message
|
||||
// Signal PRU0 to transmit message - 20 | (18-16) = 22 = 0010 0010
|
||||
write_r31(R31_WRITE_IRQ_SELECT | (KICK_PRU0_EVENT - R31_WRITE_IRQ_OFFSET));
|
||||
uint32_t itd = in_timer_dispatch;
|
||||
while (readl(&SHARED_MEM->next_encoder))
|
||||
@@ -197,25 +197,6 @@ dynmem_end(void)
|
||||
return (void*)(8*1024 - STACK_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Resource table
|
||||
****************************************************************/
|
||||
|
||||
struct my_resource_table {
|
||||
struct resource_table base;
|
||||
|
||||
uint32_t offset[1]; /* Should match 'num' in actual definition */
|
||||
} resourceTable __visible __section(".resource_table") = {
|
||||
{
|
||||
1, /* Resource table version: only version 1 is
|
||||
* supported by the current driver */
|
||||
0, /* number of entries in the table */
|
||||
{ 0, 0 }, /* reserved, must be zero */
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Startup
|
||||
****************************************************************/
|
||||
|
||||
135
src/pru/pru0.c
135
src/pru/pru0.c
@@ -8,17 +8,16 @@
|
||||
#include <stdint.h> // uint32_t
|
||||
#include <string.h> // memset
|
||||
#include <pru/io.h> // write_r31
|
||||
#include <pru_cfg.h> // CT_CFG
|
||||
#include <pru_intc.h> // CT_INTC
|
||||
#include <pru_rpmsg.h> // pru_rpmsg_send
|
||||
#include <pru_virtio_ids.h> // VIRTIO_ID_RPMSG
|
||||
#include <rsc_types.h> // resource_table
|
||||
#include "board/io.h" // readl
|
||||
#include "board/misc.h" // console_sendf
|
||||
#include "command.h" // command_encode_add_frame
|
||||
#include "compiler.h" // __section
|
||||
#include "internal.h" // SHARED_MEM
|
||||
#include "sched.h" // sched_shutdown
|
||||
#include "intc_map_0.h"
|
||||
#include "resource_table.h"
|
||||
|
||||
struct pru_rpmsg_transport transport;
|
||||
static uint16_t transport_dst;
|
||||
@@ -32,8 +31,7 @@ static uint16_t transport_dst;
|
||||
#define CHAN_DESC "Channel 30"
|
||||
#define CHAN_PORT 30
|
||||
|
||||
#define RPMSG_HDR_SIZE 16
|
||||
static uint8_t transmit_buf[RPMSG_BUF_SIZE - RPMSG_HDR_SIZE];
|
||||
static uint8_t transmit_buf[RPMSG_MESSAGE_SIZE];
|
||||
static int transmit_pos;
|
||||
|
||||
// Transmit all pending message blocks
|
||||
@@ -195,7 +193,7 @@ static void
|
||||
process_io(void)
|
||||
{
|
||||
for (;;) {
|
||||
CT_INTC.SECR0 = ((1 << KICK_PRU0_FROM_ARM_EVENT)
|
||||
PRU_INTC.SECR0 = ((1 << KICK_PRU0_FROM_ARM_EVENT)
|
||||
| (1 << KICK_PRU0_EVENT));
|
||||
check_can_send();
|
||||
int can_sleep = check_can_read();
|
||||
@@ -251,112 +249,6 @@ console_sendf(const struct command_encoder *ce, va_list args)
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Resource table
|
||||
****************************************************************/
|
||||
|
||||
/*
|
||||
* Sizes of the virtqueues (expressed in number of buffers supported,
|
||||
* and must be power of 2)
|
||||
*/
|
||||
#define PRU_RPMSG_VQ0_SIZE 16
|
||||
#define PRU_RPMSG_VQ1_SIZE 16
|
||||
|
||||
/*
|
||||
* The feature bitmap for virtio rpmsg
|
||||
*/
|
||||
#define VIRTIO_RPMSG_F_NS 0 //name service notifications
|
||||
|
||||
/* This firmware supports name service notifications as one of its features */
|
||||
#define RPMSG_PRU_C0_FEATURES (1 << VIRTIO_RPMSG_F_NS)
|
||||
|
||||
/* Definition for unused interrupts */
|
||||
#define HOST_UNUSED 255
|
||||
|
||||
/* Mapping sysevts to a channel. Each pair contains a sysevt, channel. */
|
||||
static struct ch_map pru_intc_map[] = {
|
||||
{IEP_EVENT, WAKE_PRU1_IRQ},
|
||||
{KICK_ARM_EVENT, WAKE_ARM_IRQ},
|
||||
{KICK_PRU0_FROM_ARM_EVENT, WAKE_PRU0_IRQ},
|
||||
{KICK_PRU0_EVENT, WAKE_PRU0_IRQ},
|
||||
{KICK_PRU1_EVENT, WAKE_PRU1_IRQ},
|
||||
};
|
||||
|
||||
struct my_resource_table {
|
||||
struct resource_table base;
|
||||
|
||||
uint32_t offset[2]; /* Should match 'num' in actual definition */
|
||||
|
||||
/* rpmsg vdev entry */
|
||||
struct fw_rsc_vdev rpmsg_vdev;
|
||||
struct fw_rsc_vdev_vring rpmsg_vring0;
|
||||
struct fw_rsc_vdev_vring rpmsg_vring1;
|
||||
|
||||
/* intc definition */
|
||||
struct fw_rsc_custom pru_ints;
|
||||
} resourceTable __section(".resource_table") = {
|
||||
{
|
||||
1, /* Resource table version: only version 1 is
|
||||
* supported by the current driver */
|
||||
2, /* number of entries in the table */
|
||||
{ 0, 0 }, /* reserved, must be zero */
|
||||
},
|
||||
/* offsets to entries */
|
||||
{
|
||||
offsetof(struct my_resource_table, rpmsg_vdev),
|
||||
offsetof(struct my_resource_table, pru_ints),
|
||||
},
|
||||
|
||||
/* rpmsg vdev entry */
|
||||
{
|
||||
(uint32_t)TYPE_VDEV, //type
|
||||
(uint32_t)VIRTIO_ID_RPMSG, //id
|
||||
(uint32_t)0, //notifyid
|
||||
(uint32_t)RPMSG_PRU_C0_FEATURES,//dfeatures
|
||||
(uint32_t)0, //gfeatures
|
||||
(uint32_t)0, //config_len
|
||||
(uint8_t)0, //status
|
||||
(uint8_t)2, //num_of_vrings, only two is supported
|
||||
{(uint8_t)0, (uint8_t)0 }, //reserved
|
||||
/* no config data */
|
||||
},
|
||||
/* the two vrings */
|
||||
{
|
||||
0, //da, will be populated by host, can't pass it in
|
||||
16, //align (bytes),
|
||||
PRU_RPMSG_VQ0_SIZE, //num of descriptors
|
||||
0, //notifyid, will be populated, can't pass right now
|
||||
0 //reserved
|
||||
},
|
||||
{
|
||||
0, //da, will be populated by host, can't pass it in
|
||||
16, //align (bytes),
|
||||
PRU_RPMSG_VQ1_SIZE, //num of descriptors
|
||||
0, //notifyid, will be populated, can't pass right now
|
||||
0 //reserved
|
||||
},
|
||||
|
||||
{
|
||||
TYPE_CUSTOM, TYPE_PRU_INTS,
|
||||
sizeof(struct fw_rsc_custom_ints),
|
||||
{ /* PRU_INTS version */
|
||||
{
|
||||
0x0000,
|
||||
/* Channel-to-host mapping, 255 for unused */
|
||||
{
|
||||
WAKE_PRU0_IRQ, WAKE_PRU1_IRQ, WAKE_ARM_IRQ,
|
||||
HOST_UNUSED, HOST_UNUSED, HOST_UNUSED,
|
||||
HOST_UNUSED, HOST_UNUSED, HOST_UNUSED, HOST_UNUSED
|
||||
},
|
||||
/* Number of evts being mapped to channels */
|
||||
(sizeof(pru_intc_map) / sizeof(struct ch_map)),
|
||||
/* Pointer to the structure containing mapped events */
|
||||
pru_intc_map,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Startup
|
||||
@@ -368,11 +260,26 @@ int
|
||||
main(void)
|
||||
{
|
||||
// allow access to external memory
|
||||
#if defined(__AM335X__)
|
||||
/* AM335x must enable OCP master port access in order for the PRU to
|
||||
* read external memories.*/
|
||||
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
|
||||
#endif
|
||||
|
||||
/* Clear the status of the PRU-ICSS system event that the ARM
|
||||
will use to 'kick' us */
|
||||
#if defined(__AM335X__)
|
||||
PRU_INTC.SICR_bit.STS_CLR_IDX = KICK_PRU0_FROM_ARM_EVENT;
|
||||
#elif defined(__TDA4VM__) || defined(__AM62X__)
|
||||
PRU_INTC.STATUS_CLR_INDEX_REG_bit.STATUS_CLR_INDEX = \
|
||||
KICK_PRU0_FROM_ARM_EVENT;
|
||||
#else
|
||||
#error "Unsupported SoC."
|
||||
#endif
|
||||
|
||||
// clear all irqs
|
||||
CT_INTC.SECR0 = 0xffffffff;
|
||||
CT_INTC.SECR1 = 0xffffffff;
|
||||
PRU_INTC.SECR0 = 0xffffffff;
|
||||
PRU_INTC.SECR1 = 0xffffffff;
|
||||
|
||||
/* Make sure the Linux drivers are ready for RPMsg communication */
|
||||
volatile uint8_t *status = &resourceTable.rpmsg_vdev.status;
|
||||
|
||||
91
src/pru/resource_table.h
Normal file
91
src/pru/resource_table.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/****************************************************************
|
||||
* Resource table
|
||||
****************************************************************/
|
||||
|
||||
#ifndef _RESOURCE_TABLE_H_
|
||||
#define _RESOURCE_TABLE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include "pru_virtio_ids.h"
|
||||
|
||||
/*
|
||||
* Sizes of the virtqueues (expressed in number of buffers supported,
|
||||
* and must be power of 2)
|
||||
*/
|
||||
#define PRU_RPMSG_VQ0_SIZE 16
|
||||
#define PRU_RPMSG_VQ1_SIZE 16
|
||||
|
||||
/*
|
||||
* The feature bitmap for virtio rpmsg
|
||||
*/
|
||||
#define VIRTIO_RPMSG_F_NS 0 //name service notifications
|
||||
|
||||
/* This firmware supports name service notifications as one of its features */
|
||||
#define RPMSG_PRU_C0_FEATURES (1 << VIRTIO_RPMSG_F_NS)
|
||||
|
||||
/* Definition for unused interrupts */
|
||||
#define HOST_UNUSED 255
|
||||
|
||||
struct my_resource_table {
|
||||
struct resource_table base;
|
||||
|
||||
uint32_t offset[1]; /* Should match 'num' in actual definition */
|
||||
|
||||
/* rpmsg vdev entry */
|
||||
struct fw_rsc_vdev rpmsg_vdev;
|
||||
struct fw_rsc_vdev_vring rpmsg_vring0;
|
||||
struct fw_rsc_vdev_vring rpmsg_vring1;
|
||||
|
||||
};
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
#pragma DATA_SECTION(resourceTable, ".resource_table")
|
||||
#pragma RETAIN(resourceTable)
|
||||
#define __resource_table /* */
|
||||
#else
|
||||
#define __resource_table __attribute__((section(".resource_table")))
|
||||
#endif
|
||||
|
||||
struct my_resource_table resourceTable __resource_table = {
|
||||
{
|
||||
1, /* Resource table version: only version 1 is
|
||||
* supported by the current driver */
|
||||
1, /* number of entries in the table */
|
||||
{0, 0}, /* reserved, must be zero */
|
||||
},
|
||||
/* offsets to entries */
|
||||
{
|
||||
offsetof(struct my_resource_table, rpmsg_vdev),
|
||||
},
|
||||
|
||||
/* rpmsg vdev entry */
|
||||
{
|
||||
(uint32_t)TYPE_VDEV, //type
|
||||
(uint32_t)VIRTIO_ID_RPMSG, //id
|
||||
(uint32_t)0, //notifyid
|
||||
(uint32_t)RPMSG_PRU_C0_FEATURES,//dfeatures
|
||||
(uint32_t)0, //gfeatures
|
||||
(uint32_t)0, //config_len
|
||||
(uint8_t)0, //status
|
||||
(uint8_t)2, //num_of_vrings, only two is supported
|
||||
{(uint8_t)0, (uint8_t)0 }, //reserved
|
||||
/* no config data */
|
||||
},
|
||||
/* the two vrings */
|
||||
{
|
||||
FW_RSC_ADDR_ANY, //da, will be populated by host, can't pass it in
|
||||
16, //align (bytes),
|
||||
PRU_RPMSG_VQ0_SIZE, //num of descriptors
|
||||
0, //notifyid, will be populated, can't pass right now
|
||||
0 //reserved
|
||||
},
|
||||
{
|
||||
FW_RSC_ADDR_ANY, //da, will be populated by host, can't pass it in
|
||||
16, //align (bytes),
|
||||
PRU_RPMSG_VQ1_SIZE, //num of descriptors
|
||||
0, //notifyid, will be populated, can't pass right now
|
||||
0 //reserved
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* _RESOURCE_TABLE_H_ */
|
||||
Reference in New Issue
Block a user