Signed-off-by: Sergey Kambalin <sergey.kamba...@auriga.com> --- hw/misc/bcm2835_property.c | 170 ++++++++++++++++++++++++++ include/hw/misc/raspberrypi-fw-defs.h | 11 ++ 2 files changed, 181 insertions(+)
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 4ed9faa54a..7d2d6e518d 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -19,6 +19,31 @@ #include "trace.h" #include "hw/arm/raspi_platform.h" +#define RPI_EXP_GPIO_BASE 128 +#define VC4_GPIO_EXPANDER_COUNT 8 +#define VCHI_BUSADDR_SIZE sizeof(uint32_t) + +struct vc4_display_settings_t { + uint32_t display_num; + uint32_t width; + uint32_t height; + uint32_t depth; + uint16_t pitch; + uint32_t virtual_width; + uint32_t virtual_height; + uint16_t virtual_width_offset; + uint32_t virtual_height_offset; + unsigned long fb_bus_address; +} QEMU_PACKED; + +struct vc4_gpio_expander_t { + uint32_t direction; + uint32_t polarity; + uint32_t term_en; + uint32_t term_pull_up; + uint32_t state; +} vc4_gpio_expander[VC4_GPIO_EXPANDER_COUNT]; + /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) @@ -30,6 +55,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) uint32_t tmp; int n; uint32_t offset, length, color; + uint32_t gpio_num; /* * Copy the current state of the framebuffer config; we will update @@ -138,6 +164,13 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) resplen = 8; break; + case RPI_FWREQ_GET_CLOCKS: + /* TODO: add more clock IDs if needed */ + stl_le_phys(&s->dma_as, value + 12, 0); + stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_ARM_CLK_ID); + resplen = 8; + break; + case RPI_FWREQ_SET_CLOCK_RATE: case RPI_FWREQ_SET_MAX_CLOCK_RATE: case RPI_FWREQ_SET_MIN_CLOCK_RATE: @@ -276,6 +309,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) stl_le_phys(&s->dma_as, value + 12, 0); resplen = 4; break; + case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS: stl_le_phys(&s->dma_as, value + 12, 1); resplen = 4; @@ -301,6 +335,142 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) resplen); break; + case RPI_FWREQ_GET_THROTTLED: + stl_le_phys(&s->dma_as, value + 12, 0); + resplen = 4; + break; + + case RPI_FWREQ_FRAMEBUFFER_GET_DISPLAY_SETTINGS: + stl_le_phys(&s->dma_as, value + 12, 0); /* display_num */ + stl_le_phys(&s->dma_as, value + 16, 800); /* width */ + stl_le_phys(&s->dma_as, value + 20, 600); /* height */ + stl_le_phys(&s->dma_as, value + 24, 32); /* depth */ + stl_le_phys(&s->dma_as, value + 28, 32); /* pitch */ + stl_le_phys(&s->dma_as, value + 30, 0); /* virtual_width */ + stl_le_phys(&s->dma_as, value + 34, 0); /* virtual_height */ + stl_le_phys(&s->dma_as, value + 38, 0); /* virtual_width_offset */ + stl_le_phys(&s->dma_as, value + 40, 0); /* virtual_height_offset */ + stl_le_phys(&s->dma_as, value + 44, 0); /* fb_bus_address low */ + stl_le_phys(&s->dma_as, value + 48, 0); /* fb_bus_address hi */ + resplen = sizeof(struct vc4_display_settings_t); + break; + + case RPI_FWREQ_FRAMEBUFFER_SET_PITCH: + resplen = 0; + break; + + case RPI_FWREQ_GET_GPIO_CONFIG: + if (ldl_le_phys(&s->dma_as, value + 12) < RPI_EXP_GPIO_BASE) { + qemu_log_mask(LOG_UNIMP, "RPI_FWREQ_GET_GPIO_CONFIG " + "not implemented for gpiochip0\n"); + } else { + gpio_num = ldl_le_phys(&s->dma_as, value + 12) + - RPI_EXP_GPIO_BASE; + + if (gpio_num < VC4_GPIO_EXPANDER_COUNT) { + stl_le_phys(&s->dma_as, value + 16, + vc4_gpio_expander[gpio_num].direction); + stl_le_phys(&s->dma_as, value + 20, + vc4_gpio_expander[gpio_num].polarity); + stl_le_phys(&s->dma_as, value + 24, + vc4_gpio_expander[gpio_num].term_en); + stl_le_phys(&s->dma_as, value + 28, + vc4_gpio_expander[gpio_num].term_pull_up); + /* must be equal 0 */ + stl_le_phys(&s->dma_as, value + 12, 0); + resplen = 4 * 5; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "RPI_FWREQ_GET_GPIO_CONFIG " + "gpio num must be < %d", + RPI_EXP_GPIO_BASE + VC4_GPIO_EXPANDER_COUNT); + } + } + break; + + case RPI_FWREQ_SET_GPIO_CONFIG: + if (ldl_le_phys(&s->dma_as, value + 12) < RPI_EXP_GPIO_BASE) { + qemu_log_mask(LOG_UNIMP, "RPI_FWREQ_SET_GPIO_CONFIG " + "not implemented for gpiochip0\n"); + } else { + gpio_num = ldl_le_phys(&s->dma_as, value + 12) + - RPI_EXP_GPIO_BASE; + + if (gpio_num < VC4_GPIO_EXPANDER_COUNT) { + vc4_gpio_expander[gpio_num].direction = + ldl_le_phys(&s->dma_as, value + 16); + vc4_gpio_expander[gpio_num].polarity = + ldl_le_phys(&s->dma_as, value + 20); + vc4_gpio_expander[gpio_num].term_en = + ldl_le_phys(&s->dma_as, value + 24); + vc4_gpio_expander[gpio_num].term_pull_up = + ldl_le_phys(&s->dma_as, value + 28); + vc4_gpio_expander[gpio_num].state = + ldl_le_phys(&s->dma_as, value + 32); + /* must be equal 0 */ + stl_le_phys(&s->dma_as, value + 12, 0); + resplen = 4; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "RPI_FWREQ_SET_GPIO_CONFIG " + "gpio num must be < %d", + RPI_EXP_GPIO_BASE + VC4_GPIO_EXPANDER_COUNT); + } + } + break; + + case RPI_FWREQ_GET_GPIO_STATE: + if (ldl_le_phys(&s->dma_as, value + 12) < RPI_EXP_GPIO_BASE) { + qemu_log_mask(LOG_UNIMP, "RPI_FWREQ_GET_GPIO_STATE " + "not implemented for gpiochip0\n"); + } else { + gpio_num = ldl_le_phys(&s->dma_as, value + 12) + - RPI_EXP_GPIO_BASE; + + if (gpio_num < VC4_GPIO_EXPANDER_COUNT) { + stl_le_phys(&s->dma_as, value + 16, + vc4_gpio_expander[gpio_num].state); + /* must be equal 0 */ + stl_le_phys(&s->dma_as, value + 12, 0); + resplen = 8; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "RPI_FWREQ_GET_GPIO_STATE " + "gpio num must be < %d", + RPI_EXP_GPIO_BASE + VC4_GPIO_EXPANDER_COUNT); + } + } + break; + + case RPI_FWREQ_SET_GPIO_STATE: + if (ldl_le_phys(&s->dma_as, value + 12) < RPI_EXP_GPIO_BASE) { + qemu_log_mask(LOG_UNIMP, "RPI_FWREQ_SET_GPIO_STATE not " + "implemented for gpiochip0\n"); + } else { + gpio_num = ldl_le_phys(&s->dma_as, value + 12) + - RPI_EXP_GPIO_BASE; + + if (gpio_num < VC4_GPIO_EXPANDER_COUNT) { + vc4_gpio_expander[gpio_num].state = ldl_le_phys(&s->dma_as, + value + 16); + /* must be equal 0 */ + stl_le_phys(&s->dma_as, value + 12, 0); + resplen = 4; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "RPI_FWREQ_SET_GPIO_STATE " + "gpio num must be < %d", + RPI_EXP_GPIO_BASE + VC4_GPIO_EXPANDER_COUNT); + } + } + break; + + case RPI_FWREQ_VCHIQ_INIT: + stl_le_phys(&s->dma_as, + value + offsetof(rpi_firmware_prop_request_t, payload), + 0); + resplen = VCHI_BUSADDR_SIZE; + break; default: qemu_log_mask(LOG_UNIMP, "bcm2835_property: unhandled tag 0x%08x\n", tag); diff --git a/include/hw/misc/raspberrypi-fw-defs.h b/include/hw/misc/raspberrypi-fw-defs.h index 4551fe7450..d461b30749 100644 --- a/include/hw/misc/raspberrypi-fw-defs.h +++ b/include/hw/misc/raspberrypi-fw-defs.h @@ -160,4 +160,15 @@ enum rpi_firmware_clk_id { RPI_FIRMWARE_NUM_CLK_ID, }; +struct rpi_firmware_property_tag_header { + uint32_t tag; + uint32_t buf_size; + uint32_t req_resp_size; +}; + +typedef struct rpi_firmware_prop_request { + struct rpi_firmware_property_tag_header hdr; + uint8_t payload[0]; +} rpi_firmware_prop_request_t; + #endif /* INCLUDE_HW_MISC_RASPBERRYPI_FW_DEFS_H_ */ -- 2.34.1