video: add a driver for the bcm2835
The firmware running on the bcm2835 SoC's VideoCore CPU manages the
display controller. Add a simple "LCD" driver that communicates with the
firmware using the property mailbox protocol. This configures the
display and frame-buffer to match whatever physical resolution the
firmware chosen when booting, which is typically the native resolution
of the attached display device, presumably unless otherwise specified
in config.txt on the boot media.
Enable this driver in the Raspberry Pi board configuration.
Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
Acked-by: Anatolij Gustschin <agust@denx.de>
diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c
new file mode 100644
index 0000000..1e9a84a
--- /dev/null
+++ b/drivers/video/bcm2835.c
@@ -0,0 +1,127 @@
+/*
+ * (C) Copyright 2012 Stephen Warren
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <lcd.h>
+#include <asm/arch/mbox.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Global variables that lcd.c expects to exist */
+int lcd_line_length;
+int lcd_color_fg;
+int lcd_color_bg;
+void *lcd_base;
+void *lcd_console_address;
+short console_col;
+short console_row;
+vidinfo_t panel_info;
+char lcd_cursor_enabled;
+ushort lcd_cursor_width;
+ushort lcd_cursor_height;
+
+struct msg_query {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_physical_w_h physical_w_h;
+ u32 end_tag;
+};
+
+struct msg_setup {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_physical_w_h physical_w_h;
+ struct bcm2835_mbox_tag_virtual_w_h virtual_w_h;
+ struct bcm2835_mbox_tag_depth depth;
+ struct bcm2835_mbox_tag_pixel_order pixel_order;
+ struct bcm2835_mbox_tag_alpha_mode alpha_mode;
+ struct bcm2835_mbox_tag_virtual_offset virtual_offset;
+ struct bcm2835_mbox_tag_overscan overscan;
+ struct bcm2835_mbox_tag_allocate_buffer allocate_buffer;
+ u32 end_tag;
+};
+
+void lcd_ctrl_init(void *lcdbase)
+{
+ ALLOC_ALIGN_BUFFER(struct msg_query, msg_query, 1, 16);
+ ALLOC_ALIGN_BUFFER(struct msg_setup, msg_setup, 1, 16);
+ int ret;
+ u32 w, h;
+
+ debug("bcm2835: Query resolution...\n");
+
+ BCM2835_MBOX_INIT_HDR(msg_query);
+ BCM2835_MBOX_INIT_TAG_NO_REQ(&msg_query->physical_w_h,
+ GET_PHYSICAL_W_H);
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_query->hdr);
+ if (ret) {
+ printf("bcm2835: Could not query display resolution\n");
+ /* FIXME: How to disable the LCD to prevent errors? hang()? */
+ return;
+ }
+
+ w = msg_query->physical_w_h.body.resp.width;
+ h = msg_query->physical_w_h.body.resp.height;
+
+ debug("bcm2835: Setting up display for %d x %d\n", w, h);
+
+ BCM2835_MBOX_INIT_HDR(msg_setup);
+ BCM2835_MBOX_INIT_TAG(&msg_setup->physical_w_h, SET_PHYSICAL_W_H);
+ msg_setup->physical_w_h.body.req.width = w;
+ msg_setup->physical_w_h.body.req.height = h;
+ BCM2835_MBOX_INIT_TAG(&msg_setup->virtual_w_h, SET_VIRTUAL_W_H);
+ msg_setup->virtual_w_h.body.req.width = w;
+ msg_setup->virtual_w_h.body.req.height = h;
+ BCM2835_MBOX_INIT_TAG(&msg_setup->depth, SET_DEPTH);
+ msg_setup->depth.body.req.bpp = 16;
+ BCM2835_MBOX_INIT_TAG(&msg_setup->pixel_order, SET_PIXEL_ORDER);
+ msg_setup->pixel_order.body.req.order = BCM2835_MBOX_PIXEL_ORDER_BGR;
+ BCM2835_MBOX_INIT_TAG(&msg_setup->alpha_mode, SET_ALPHA_MODE);
+ msg_setup->alpha_mode.body.req.alpha = BCM2835_MBOX_ALPHA_MODE_IGNORED;
+ BCM2835_MBOX_INIT_TAG(&msg_setup->virtual_offset, SET_VIRTUAL_OFFSET);
+ msg_setup->virtual_offset.body.req.x = 0;
+ msg_setup->virtual_offset.body.req.y = 0;
+ BCM2835_MBOX_INIT_TAG(&msg_setup->overscan, SET_OVERSCAN);
+ msg_setup->overscan.body.req.top = 0;
+ msg_setup->overscan.body.req.bottom = 0;
+ msg_setup->overscan.body.req.left = 0;
+ msg_setup->overscan.body.req.right = 0;
+ BCM2835_MBOX_INIT_TAG(&msg_setup->allocate_buffer, ALLOCATE_BUFFER);
+ msg_setup->allocate_buffer.body.req.alignment = 0x100;
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_setup->hdr);
+ if (ret) {
+ printf("bcm2835: Could not configure display\n");
+ /* FIXME: How to disable the LCD to prevent errors? hang()? */
+ return;
+ }
+
+ w = msg_setup->physical_w_h.body.resp.width;
+ h = msg_setup->physical_w_h.body.resp.height;
+
+ debug("bcm2835: Final resolution is %d x %d\n", w, h);
+
+ panel_info.vl_col = w;
+ panel_info.vl_row = h;
+ panel_info.vl_bpix = LCD_COLOR16;
+
+ gd->fb_base = msg_setup->allocate_buffer.body.resp.fb_address;
+ lcd_base = (void *)gd->fb_base;
+}
+
+void lcd_enable(void)
+{
+}