Module Name:    src
Committed By:   jmcneill
Date:           Wed Jan  9 00:24:54 UTC 2013

Modified Files:
        src/sys/arch/evbarm/rpi: rpi_machdep.c

Log Message:
genfb support for rpi


To generate a diff of this commit:
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/evbarm/rpi/rpi_machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/evbarm/rpi/rpi_machdep.c
diff -u src/sys/arch/evbarm/rpi/rpi_machdep.c:1.21 src/sys/arch/evbarm/rpi/rpi_machdep.c:1.22
--- src/sys/arch/evbarm/rpi/rpi_machdep.c:1.21	Tue Jan  8 16:49:43 2013
+++ src/sys/arch/evbarm/rpi/rpi_machdep.c	Wed Jan  9 00:24:54 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: rpi_machdep.c,v 1.21 2013/01/08 16:49:43 skrll Exp $	*/
+/*	$NetBSD: rpi_machdep.c,v 1.22 2013/01/09 00:24:54 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -30,13 +30,15 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rpi_machdep.c,v 1.21 2013/01/08 16:49:43 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rpi_machdep.c,v 1.22 2013/01/09 00:24:54 jmcneill Exp $");
 
 #include "opt_evbarm_boardtype.h"
 
 #include "sdhc.h"
 #include "bcmspi.h"
 #include "bsciic.h"
+#include "plcom.h"
+#include "genfb.h"
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -67,12 +69,16 @@ __KERNEL_RCSID(0, "$NetBSD: rpi_machdep.
 
 #include <evbarm/rpi/rpi.h>
 
-#include "plcom.h"
-#if (NPLCOM > 0)
+#if NPLCOM > 0
 #include <evbarm/dev/plcomreg.h>
 #include <evbarm/dev/plcomvar.h>
 #endif
 
+#if NGENFB > 0
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/edidvar.h>
+#endif
+
 #include "ksyms.h"
 
 extern int KERNEL_BASE_phys[];
@@ -94,6 +100,13 @@ static void rpi_device_register(device_t
 #define KERN_VTOPHYS(va) ((paddr_t)((vaddr_t)va + KERN_VTOPDIFF))
 #define KERN_PHYSTOV(pa) ((vaddr_t)((paddr_t)pa - KERN_VTOPDIFF))
 
+#ifndef RPI_FB_WIDTH
+#define RPI_FB_WIDTH	1280
+#endif
+#ifndef RPI_FB_HEIGHT
+#define RPI_FB_HEIGHT	720
+#endif
+
 #define	PLCONADDR 0x20201000
 
 #ifndef CONSDEVNAME
@@ -213,6 +226,118 @@ static struct {
 	}
 };
 
+#if NGENFB > 0
+static struct {
+	struct vcprop_buffer_hdr	vb_hdr;
+	struct vcprop_tag_edidblock	vbt_edid;
+	struct vcprop_tag end;
+} vb_edid __packed __aligned(16) =
+{
+	.vb_hdr = {
+		.vpb_len = sizeof(vb_edid),
+		.vpb_rcode = VCPROP_PROCESS_REQUEST,
+	},
+	.vbt_edid = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_GET_EDID_BLOCK,
+			.vpt_len = VCPROPTAG_LEN(vb_edid.vbt_edid),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+		.blockno = 0,
+	},
+	.end = {
+		.vpt_tag = VCPROPTAG_NULL
+	}
+};
+
+static struct {
+	struct vcprop_buffer_hdr	vb_hdr;
+	struct vcprop_tag_fbres		vbt_res;
+	struct vcprop_tag_fbres		vbt_vres;
+	struct vcprop_tag_fbdepth	vbt_depth;
+	struct vcprop_tag_fbpixelorder	vbt_pixelorder;
+	struct vcprop_tag_fbalpha	vbt_alpha;
+	struct vcprop_tag_allocbuf	vbt_allocbuf;
+	struct vcprop_tag_blankscreen	vbt_blank;
+	struct vcprop_tag_fbpitch	vbt_pitch;
+	struct vcprop_tag end;
+} vb_setfb __packed __aligned(16) =
+{
+	.vb_hdr = {
+		.vpb_len = sizeof(vb_setfb),
+		.vpb_rcode = VCPROP_PROCESS_REQUEST,
+	},
+	.vbt_res = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_SET_FB_RES,
+			.vpt_len = VCPROPTAG_LEN(vb_setfb.vbt_res),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+		.width = 0,
+		.height = 0,
+	},
+	.vbt_vres = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_SET_FB_VRES,
+			.vpt_len = VCPROPTAG_LEN(vb_setfb.vbt_vres),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+		.width = 0,
+		.height = 0,
+	},
+	.vbt_depth = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_SET_FB_DEPTH,
+			.vpt_len = VCPROPTAG_LEN(vb_setfb.vbt_depth),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+		.bpp = 32,
+	},
+	.vbt_pixelorder = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_SET_FB_PIXEL_ORDER,
+			.vpt_len = VCPROPTAG_LEN(vb_setfb.vbt_pixelorder),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+		.state = VCPROP_PIXEL_RGB,
+	},
+	.vbt_alpha = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_SET_FB_ALPHA_MODE,
+			.vpt_len = VCPROPTAG_LEN(vb_setfb.vbt_alpha),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+		.state = VCPROP_ALPHA_IGNORED,
+	},
+	.vbt_allocbuf = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_ALLOCATE_BUFFER,
+			.vpt_len = VCPROPTAG_LEN(vb_setfb.vbt_allocbuf),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+		.address = PAGE_SIZE,	/* alignment */
+	},
+	.vbt_blank = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_BLANK_SCREEN,
+			.vpt_len = VCPROPTAG_LEN(vb_setfb.vbt_blank),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+		.state = VCPROP_BLANK_OFF,
+	},
+	.vbt_pitch = {
+		.tag = {
+			.vpt_tag = VCPROPTAG_GET_FB_PITCH,
+			.vpt_len = VCPROPTAG_LEN(vb_setfb.vbt_pitch),
+			.vpt_rcode = VCPROPTAG_REQUEST,
+		},
+	},
+	.end = {
+		.vpt_tag = VCPROPTAG_NULL,
+	},
+};
+#endif
+
 static void
 rpi_bootparams(void)
 {
@@ -227,7 +352,6 @@ rpi_bootparams(void)
 #if (NPLCOM > 0)
 	    (1 << VCPM_POWER_UART0) |
 #endif
-
 #if (NBSCIIC > 0)
 	    (1 << VCPM_POWER_I2C0) | (1 << VCPM_POWER_I2C1) | 
 	/*  (1 << VCPM_POWER_I2C2) | */
@@ -244,9 +368,9 @@ rpi_bootparams(void)
 	/*
 	 * No need to invalid the cache as the memory has never been referenced
 	 * by the ARM.
-	 * 
+	 *
 	 * cpu_dcache_inv_range((vaddr_t)&vb, sizeof(vb));
-	 * 
+	 *
 	 */
 
 	if (!vcprop_buffer_success_p(&vb.vb_hdr)) {
@@ -254,10 +378,10 @@ rpi_bootparams(void)
 		bootconfig.dram[0].address = 0x0;
 		bootconfig.dram[0].pages = atop(RPI_MINIMUM_SPLIT);
 		return;
-	} 
+	}
 
 	struct vcprop_tag_memory *vptp_mem = &vb.vbt_memory;
-	
+
 	if (vcprop_tag_success_p(&vptp_mem->tag)) {
 		size_t n = vcprop_tag_resplen(&vptp_mem->tag) /
 		    sizeof(struct vcprop_memory);
@@ -270,7 +394,7 @@ rpi_bootparams(void)
 			bootconfig.dramblocks++;
 		}
 	}
-	
+
 	if (vcprop_tag_success_p(&vb.vbt_armclockrate.tag))
 		curcpu()->ci_data.cpu_cc_freq = vb.vbt_armclockrate.rate;
 
@@ -290,6 +414,7 @@ rpi_bootparams(void)
 	if (vcprop_tag_success_p(&vb.vbt_serial.tag))
 		printf("%s: board serial %llx\n", __func__,
 		    vb.vbt_serial.sn);
+
 	if (vcprop_tag_success_p(&vb.vbt_cmdline.tag))
 		printf("%s: cmdline      %s\n", __func__,
 		    vb.vbt_cmdline.cmdline);
@@ -365,6 +490,12 @@ initarm(void *arg)
 
 	rpi_bootparams();
 
+	if (vcprop_tag_success_p(&vb.vbt_armclockrate.tag)) {
+		curcpu()->ci_data.cpu_cc_freq = vb.vbt_armclockrate.rate;
+		printf("%s: arm clock   %d\n", __func__,
+		    vb.vbt_armclockrate.rate);
+	}
+
 #ifdef VERBOSE_INIT_ARM
 	printf("initarm: Configuring system ...\n");
 #endif
@@ -422,22 +553,183 @@ consinit(void)
 	 * This allows a means of generating output during initarm().
 	 */
 	rpi_pi.pi_iobase = consaddr;
-	
+
 	plcomcnattach(&rpi_pi, plcomcnspeed, BCM2835_UART0_CLK,
 	    plcomcnmode, PLCOMCNUNIT);
 
 #endif
 }
 
+#if NGENFB > 0
+static bool
+rpi_fb_parse_mode(const char *s, uint32_t *pwidth, uint32_t *pheight)
+{
+	if (strncmp(s, "fb", 2) != 0)
+		return false;
+
+	if (strncmp(s, "fb:", 3) == 0) {
+		char *x = strchr(s + 3, 'x');
+		if (x) {
+			*pwidth = strtoul(s + 3, NULL, 10);
+			*pheight = strtoul(x + 1, NULL, 10);
+		}	 
+	}
+
+	return true;
+}
+
+static bool
+rpi_fb_get_edid_mode(uint32_t *pwidth, uint32_t *pheight)
+{
+	struct edid_info ei;
+	uint8_t edid_data[1024];
+	uint32_t res;
+	int error;
+	
+	error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_edid,
+	    sizeof(vb_edid), &res);
+	if (error) {
+		printf("%s: mbox request failed (%d)\n", __func__, error);
+		return false;
+	}
+
+	if (!vcprop_buffer_success_p(&vb_edid.vb_hdr) ||
+	    !vcprop_tag_success_p(&vb_edid.vbt_edid.tag))
+		return false;
+
+	memset(edid_data, 0, sizeof(edid_data));
+	memcpy(edid_data, vb_edid.vbt_edid.data,
+	    sizeof(vb_edid.vbt_edid.data));
+	edid_parse(edid_data, &ei);
+#ifdef VERBOSE_INIT_ARM
+	edid_print(&ei);
+#endif
+
+	*pwidth = ei.edid_preferred_mode->hdisplay;
+	*pheight = ei.edid_preferred_mode->vdisplay;
+
+	return true;
+}
+
+/*
+ * Initialize framebuffer console.
+ *
+ * Some notes about boot parameters:
+ *  - If "console=" specifies something other than fb, ignore framebuffer
+ *    completely.
+ *  - If "console=fb" is present, try to use the preferred mode of the
+ *    display from the EDID block. If the EDID block is not present, use
+ *    RPI_FB_WIDTH and RPI_FB_HEIGHT.
+ *  - If "console=fb:<width>x<height>" is present, use the specified mode.
+ * 
+ * If the specified mode cannot be set, the framebuffer will not be used
+ * as the console device.
+ */
+static bool
+rpi_fb_init(prop_dictionary_t dict)
+{
+	uint32_t width = 0, height = 0;
+	uint32_t res;
+	char *ptr;
+	int error;
+
+	if (get_bootconf_option(boot_args, "console",
+			      BOOTOPT_TYPE_STRING, &ptr)) {
+		if (rpi_fb_parse_mode(ptr, &width, &height) == false)
+			return false;
+		if (width == 0 || height == 0)
+			rpi_fb_get_edid_mode(&width, &height);
+		if (width == 0 || height == 0) {
+			width = RPI_FB_WIDTH;
+			height = RPI_FB_HEIGHT;
+		}
+	} else {
+		/* console= not specified, so only attach if EDID block found */
+		if (rpi_fb_get_edid_mode(&width, &height) == false)
+			return false;
+	}
+
+	if (width == 0 || height == 0)
+		return false;
+
+	vb_setfb.vbt_res.width = width;
+	vb_setfb.vbt_res.height = height;
+	vb_setfb.vbt_vres.width = width;
+	vb_setfb.vbt_vres.height = height;
+	error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_setfb,
+	    sizeof(vb_setfb), &res);
+	if (error) {
+		printf("%s: mbox request failed (%d)\n", __func__, error);
+		return false;
+	}
+
+	if (!vcprop_buffer_success_p(&vb_setfb.vb_hdr) ||
+	    !vcprop_tag_success_p(&vb_setfb.vbt_res.tag) ||
+	    !vcprop_tag_success_p(&vb_setfb.vbt_vres.tag) ||
+	    !vcprop_tag_success_p(&vb_setfb.vbt_depth.tag) ||
+	    !vcprop_tag_success_p(&vb_setfb.vbt_pixelorder.tag) ||
+	    !vcprop_tag_success_p(&vb_setfb.vbt_allocbuf.tag) ||
+	    !vcprop_tag_success_p(&vb_setfb.vbt_blank.tag) ||
+	    !vcprop_tag_success_p(&vb_setfb.vbt_pitch.tag)) {
+		printf("%s: prop tag failed\n", __func__);
+		return false;
+	}
+
+#ifdef VERBOSE_INIT_ARM
+	printf("%s: addr = 0x%x size = %d\n", __func__,
+	    vb_setfb.vbt_allocbuf.address,
+	    vb_setfb.vbt_allocbuf.size);
+	printf("%s: depth = %d\n", __func__, vb_setfb.vbt_depth.bpp);
+	printf("%s: pitch = %d\n", __func__,
+	    vb_setfb.vbt_pitch.linebytes);
+	printf("%s: width = %d height = %d\n", __func__,
+	    vb_setfb.vbt_res.width, vb_setfb.vbt_res.height);
+	printf("%s: vwidth = %d vheight = %d\n", __func__,
+	    vb_setfb.vbt_vres.width, vb_setfb.vbt_vres.height);
+#endif
+
+	if (vb_setfb.vbt_allocbuf.address == 0 ||
+	    vb_setfb.vbt_allocbuf.size == 0 ||
+	    vb_setfb.vbt_res.width == 0 ||
+	    vb_setfb.vbt_res.height == 0 ||
+	    vb_setfb.vbt_vres.width == 0 ||
+	    vb_setfb.vbt_vres.height == 0 ||
+	    vb_setfb.vbt_pitch.linebytes == 0) {
+		printf("%s: failed to set mode %ux%u\n", __func__,
+		    width, height);
+		return false;
+	}
+
+	prop_dictionary_set_uint32(dict, "width", vb_setfb.vbt_res.width);
+	prop_dictionary_set_uint32(dict, "height", vb_setfb.vbt_res.height);
+	prop_dictionary_set_uint8(dict, "depth", vb_setfb.vbt_depth.bpp);
+	prop_dictionary_set_uint16(dict, "linebytes",
+	    vb_setfb.vbt_pitch.linebytes);
+	prop_dictionary_set_uint32(dict, "address",
+	    vb_setfb.vbt_allocbuf.address);
+
+	return true;
+}
+#endif
 
 static void
 rpi_device_register(device_t dev, void *aux)
 {
 	prop_dictionary_t dict = device_properties(dev);
 
+#if NSDHC > 0
 	if (device_is_a(dev, "sdhc") &&
 	    vcprop_tag_success_p(&vb.vbt_emmcclockrate.tag)) {
 		prop_dictionary_set_uint32(dict,
 		    "frequency", vb.vbt_emmcclockrate.rate);
 	}
+#endif
+
+#if NGENFB > 0
+	if (device_is_a(dev, "genfb")) {
+		if (rpi_fb_init(dict) == false)
+			return;
+		prop_dictionary_set_bool(dict, "is_console", true);
+	}
+#endif
 }

Reply via email to