diff mbox

[U-Boot] ppc4xx: Support dual link OSD

Message ID 1294662805-11704-3-git-send-email-eibach@gdsys.de
State Superseded
Delegated to: Stefan Roese
Headers show

Commit Message

Dirk Eibach Jan. 10, 2011, 12:33 p.m. UTC
Add support for dual link osd hardware for gdsys 405ep.

Signed-off-by: Dirk Eibach <eibach@gdsys.de>
---
 board/gdsys/405ep/dlvision-10g.c |    3 +-
 board/gdsys/common/osd.c         |  303 ++++++++++++++++++++++++++++---------
 board/gdsys/common/osd.h         |    2 +-
 3 files changed, 232 insertions(+), 76 deletions(-)

Comments

Stefan Roese Jan. 12, 2011, 2:21 p.m. UTC | #1
Hi Dirk,

On Monday 10 January 2011 13:33:25 Dirk Eibach wrote:
> Add support for dual link osd hardware for gdsys 405ep.

This patch also changes many lines introduced by the 2 previous patches. Again 
I'm thinking if it makes more sense to squash all those 3 patches into one. 
Would be interesting to see the git diffstat (e.g. 8 files changed, 417 
insertions(+), 3 deletions(-)) of the single squashed patch compared to the 
summary of the 3 single patches.

What do you think?

Cheers,
Stefan

--
DENX Software Engineering GmbH,      MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich,  Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-0 Fax: (+49)-8142-66989-80 Email: office@denx.de
Wolfgang Denk Jan. 17, 2011, 10:04 p.m. UTC | #2
Dear Dirk Eibach,

In message <1294662805-11704-3-git-send-email-eibach@gdsys.de> you wrote:
> 
>  #define BASE_WIDTH 32
> @@ -38,12 +44,18 @@
>  enum {
>  	REG_CONTROL = 0x0010,
>  	REG_MPC3W_CONTROL = 0x001a,
> +	REG_EXT_INTERRUPT = 0x001c,
> +	REG_EXT_INTERRUPT_ENABLE = 0x001e,
> +	REG_IIC_WRITE_MAILBOX = 0x0030,
> +	REG_IIC_WRITE_MAILBOX_EXT = 0x0032,
> +	REG_IIC_READ_MAILBOX = 0x0034,
> +	REG_IIC_READ_MAILBOX_EXT = 0x0036,
>  	REG_VIDEOCONTROL = 0x0042,
> -	REG_OSDVERSION = 0x0100,
> -	REG_OSDFEATURES = 0x0102,
> -	REG_OSDCONTROL = 0x0104,
> -	REG_XY_SIZE = 0x0106,
> -	REG_VIDEOMEM = 0x0800,
> +	REG_OSDVERSION = CONFIG_SYS_FPGA_OSD_BASE + 0x0000,
> +	REG_OSDFEATURES = CONFIG_SYS_FPGA_OSD_BASE + 0x0002,
> +	REG_OSDCONTROL = CONFIG_SYS_FPGA_OSD_BASE + 0x0004,
> +	REG_XY_SIZE = CONFIG_SYS_FPGA_OSD_BASE + 0x0006,
> +	REG_VIDEOMEM = CONFIG_SYS_FPGA_OSD_MEM,

This has a certain smell to me - it smells like device accesses based
on a base + offset notation, which is not waht we want to see.  Why
don't you use proper C structs instead to describe your devices?

Best regards,

Wolfgang Denk
Dirk Eibach Jan. 18, 2011, 8:10 a.m. UTC | #3
> Dear Dirk Eibach,

Dear Wolfgang,

> ...
> >  #define BASE_WIDTH 32
> > @@ -38,12 +44,18 @@
> >  enum {
> >  	REG_CONTROL = 0x0010,
> >  	REG_MPC3W_CONTROL = 0x001a,
> > +	REG_EXT_INTERRUPT = 0x001c,
> > +	REG_EXT_INTERRUPT_ENABLE = 0x001e,
> > +	REG_IIC_WRITE_MAILBOX = 0x0030,
> > +	REG_IIC_WRITE_MAILBOX_EXT = 0x0032,
> > +	REG_IIC_READ_MAILBOX = 0x0034,
> > +	REG_IIC_READ_MAILBOX_EXT = 0x0036,
> >  	REG_VIDEOCONTROL = 0x0042,
> > -	REG_OSDVERSION = 0x0100,
> > -	REG_OSDFEATURES = 0x0102,
> > -	REG_OSDCONTROL = 0x0104,
> > -	REG_XY_SIZE = 0x0106,
> > -	REG_VIDEOMEM = 0x0800,
> > +	REG_OSDVERSION = CONFIG_SYS_FPGA_OSD_BASE + 0x0000,
> > +	REG_OSDFEATURES = CONFIG_SYS_FPGA_OSD_BASE + 0x0002,
> > +	REG_OSDCONTROL = CONFIG_SYS_FPGA_OSD_BASE + 0x0004,
> > +	REG_XY_SIZE = CONFIG_SYS_FPGA_OSD_BASE + 0x0006,
> > +	REG_VIDEOMEM = CONFIG_SYS_FPGA_OSD_MEM,
> 
> This has a certain smell to me - it smells like device 
> accesses based on a base + offset notation, which is not waht 
> we want to see.  Why don't you use proper C structs instead 
> to describe your devices?

yup, got me. I know you prefer C struct based register access while we
don't. I'm sure anyone has excellent reasons for his opinion, and I
don't want to start a discussion here which would probably lead nowhere.
So, if you insist, I will convert our code to C struct based access.
Maybe you could point me to a nice clean implementation in u-boot, so I
can use the semantics you prefer (e.g. how holes in address space are
labeled).

> Best regards,
> 
> Wolfgang Denk

Cheers
Dirk
Wolfgang Denk Jan. 18, 2011, 9:44 a.m. UTC | #4
Dear "Eibach, Dirk",

In message <48D3D52125C49B43AE880038E2E5314BB5BE30@SRV101.gdsys.de> you wrote:
>  
> So, if you insist, I will convert our code to C struct based access.

Please do.

> Maybe you could point me to a nice clean implementation in u-boot, so I
> can use the semantics you prefer (e.g. how holes in address space are
> labeled).

Check out any of the PPC header files. "Holes" are usually marked as
"reserved" - try for example

	grep reserved arch/powerpc/include/asm/*


Best regards,

Wolfgang Denk
diff mbox

Patch

diff --git a/board/gdsys/405ep/dlvision-10g.c b/board/gdsys/405ep/dlvision-10g.c
index c217dfe..740cceb 100644
--- a/board/gdsys/405ep/dlvision-10g.c
+++ b/board/gdsys/405ep/dlvision-10g.c
@@ -235,7 +235,8 @@  int last_stage_init(void)
 	unsigned k;
 
 	for (k = 0; k < CONFIG_SYS_OSD_SCREENS; ++k)
-		if (!get_fpga_state(k))
+		if (!get_fpga_state(k)
+		    || (get_fpga_state(k) == FPGA_STATE_DONE_FAILED))
 			osd_probe(k);
 
 	return 0;
diff --git a/board/gdsys/common/osd.c b/board/gdsys/common/osd.c
index 239c870..9968dbf 100644
--- a/board/gdsys/common/osd.c
+++ b/board/gdsys/common/osd.c
@@ -29,6 +29,12 @@ 
 
 #define CH7301_I2C_ADDR 0x75
 
+#define ICS8N3QV01_I2C_ADDR 0x6E
+#define ICS8N3QV01_FREF 114285
+
+#define SIL1178_MASTER_I2C_ADDRESS 0x38
+#define SIL1178_SLAVE_I2C_ADDRESS 0x39
+
 #define PIXCLK_640_480_60 25180000
 
 #define BASE_WIDTH 32
@@ -38,12 +44,18 @@ 
 enum {
 	REG_CONTROL = 0x0010,
 	REG_MPC3W_CONTROL = 0x001a,
+	REG_EXT_INTERRUPT = 0x001c,
+	REG_EXT_INTERRUPT_ENABLE = 0x001e,
+	REG_IIC_WRITE_MAILBOX = 0x0030,
+	REG_IIC_WRITE_MAILBOX_EXT = 0x0032,
+	REG_IIC_READ_MAILBOX = 0x0034,
+	REG_IIC_READ_MAILBOX_EXT = 0x0036,
 	REG_VIDEOCONTROL = 0x0042,
-	REG_OSDVERSION = 0x0100,
-	REG_OSDFEATURES = 0x0102,
-	REG_OSDCONTROL = 0x0104,
-	REG_XY_SIZE = 0x0106,
-	REG_VIDEOMEM = 0x0800,
+	REG_OSDVERSION = CONFIG_SYS_FPGA_OSD_BASE + 0x0000,
+	REG_OSDFEATURES = CONFIG_SYS_FPGA_OSD_BASE + 0x0002,
+	REG_OSDCONTROL = CONFIG_SYS_FPGA_OSD_BASE + 0x0004,
+	REG_XY_SIZE = CONFIG_SYS_FPGA_OSD_BASE + 0x0006,
+	REG_VIDEOMEM = CONFIG_SYS_FPGA_OSD_MEM,
 };
 
 enum {
@@ -67,6 +79,37 @@  enum {
 	CH7301_DSP = 0x56,		/* DVI Sync polarity Register */
 };
 
+#if defined(CONFIG_SYS_ICS8N3QV01) || defined(CONFIG_SYS_SIL1178)
+static void fpga_iic_write(unsigned screen, u8 slave, u8 reg, u8 data)
+{
+	while (fpga_get_reg(screen, REG_EXT_INTERRUPT) & (1 << 12))
+		;
+	fpga_set_reg(screen, REG_IIC_WRITE_MAILBOX_EXT,
+		reg | (data << 8));
+	fpga_set_reg(screen, REG_IIC_WRITE_MAILBOX,
+		0xc400 | (slave << 1));
+}
+
+static u8 fpga_iic_read(unsigned screen, u8 slave, u8 reg)
+{
+	unsigned int ctr = 0;
+	while (fpga_get_reg(screen, REG_EXT_INTERRUPT) & (1 << 12))
+		;
+	fpga_set_reg(screen, REG_EXT_INTERRUPT, 1 << 14);
+	fpga_set_reg(screen, REG_IIC_WRITE_MAILBOX_EXT, reg);
+	fpga_set_reg(screen, REG_IIC_WRITE_MAILBOX, 0xc000 | (slave << 1));
+	while (!(fpga_get_reg(screen, REG_EXT_INTERRUPT) & (1 << 14))) {
+		udelay(100000);
+		if (ctr++ > 5) {
+			printf("iic receive timeout\n");
+			break;
+		}
+	}
+	return fpga_get_reg(screen, REG_IIC_READ_MAILBOX_EXT) >> 8;
+}
+#endif
+
+#ifdef CONFIG_SYS_MPC92469AC
 static void mpc92469ac_calc_parameters(unsigned int fout,
 	unsigned int *post_div, unsigned int *feedback_div)
 {
@@ -92,7 +135,7 @@  static void mpc92469ac_calc_parameters(unsigned int fout,
 	*feedback_div = m;
 }
 
-static void mpc92469ac_set(unsigned int fout)
+static void mpc92469ac_set(unsigned screen, unsigned int fout)
 {
 	unsigned int n;
 	unsigned int m;
@@ -114,17 +157,83 @@  static void mpc92469ac_set(unsigned int fout)
 		break;
 	}
 
-	fpga_set_reg(REG_MPC3W_CONTROL, (bitval << 9) | m);
+	fpga_set_reg(screen, REG_MPC3W_CONTROL, (bitval << 9) | m);
 }
+#endif
 
-static int osd_write_videomem(unsigned offset, u16 *data, size_t charcount)
+#ifdef CONFIG_SYS_ICS8N3QV01
+static void ics8n3qv01_calc_parameters(unsigned int fout,
+	unsigned int *_mint, unsigned int *_mfrac,
+	unsigned int *_n)
+{
+	unsigned int n;
+	unsigned int foutiic;
+	unsigned int fvcoiic;
+	unsigned int mint;
+	unsigned long long mfrac;
+
+	n = 2550000000U / fout;
+	if ((n & 1) && (n > 5))
+		n -= 1;
+
+	foutiic = fout - (fout / 10000);
+	fvcoiic = foutiic * n;
+
+	mint = fvcoiic / 114285000;
+	if ((mint < 17) || (mint > 63))
+		printf("ics8n3qv01_calc_parameters: cannot determine mint\n");
+
+	mfrac = ((unsigned long long)fvcoiic % 114285000LL) * 262144LL
+		/ 114285000LL;
+
+	*_mint = mint;
+	*_mfrac = mfrac;
+	*_n = n;
+}
+
+static void ics8n3qv01_set(unsigned screen, unsigned int fout)
+{
+	unsigned int n;
+	unsigned int mint;
+	unsigned int mfrac;
+	u8 reg0, reg4, reg8, reg12, reg18, reg20;
+
+	ics8n3qv01_calc_parameters(fout, &mint, &mfrac, &n);
+
+	reg0 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 0) & 0xc0;
+	reg0 |= (mint & 0x1f) << 1;
+	reg0 |= (mfrac >> 17) & 0x01;
+	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 0, reg0);
+
+	reg4 = mfrac >> 9;
+	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 4, reg4);
+
+	reg8 = mfrac >> 1;
+	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 8, reg8);
+
+	reg12 = mfrac << 7;
+	reg12 |= n & 0x7f;
+	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 12, reg12);
+
+	reg18 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 18) & 0x03;
+	reg18 |= 0x20;
+	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 18, reg18);
+
+	reg20 = fpga_iic_read(screen, ICS8N3QV01_I2C_ADDR, 20) & 0x1f;
+	reg20 |= mint & (1 << 5);
+	fpga_iic_write(screen, ICS8N3QV01_I2C_ADDR, 20, reg20);
+}
+#endif
+
+static int osd_write_videomem(unsigned screen, unsigned offset,
+	u16 *data, size_t charcount)
 {
 	unsigned int k;
 
 	for (k = 0; k < charcount; ++k) {
 		if (offset + k >= BUFSIZE)
 			return -1;
-		fpga_set_reg(REG_VIDEOMEM + 2 * (offset + k), data[k]);
+		fpga_set_reg(screen, REG_VIDEOMEM + 2 * (offset + k), data[k]);
 	}
 
 	return charcount;
@@ -132,46 +241,57 @@  static int osd_write_videomem(unsigned offset, u16 *data, size_t charcount)
 
 static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	unsigned x;
-	unsigned y;
-	unsigned charcount;
-	unsigned len;
-	u8 color;
-	unsigned int k;
-	u16 buf[BUFSIZE];
-	char *text;
-
-	if (argc < 5) {
-		return cmd_usage(cmdtp);
+	unsigned screen;
+
+	for (screen = 0; screen < CONFIG_SYS_OSD_SCREENS; ++screen) {
+		unsigned x;
+		unsigned y;
+		unsigned charcount;
+		unsigned len;
+		u8 color;
+		unsigned int k;
+		u16 buf[BUFSIZE];
+		char *text;
+		int res;
+
+		if (argc < 5) {
+			cmd_usage(cmdtp);
+			return 1;
+		}
+
+		x = simple_strtoul(argv[1], NULL, 16);
+		y = simple_strtoul(argv[2], NULL, 16);
+		color = simple_strtoul(argv[3], NULL, 16);
+		text = argv[4];
+		charcount = strlen(text);
+		len = (charcount > BUFSIZE) ? BUFSIZE : charcount;
+
+		for (k = 0; k < len; ++k)
+			buf[k] = (text[k] << 8) | color;
+
+		res = osd_write_videomem(screen, y * BASE_WIDTH + x, buf, len);
+		if (res < 0)
+			return res;
 	}
 
-	x = simple_strtoul(argv[1], NULL, 16);
-	y = simple_strtoul(argv[2], NULL, 16);
-	color = simple_strtoul(argv[3], NULL, 16);
-	text = argv[4];
-	charcount = strlen(text);
-	len = (charcount > BUFSIZE) ? BUFSIZE : charcount;
-
-	for (k = 0; k < len; ++k)
-		buf[k] = (text[k] << 8) | color;
-
-	return osd_write_videomem(y * BASE_WIDTH + x, buf, len);
+	return 0;
 }
 
-int osd_probe(void)
+int osd_probe(unsigned screen)
 {
-	u8 value;
-	u16 version = fpga_get_reg(REG_OSDVERSION);
-	u16 features = fpga_get_reg(REG_OSDFEATURES);
+	u16 version = fpga_get_reg(screen, REG_OSDVERSION);
+	u16 features = fpga_get_reg(screen, REG_OSDFEATURES);
 	unsigned width;
 	unsigned height;
+	u8 value;
 
 	width = ((features & 0x3f00) >> 8) + 1;
 	height = (features & 0x001f) + 1;
 
-	printf("OSD:   Digital-OSD version %01d.%02d, %d" "x%d characters\n",
-		version/100, version%100, width, height);
+	printf("OSD%d:  Digital-OSD version %01d.%02d, %d" "x%d characters\n",
+		screen, version/100, version%100, width, height);
 
+#ifdef CONFIG_SYS_CH7301
 	value = i2c_reg_read(CH7301_I2C_ADDR, CH7301_DID);
 	if (value != 0x17) {
 		printf("       Probing CH7301 failed, DID %02x\n", value);
@@ -182,51 +302,86 @@  int osd_probe(void)
 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPF, 0x60);
 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_DC, 0x09);
 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_PM, 0xc0);
+#endif
 
-	mpc92469ac_set(PIXCLK_640_480_60);
-	fpga_set_reg(REG_VIDEOCONTROL, 0x0002);
-	fpga_set_reg(REG_OSDCONTROL, 0x0049);
+#ifdef CONFIG_SYS_MPC92469AC
+	mpc92469ac_set(screen, PIXCLK_640_480_60);
+#endif
 
-	fpga_set_reg(REG_XY_SIZE, ((32 - 1) << 8) | (16 - 1));
+#ifdef CONFIG_SYS_ICS8N3QV01
+	ics8n3qv01_set(screen, PIXCLK_640_480_60);
+#endif
+
+#ifdef CONFIG_SYS_SIL1178
+	value = fpga_iic_read(screen, SIL1178_SLAVE_I2C_ADDRESS, 0x02);
+	if (value != 0x06) {
+		printf("       Probing CH7301 SIL1178, DEV_IDL %02x\n", value);
+		return -1;
+	}
+	/* magic initialization sequence adapted from datasheet */
+	fpga_iic_write(screen, SIL1178_SLAVE_I2C_ADDRESS, 0x08, 0x36);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x44);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x4c);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0e, 0x10);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0a, 0x80);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x09, 0x30);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0c, 0x89);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x0d, 0x60);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x36);
+	fpga_iic_write(screen, SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x37);
+#endif
+
+	fpga_set_reg(screen, REG_VIDEOCONTROL, 0x0002);
+	fpga_set_reg(screen, REG_OSDCONTROL, 0x0049);
+
+	fpga_set_reg(screen, REG_XY_SIZE, ((32 - 1) << 8) | (16 - 1));
 
 	return 0;
 }
 
 int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	unsigned x;
-	unsigned y;
-	unsigned k;
-	u16 buffer[BASE_WIDTH];
-	char *rp;
-	u16 *wp = buffer;
-	unsigned count = (argc > 4) ?  simple_strtoul(argv[4], NULL, 16) : 1;
-
-	if ((argc < 4) || (strlen(argv[3]) % 4)) {
-		return cmd_usage(cmdtp);
-	}
-
-	x = simple_strtoul(argv[1], NULL, 16);
-	y = simple_strtoul(argv[2], NULL, 16);
-	rp = argv[3];
-
-
-	while (*rp) {
-		char substr[5];
-
-		memcpy(substr, rp, 4);
-		substr[4] = 0;
-		*wp = simple_strtoul(substr, NULL, 16);
-
-		rp += 4;
-		wp++;
-		if (wp - buffer > BASE_WIDTH)
-			break;
-	}
-
-	for (k = 0; k < count; ++k) {
-		unsigned offset = y * BASE_WIDTH + x + k * (wp - buffer);
-		osd_write_videomem(offset, buffer, wp - buffer);
+	unsigned screen;
+
+	for (screen = 0; screen < CONFIG_SYS_OSD_SCREENS; ++screen) {
+		unsigned x;
+		unsigned y;
+		unsigned k;
+		u16 buffer[BASE_WIDTH];
+		char *rp;
+		u16 *wp = buffer;
+		unsigned count = (argc > 4) ?
+			simple_strtoul(argv[4], NULL, 16) : 1;
+
+		if ((argc < 4) || (strlen(argv[3]) % 4)) {
+			cmd_usage(cmdtp);
+			return 1;
+		}
+
+		x = simple_strtoul(argv[1], NULL, 16);
+		y = simple_strtoul(argv[2], NULL, 16);
+		rp = argv[3];
+
+
+		while (*rp) {
+			char substr[5];
+
+			memcpy(substr, rp, 4);
+			substr[4] = 0;
+			*wp = simple_strtoul(substr, NULL, 16);
+
+			rp += 4;
+			wp++;
+			if (wp - buffer > BASE_WIDTH)
+				break;
+		}
+
+		for (k = 0; k < count; ++k) {
+			unsigned offset =
+				y * BASE_WIDTH + x + k * (wp - buffer);
+			osd_write_videomem(screen, offset, buffer,
+				wp - buffer);
+		}
 	}
 
 	return 0;
diff --git a/board/gdsys/common/osd.h b/board/gdsys/common/osd.h
index 4431cbc..c59d9c3 100644
--- a/board/gdsys/common/osd.h
+++ b/board/gdsys/common/osd.h
@@ -24,6 +24,6 @@ 
 #ifndef _OSD_H_
 #define _OSD_H_
 
-int osd_probe(void);
+int osd_probe(unsigned screen);
 
 #endif