mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/5] at91 framebuffer support
@ 2012-09-21 12:51 Jean-Christophe PLAGNIOL-VILLARD
  2012-09-21 12:55 ` [PATCH 1/5] video: add atmel lcdc frambuffer support Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-21 12:51 UTC (permalink / raw)
  To: barebox; +Cc: Nicolas Ferre

Hi,

	The following patch serie add the support of the Framebuffer on at91
	sam9261/sam9263 and sam9g45. The sam9x5 series is not yet supported as
	they use an other IP.

	And enable it on sam0m10g45ek (9263ek and 9261ek will be availlable
	later).

	This is based on the next branch

The following changes since commit 6392955f283389fa4fecb0e2d5d1837bcb83f480:

  Merge branch 'for-next/testing-menu' into next (2012-09-20 23:11:42 +0200)

are available in the git repository at:


  git://git.jcrosoft.org/barebox.git delivery/atmel_fb

for you to fetch changes up to a60a81609fdc332ca8b84d2b8633dc59f8aacbc8:

  at91sam9m10g45ek: add lcdc support (2012-09-21 20:49:25 +0800)

----------------------------------------------------------------
Jean-Christophe PLAGNIOL-VILLARD (5):
      video: add atmel lcdc frambuffer support
      at91sam9263: add atmel lcdc frambuffer support
      at91sam9261: add atmel lcdc frambuffer support
      at91sam9g45: add atmel lcdc frambuffer support
      at91sam9m10g45ek: add lcdc support

 arch/arm/boards/at91sam9m10g45ek/env/bin/boot_board |    7 +++
 arch/arm/boards/at91sam9m10g45ek/env/splash.png     |  Bin 0 -> 22747 bytes
 arch/arm/boards/at91sam9m10g45ek/init.c             |   35 +++++++++++++
 arch/arm/configs/at91sam9m10g45ek_defconfig         |   11 ++--
 arch/arm/mach-at91/at91sam9261.c                    |    1 +
 arch/arm/mach-at91/at91sam9261_devices.c            |   51 ++++++++++++++++++
 arch/arm/mach-at91/at91sam9263.c                    |    1 +
 arch/arm/mach-at91/at91sam9263_devices.c            |   40 +++++++++++++++
 arch/arm/mach-at91/at91sam9g45.c                    |    1 +
 arch/arm/mach-at91/at91sam9g45_devices.c            |   49 ++++++++++++++++++
 arch/arm/mach-at91/include/mach/atmel_lcdc.h        |  209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-at91/include/mach/board.h             |    4 ++
 drivers/video/Kconfig                               |    4 ++
 drivers/video/Makefile                              |    1 +
 drivers/video/atmel_lcdfb.c                         |  477 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 15 files changed, 888 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/boards/at91sam9m10g45ek/env/splash.png
 create mode 100644 arch/arm/mach-at91/include/mach/atmel_lcdc.h
 create mode 100644 drivers/video/atmel_lcdfb.c

Best Regards,
J.

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/5] video: add atmel lcdc frambuffer support
  2012-09-21 12:51 [PATCH 0/5] at91 framebuffer support Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-21 12:55 ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-21 12:55   ` [PATCH 2/5] at91sam9263: " Jean-Christophe PLAGNIOL-VILLARD
                     ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-21 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Nicolas Ferre

This IP is present on the at91sam9 until the sam9g45, on the sam9x5 we use a
new IP.

This driver is based on the linux one.

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 arch/arm/mach-at91/include/mach/atmel_lcdc.h |  209 +++++++++++
 arch/arm/mach-at91/include/mach/board.h      |    4 +
 drivers/video/Kconfig                        |    4 +
 drivers/video/Makefile                       |    1 +
 drivers/video/atmel_lcdfb.c                  |  477 ++++++++++++++++++++++++++
 5 files changed, 695 insertions(+)
 create mode 100644 arch/arm/mach-at91/include/mach/atmel_lcdc.h
 create mode 100644 drivers/video/atmel_lcdfb.c

diff --git a/arch/arm/mach-at91/include/mach/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
new file mode 100644
index 0000000..a85e4b8
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
@@ -0,0 +1,209 @@
+/*
+ *  Header file for AT91/AT32 LCD Controller
+ *
+ *  Data structure and register user interface
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ATMEL_LCDC_H__
+#define __ATMEL_LCDC_H__
+
+/* Way LCD wires are connected to the chip:
+ * Some Atmel chips use BGR color mode (instead of standard RGB)
+ * A swapped wiring onboard can bring to RGB mode.
+ */
+#define ATMEL_LCDC_WIRING_BGR	0
+#define ATMEL_LCDC_WIRING_RGB	1
+#define ATMEL_LCDC_WIRING_RGB555	2
+
+
+ /* LCD Controller info data structure, stored in device platform_data */
+struct atmel_lcdfb_info {
+	struct fb_info		info;
+	void __iomem		*mmio;
+	struct device_d		*device;
+
+	unsigned int		guard_time;
+	unsigned int 		smem_len;
+	struct clk		*bus_clk;
+	struct clk		*lcdc_clk;
+
+	bool			lcdcon_is_backlight;
+	bool			lcdcon_pol_negative;
+	u8			saved_lcdcon;
+
+	u8			default_bpp;
+	u8			lcd_wiring_mode;
+	unsigned int		default_lcdcon2;
+	unsigned int		default_dmacon;
+	void (*atmel_lcdfb_power_control)(int on);
+	u32			pseudo_palette[16];
+};
+
+#define ATMEL_LCDC_DMABADDR1	0x00
+#define ATMEL_LCDC_DMABADDR2	0x04
+#define ATMEL_LCDC_DMAFRMPT1	0x08
+#define ATMEL_LCDC_DMAFRMPT2	0x0c
+#define ATMEL_LCDC_DMAFRMADD1	0x10
+#define ATMEL_LCDC_DMAFRMADD2	0x14
+
+#define ATMEL_LCDC_DMAFRMCFG	0x18
+#define	ATMEL_LCDC_FRSIZE	(0x7fffff <<  0)
+#define	ATMEL_LCDC_BLENGTH_OFFSET	24
+#define	ATMEL_LCDC_BLENGTH	(0x7f     << ATMEL_LCDC_BLENGTH_OFFSET)
+
+#define ATMEL_LCDC_DMACON	0x1c
+#define	ATMEL_LCDC_DMAEN	(0x1 << 0)
+#define	ATMEL_LCDC_DMARST	(0x1 << 1)
+#define	ATMEL_LCDC_DMABUSY	(0x1 << 2)
+#define		ATMEL_LCDC_DMAUPDT	(0x1 << 3)
+#define		ATMEL_LCDC_DMA2DEN	(0x1 << 4)
+
+#define ATMEL_LCDC_DMA2DCFG	0x20
+#define		ATMEL_LCDC_ADDRINC_OFFSET	0
+#define		ATMEL_LCDC_ADDRINC		(0xffff)
+#define		ATMEL_LCDC_PIXELOFF_OFFSET	24
+#define		ATMEL_LCDC_PIXELOFF		(0x1f << 24)
+
+#define ATMEL_LCDC_LCDCON1	0x0800
+#define	ATMEL_LCDC_BYPASS	(1     <<  0)
+#define	ATMEL_LCDC_CLKVAL_OFFSET	12
+#define	ATMEL_LCDC_CLKVAL	(0x1ff << ATMEL_LCDC_CLKVAL_OFFSET)
+#define	ATMEL_LCDC_LINCNT	(0x7ff << 21)
+
+#define ATMEL_LCDC_LCDCON2	0x0804
+#define	ATMEL_LCDC_DISTYPE	(3 << 0)
+#define		ATMEL_LCDC_DISTYPE_STNMONO	(0 << 0)
+#define		ATMEL_LCDC_DISTYPE_STNCOLOR	(1 << 0)
+#define		ATMEL_LCDC_DISTYPE_TFT		(2 << 0)
+#define	ATMEL_LCDC_SCANMOD	(1 << 2)
+#define		ATMEL_LCDC_SCANMOD_SINGLE	(0 << 2)
+#define		ATMEL_LCDC_SCANMOD_DUAL		(1 << 2)
+#define	ATMEL_LCDC_IFWIDTH	(3 << 3)
+#define		ATMEL_LCDC_IFWIDTH_4		(0 << 3)
+#define		ATMEL_LCDC_IFWIDTH_8		(1 << 3)
+#define		ATMEL_LCDC_IFWIDTH_16		(2 << 3)
+#define	ATMEL_LCDC_PIXELSIZE	(7 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_1		(0 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_2		(1 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_4		(2 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_8		(3 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_16		(4 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_24		(5 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_32		(6 << 5)
+#define	ATMEL_LCDC_INVVD	(1 << 8)
+#define		ATMEL_LCDC_INVVD_NORMAL		(0 << 8)
+#define		ATMEL_LCDC_INVVD_INVERTED	(1 << 8)
+#define	ATMEL_LCDC_INVFRAME	(1 << 9 )
+#define		ATMEL_LCDC_INVFRAME_NORMAL	(0 << 9)
+#define		ATMEL_LCDC_INVFRAME_INVERTED	(1 << 9)
+#define	ATMEL_LCDC_INVLINE	(1 << 10)
+#define		ATMEL_LCDC_INVLINE_NORMAL	(0 << 10)
+#define		ATMEL_LCDC_INVLINE_INVERTED	(1 << 10)
+#define	ATMEL_LCDC_INVCLK	(1 << 11)
+#define		ATMEL_LCDC_INVCLK_NORMAL	(0 << 11)
+#define		ATMEL_LCDC_INVCLK_INVERTED	(1 << 11)
+#define	ATMEL_LCDC_INVDVAL	(1 << 12)
+#define		ATMEL_LCDC_INVDVAL_NORMAL	(0 << 12)
+#define		ATMEL_LCDC_INVDVAL_INVERTED	(1 << 12)
+#define	ATMEL_LCDC_CLKMOD	(1 << 15)
+#define		ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY	(0 << 15)
+#define		ATMEL_LCDC_CLKMOD_ALWAYSACTIVE	(1 << 15)
+#define	ATMEL_LCDC_MEMOR	(1 << 31)
+#define		ATMEL_LCDC_MEMOR_BIG		(0 << 31)
+#define		ATMEL_LCDC_MEMOR_LITTLE		(1 << 31)
+
+#define ATMEL_LCDC_TIM1		0x0808
+#define	ATMEL_LCDC_VFP		(0xffU <<  0)
+#define	ATMEL_LCDC_VBP_OFFSET		8
+#define	ATMEL_LCDC_VBP		(0xffU <<  ATMEL_LCDC_VBP_OFFSET)
+#define	ATMEL_LCDC_VPW_OFFSET		16
+#define	ATMEL_LCDC_VPW		(0x3fU << ATMEL_LCDC_VPW_OFFSET)
+#define	ATMEL_LCDC_VHDLY_OFFSET		24
+#define	ATMEL_LCDC_VHDLY	(0xfU  << ATMEL_LCDC_VHDLY_OFFSET)
+
+#define ATMEL_LCDC_TIM2		0x080c
+#define	ATMEL_LCDC_HBP		(0xffU  <<  0)
+#define	ATMEL_LCDC_HPW_OFFSET		8
+#define	ATMEL_LCDC_HPW		(0x3fU  <<  ATMEL_LCDC_HPW_OFFSET)
+#define	ATMEL_LCDC_HFP_OFFSET		21
+#define	ATMEL_LCDC_HFP		(0x7ffU << ATMEL_LCDC_HFP_OFFSET)
+
+#define ATMEL_LCDC_LCDFRMCFG	0x0810
+#define	ATMEL_LCDC_LINEVAL	(0x7ff <<  0)
+#define	ATMEL_LCDC_HOZVAL_OFFSET	21
+#define	ATMEL_LCDC_HOZVAL	(0x7ff << ATMEL_LCDC_HOZVAL_OFFSET)
+
+#define ATMEL_LCDC_FIFO		0x0814
+#define	ATMEL_LCDC_FIFOTH	(0xffff)
+
+#define ATMEL_LCDC_MVAL		0x0818
+
+#define ATMEL_LCDC_DP1_2	0x081c
+#define ATMEL_LCDC_DP4_7	0x0820
+#define ATMEL_LCDC_DP3_5	0x0824
+#define ATMEL_LCDC_DP2_3	0x0828
+#define ATMEL_LCDC_DP5_7	0x082c
+#define ATMEL_LCDC_DP3_4	0x0830
+#define ATMEL_LCDC_DP4_5	0x0834
+#define ATMEL_LCDC_DP6_7	0x0838
+#define	ATMEL_LCDC_DP1_2_VAL	(0xff)
+#define	ATMEL_LCDC_DP4_7_VAL	(0xfffffff)
+#define	ATMEL_LCDC_DP3_5_VAL	(0xfffff)
+#define	ATMEL_LCDC_DP2_3_VAL	(0xfff)
+#define	ATMEL_LCDC_DP5_7_VAL	(0xfffffff)
+#define	ATMEL_LCDC_DP3_4_VAL	(0xffff)
+#define	ATMEL_LCDC_DP4_5_VAL	(0xfffff)
+#define	ATMEL_LCDC_DP6_7_VAL	(0xfffffff)
+
+#define ATMEL_LCDC_PWRCON	0x083c
+#define	ATMEL_LCDC_PWR		(1    <<  0)
+#define	ATMEL_LCDC_GUARDT_OFFSET	1
+#define	ATMEL_LCDC_GUARDT	(0x7f <<  ATMEL_LCDC_GUARDT_OFFSET)
+#define	ATMEL_LCDC_BUSY		(1    << 31)
+
+#define ATMEL_LCDC_CONTRAST_CTR	0x0840
+#define	ATMEL_LCDC_PS		(3 << 0)
+#define		ATMEL_LCDC_PS_DIV1		(0 << 0)
+#define		ATMEL_LCDC_PS_DIV2		(1 << 0)
+#define		ATMEL_LCDC_PS_DIV4		(2 << 0)
+#define		ATMEL_LCDC_PS_DIV8		(3 << 0)
+#define	ATMEL_LCDC_POL		(1 << 2)
+#define		ATMEL_LCDC_POL_NEGATIVE		(0 << 2)
+#define		ATMEL_LCDC_POL_POSITIVE		(1 << 2)
+#define	ATMEL_LCDC_ENA		(1 << 3)
+#define		ATMEL_LCDC_ENA_PWMDISABLE	(0 << 3)
+#define		ATMEL_LCDC_ENA_PWMENABLE	(1 << 3)
+
+#define ATMEL_LCDC_CONTRAST_VAL	0x0844
+#define	ATMEL_LCDC_CVAL	(0xff)
+
+#define ATMEL_LCDC_IER		0x0848
+#define ATMEL_LCDC_IDR		0x084c
+#define ATMEL_LCDC_IMR		0x0850
+#define ATMEL_LCDC_ISR		0x0854
+#define ATMEL_LCDC_ICR		0x0858
+#define	ATMEL_LCDC_LNI		(1 << 0)
+#define	ATMEL_LCDC_LSTLNI	(1 << 1)
+#define	ATMEL_LCDC_EOFI		(1 << 2)
+#define	ATMEL_LCDC_UFLWI	(1 << 4)
+#define	ATMEL_LCDC_OWRI		(1 << 5)
+#define	ATMEL_LCDC_MERI		(1 << 6)
+
+#define ATMEL_LCDC_LUT(n)	(0x0c00 + ((n)*4))
+
+#endif /* __ATMEL_LCDC_H__ */
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 670c73d..a720a36 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -23,6 +23,8 @@
 #include <net.h>
 #include <spi/spi.h>
 #include <linux/mtd/mtd.h>
+#include <fb.h>
+#include <mach/atmel_lcdc.h>
 
  /* USB Host */
 struct at91_usbh_data {
@@ -154,4 +156,6 @@ struct at91_spi_platform_data {
 };
 
 void at91_add_device_spi(int spi_id, struct at91_spi_platform_data *pdata);
+
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
 #endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 519cdbf..38dbb7a 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -5,6 +5,10 @@ menuconfig VIDEO
 
 if VIDEO
 
+config DRIVER_VIDEO_ATMEL
+	bool "Atmel LCDC framebuffer driver"
+	depends on ARCH_AT91
+
 config DRIVER_VIDEO_IMX
 	bool "i.MX framebuffer driver"
 	depends on ARCH_IMX1 || ARCH_IMX21 || ARCH_IMX25 || ARCH_IMX27
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 913c78d..dcadcf6 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_DRIVER_VIDEO_IMX) += imx.o
 obj-$(CONFIG_DRIVER_VIDEO_IMX_IPU) += imx-ipu-fb.o
 obj-$(CONFIG_DRIVER_VIDEO_S3C24XX) += s3c24xx.o
 obj-$(CONFIG_DRIVER_VIDEO_PXA) += pxa.o
+obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
new file mode 100644
index 0000000..8659836
--- /dev/null
+++ b/drivers/video/atmel_lcdfb.c
@@ -0,0 +1,477 @@
+/*
+ * Driver for AT91/AT32 LCD Controller
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <io.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <fb.h>
+#include <mach/atmel_lcdc.h>
+#include <mach/hardware.h>
+#include <mach/io.h>
+#include <mach/cpu.h>
+#include <errno.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <asm/mmu.h>
+
+#define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
+#define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
+
+/* configurable parameters */
+#define ATMEL_LCDC_CVAL_DEFAULT		0xc8
+#define ATMEL_LCDC_DMA_BURST_LEN	8	/* words */
+#define ATMEL_LCDC_FIFO_SIZE		512	/* words */
+
+static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+{
+	clk_enable(sinfo->bus_clk);
+	clk_enable(sinfo->lcdc_clk);
+}
+
+static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+{
+	clk_disable(sinfo->bus_clk);
+	clk_disable(sinfo->lcdc_clk);
+}
+
+static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+{
+	unsigned long value;
+
+	if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+		|| cpu_is_at32ap7000()))
+		return xres;
+
+	value = xres;
+	if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+		/* STN display */
+		if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR)
+			value *= 3;
+
+		if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+		   || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+		      && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+			value = DIV_ROUND_UP(value, 4);
+		else
+			value = DIV_ROUND_UP(value, 8);
+	}
+
+	return value;
+}
+
+static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+{
+	/* Turn off the LCD controller and the DMA controller */
+	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+			sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+	/* Wait for the LCDC core to become idle */
+	while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
+		mdelay(10);
+
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+}
+
+static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
+{
+	atmel_lcdfb_stop_nowait(sinfo);
+
+	/* Wait for DMA engine to become idle... */
+	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+		mdelay(10);
+}
+
+static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+{
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+		(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+		| ATMEL_LCDC_PWR);
+}
+
+/**
+ * @param fb_info Framebuffer information
+ */
+static void atmel_lcdc_enable_controller(struct fb_info *fb_info)
+{
+	struct atmel_lcdfb_info *sinfo = fb_info->priv;
+
+	if (sinfo->atmel_lcdfb_power_control)
+		sinfo->atmel_lcdfb_power_control(1);
+}
+
+/**
+ * @param fb_info Framebuffer information
+ */
+static void atmel_lcdc_disable_controller(struct fb_info *fb_info)
+{
+	struct atmel_lcdfb_info *sinfo = fb_info->priv;
+
+	if (sinfo->atmel_lcdfb_power_control)
+		sinfo->atmel_lcdfb_power_control(0);
+}
+
+static void atmel_lcdfb_update_dma(struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->priv;
+	unsigned long dma_addr;
+
+	dma_addr = (unsigned long)info->screen_base;
+
+	dma_addr &= ~3UL;
+
+	/* Set framebuffer DMA base address and pixel offset */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+}
+
+static void atmel_lcdfb_set_par(struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->priv;
+	struct fb_videomode *mode = info->mode;
+	unsigned long clk_value_khz;
+	unsigned long value;
+	unsigned long pix_factor = 2;
+	unsigned long hozval_linesz;
+
+	atmel_lcdfb_stop(sinfo);
+
+	/* Re-initialize the DMA engine... */
+	dev_dbg(&info->dev, "  * update DMA engine\n");
+	atmel_lcdfb_update_dma(info);
+
+	/* ...set frame size and burst length = 8 words (?) */
+	value = (mode->yres * mode->xres * info->bits_per_pixel) / 32;
+	value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+	lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+
+	/* Now, the LCDC core... */
+
+	/* Set pixel clock */
+	if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+		pix_factor = 1;
+
+	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+	value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(mode->pixclock));
+
+	if (value < pix_factor) {
+		dev_notice(&info->dev, "Bypassing pixel clock divider\n");
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+	} else {
+		value = (value / pix_factor) - 1;
+		dev_dbg(&info->dev, "  * programming CLKVAL = 0x%08lx\n",
+				value);
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+				value << ATMEL_LCDC_CLKVAL_OFFSET);
+		mode->pixclock =
+			KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
+		dev_dbg(&info->dev, "  updated pixclk:     %lu KHz\n",
+					PICOS2KHZ(mode->pixclock));
+	}
+
+	/* Initialize control register 2 */
+	value = sinfo->default_lcdcon2;
+
+	if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
+		value |= ATMEL_LCDC_INVLINE_INVERTED;
+	if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
+		value |= ATMEL_LCDC_INVFRAME_INVERTED;
+
+	switch (info->bits_per_pixel) {
+		case 1:	value |= ATMEL_LCDC_PIXELSIZE_1; break;
+		case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+		case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+		case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+		case 15: /* fall through */
+		case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+		case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+		case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+		default: BUG(); break;
+	}
+	dev_dbg(&info->dev, "  * LCDCON2 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+
+	/* Vertical timing */
+	value = (mode->vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+	value |= mode->upper_margin << ATMEL_LCDC_VBP_OFFSET;
+	value |= mode->lower_margin;
+	dev_dbg(&info->dev, "  * LCDTIM1 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+
+	/* Horizontal timing */
+	value = (mode->right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+	value |= (mode->hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+	value |= (mode->left_margin - 1);
+	dev_dbg(&info->dev, "  * LCDTIM2 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+
+	/* Horizontal value (aka line size) */
+	hozval_linesz = compute_hozval(mode->xres,
+					lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+
+	/* Display size */
+	value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+	value |= mode->yres - 1;
+	dev_dbg(&info->dev, "  * LCDFRMCFG = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+
+	/* FIFO Threshold: Use formula from data sheet */
+	value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+	lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+
+	/* Toggle LCD_MODE every frame */
+	lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+
+	/* Disable all interrupts */
+	lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+	/* Enable FIFO & DMA errors */
+	lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+
+	/* ...wait for DMA engine to become idle... */
+	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+		mdelay(10);
+
+	atmel_lcdfb_start(sinfo);
+
+	dev_dbg(&info->dev, "  * DONE\n");
+}
+
+static int atmel_lcdfb_check_var(struct fb_info *info)
+{
+	struct device_d *dev = &info->dev;
+	struct atmel_lcdfb_info *sinfo = info->priv;
+	struct fb_videomode *mode = info->mode;
+	unsigned long clk_value_khz;
+
+	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+	dev_dbg(dev, "%s:\n", __func__);
+
+	if (!(mode->pixclock && info->bits_per_pixel)) {
+		dev_err(dev, "needed value not specified\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "  resolution: %ux%u\n", mode->xres, mode->yres);
+	dev_dbg(dev, "  pixclk:     %lu KHz\n", PICOS2KHZ(mode->pixclock));
+	dev_dbg(dev, "  bpp:        %u\n", info->bits_per_pixel);
+	dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
+
+	if (PICOS2KHZ(mode->pixclock) > clk_value_khz) {
+		dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(mode->pixclock));
+		return -EINVAL;
+	}
+
+	/* Saturate vertical and horizontal timings at maximum values */
+	mode->vsync_len = min_t(u32, mode->vsync_len,
+			(ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+	mode->upper_margin = min_t(u32, mode->upper_margin,
+			ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+	mode->lower_margin = min_t(u32, mode->lower_margin,
+			ATMEL_LCDC_VFP);
+	mode->right_margin = min_t(u32, mode->right_margin,
+			(ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+	mode->hsync_len = min_t(u32, mode->hsync_len,
+			(ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+	mode->left_margin = min_t(u32, mode->left_margin,
+			ATMEL_LCDC_HBP + 1);
+
+	/* Some parameters can't be zero */
+	mode->vsync_len = max_t(u32, mode->vsync_len, 1);
+	mode->right_margin = max_t(u32, mode->right_margin, 1);
+	mode->hsync_len = max_t(u32, mode->hsync_len, 1);
+	mode->left_margin = max_t(u32, mode->left_margin, 1);
+
+	switch (info->bits_per_pixel) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		info->red.offset = info->green.offset = info->blue.offset = 0;
+		info->red.length = info->green.length = info->blue.length
+			= info->bits_per_pixel;
+		break;
+	case 16:
+		if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+			/* RGB:565 mode */
+			info->red.offset = 11;
+			info->blue.offset = 0;
+		} else {
+			/* BGR:565 mode */
+			info->red.offset = 0;
+			info->blue.offset = 11;
+		}
+		info->green.offset = 5;
+		info->green.length = 6;
+		info->red.length = info->blue.length = 5;
+		break;
+	case 32:
+		info->transp.offset = 24;
+		info->transp.length = 8;
+		/* fall through */
+	case 24:
+		if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+			/* RGB:888 mode */
+			info->red.offset = 16;
+			info->blue.offset = 0;
+		} else {
+			/* BGR:888 mode */
+			info->red.offset = 0;
+			info->blue.offset = 16;
+		}
+		info->green.offset = 8;
+		info->red.length = info->green.length = info->blue.length = 8;
+		break;
+	default:
+		dev_err(dev, "color depth %d not supported\n",
+					info->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = &sinfo->info;
+	struct fb_videomode *mode = info->mode;
+	unsigned int smem_len;
+
+	free(info->screen_base);
+
+	smem_len = (mode->xres * mode->yres
+		    * ((info->bits_per_pixel + 7) / 8));
+	smem_len = max(smem_len, sinfo->smem_len);
+
+	info->screen_base = dma_alloc_coherent(smem_len);
+
+	if (!info->screen_base)
+		return -ENOMEM;
+
+	memset(info->screen_base, 0, smem_len);
+
+	return 0;
+}
+
+/**
+ * Prepare the video hardware for a specified video mode
+ * @param fb_info Framebuffer information
+ * @param mode The video mode description to initialize
+ * @return 0 on success
+ */
+static int atmel_lcdc_activate_var(struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->priv;
+	unsigned long value;
+	int ret;
+
+	ret = atmel_lcdfb_alloc_video_memory(sinfo);
+	if (ret)
+		return ret;
+
+	atmel_lcdfb_set_par(info);
+
+	/* Set contrast */
+	value = ATMEL_LCDC_PS_DIV8 |
+		ATMEL_LCDC_POL_POSITIVE |
+		ATMEL_LCDC_ENA_PWMENABLE;
+	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
+	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+
+	return atmel_lcdfb_check_var(info);
+}
+
+/*
+ * There is only one video hardware instance available.
+ * It makes no sense to dynamically allocate this data
+ */
+static struct fb_ops atmel_lcdc_ops = {
+	.fb_activate_var = atmel_lcdc_activate_var,
+	.fb_enable = atmel_lcdc_enable_controller,
+	.fb_disable = atmel_lcdc_disable_controller,
+};
+
+static int atmel_lcdc_probe(struct device_d *hw_dev)
+{
+	struct atmel_lcdfb_info *sinfo = hw_dev->platform_data;
+	int ret = 0;
+	struct fb_info *info;
+
+	if (!sinfo)
+		return -ENODEV;
+
+	sinfo->mmio = dev_request_mem_region(hw_dev, 0);
+
+	/* just init */
+	info = &sinfo->info;
+	info->priv = sinfo;
+	info->fbops = &atmel_lcdc_ops,	
+	info->mode = &info->mode_list[0];
+	info->xres = info->mode->xres;
+	info->yres = info->mode->yres;
+	info->bits_per_pixel = sinfo->default_bpp;
+
+	/* Enable LCDC Clocks */
+	sinfo->bus_clk = clk_get(hw_dev, "hck1");
+	if (IS_ERR(sinfo->bus_clk)) {
+		ret = PTR_ERR(sinfo->bus_clk);
+		goto err;
+	}
+	sinfo->lcdc_clk = clk_get(hw_dev, "lcdc_clk");
+	if (IS_ERR(sinfo->lcdc_clk)) {
+		ret = PTR_ERR(sinfo->lcdc_clk);
+		goto put_bus_clk;
+	}
+
+	atmel_lcdfb_start_clock(sinfo);
+
+	ret = register_framebuffer(info);
+	if (ret != 0) {
+		dev_err(hw_dev, "Failed to register framebuffer\n");
+		goto stop_clk;
+	}
+
+	return ret;
+
+stop_clk:
+	atmel_lcdfb_stop_clock(sinfo);
+	clk_put(sinfo->lcdc_clk);
+put_bus_clk:
+	clk_put(sinfo->bus_clk);
+err:
+	return ret;
+}
+
+static struct driver_d atmel_lcdc_driver = {
+	.name	= "atmel_lcdfb",
+	.probe	= atmel_lcdc_probe,
+};
+
+static int atmel_lcdc_init(void)
+{
+	return register_driver(&atmel_lcdc_driver);
+}
+device_initcall(atmel_lcdc_init);
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/5] at91sam9263: add atmel lcdc frambuffer support
  2012-09-21 12:55 ` [PATCH 1/5] video: add atmel lcdc frambuffer support Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-21 12:55   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-21 12:55   ` [PATCH 3/5] at91sam9261: " Jean-Christophe PLAGNIOL-VILLARD
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-21 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Nicolas Ferre

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 arch/arm/mach-at91/at91sam9263.c         |    1 +
 arch/arm/mach-at91/at91sam9263_devices.c |   40 ++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index b3116d3..4f987d8 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -168,6 +168,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci1", &mmc1_clk),
 	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi0", &spi0_clk),
 	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi1", &spi1_clk),
+	CLKDEV_CON_DEV_ID("hck1", "atmel_lcdfb0", &lcdc_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index e686480..ba0b0b2 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -218,6 +218,46 @@ void at91_add_device_spi(int spi_id, struct at91_spi_platform_data *pdata)
 void __init at91_add_device_spi(int spi_id, struct at91_spi_platform_data *pdata) {}
 #endif
 
+
+/* --------------------------------------------------------------------
+ *  LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_DRIVER_VIDEO_ATMEL)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+	BUG_ON(!data);
+
+	at91_set_A_periph(AT91_PIN_PC1, 0);	/* LCDHSYNC */
+	at91_set_A_periph(AT91_PIN_PC2, 0);	/* LCDDOTCK */
+	at91_set_A_periph(AT91_PIN_PC3, 0);	/* LCDDEN */
+	at91_set_B_periph(AT91_PIN_PB9, 0);	/* LCDCC */
+	at91_set_A_periph(AT91_PIN_PC6, 0);	/* LCDD2 */
+	at91_set_A_periph(AT91_PIN_PC7, 0);	/* LCDD3 */
+	at91_set_A_periph(AT91_PIN_PC8, 0);	/* LCDD4 */
+	at91_set_A_periph(AT91_PIN_PC9, 0);	/* LCDD5 */
+	at91_set_A_periph(AT91_PIN_PC10, 0);	/* LCDD6 */
+	at91_set_A_periph(AT91_PIN_PC11, 0);	/* LCDD7 */
+	at91_set_A_periph(AT91_PIN_PC14, 0);	/* LCDD10 */
+	at91_set_A_periph(AT91_PIN_PC15, 0);	/* LCDD11 */
+	at91_set_A_periph(AT91_PIN_PC16, 0);	/* LCDD12 */
+	at91_set_B_periph(AT91_PIN_PC12, 0);	/* LCDD13 */
+	at91_set_A_periph(AT91_PIN_PC18, 0);	/* LCDD14 */
+	at91_set_A_periph(AT91_PIN_PC19, 0);	/* LCDD15 */
+	at91_set_A_periph(AT91_PIN_PC22, 0);	/* LCDD18 */
+	at91_set_A_periph(AT91_PIN_PC23, 0);	/* LCDD19 */
+	at91_set_A_periph(AT91_PIN_PC24, 0);	/* LCDD20 */
+	at91_set_B_periph(AT91_PIN_PC17, 0);	/* LCDD21 */
+	at91_set_A_periph(AT91_PIN_PC26, 0);	/* LCDD22 */
+	at91_set_A_periph(AT91_PIN_PC27, 0);	/* LCDD23 */
+
+	add_generic_device("atmel_lcdfb", 0, NULL, AT91SAM9263_LCDC_BASE, SZ_4K,
+			   IORESOURCE_MEM, data);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
 resource_size_t __init at91_configure_dbgu(void)
 {
 	at91_set_A_periph(AT91_PIN_PC30, 0);		/* DRXD */
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/5] at91sam9261: add atmel lcdc frambuffer support
  2012-09-21 12:55 ` [PATCH 1/5] video: add atmel lcdc frambuffer support Jean-Christophe PLAGNIOL-VILLARD
  2012-09-21 12:55   ` [PATCH 2/5] at91sam9263: " Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-21 12:55   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-21 12:55   ` [PATCH 4/5] at91sam9g45: " Jean-Christophe PLAGNIOL-VILLARD
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-21 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Nicolas Ferre

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 arch/arm/mach-at91/at91sam9261.c         |    1 +
 arch/arm/mach-at91/at91sam9261_devices.c |   51 ++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index d20b250..41e4d84 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -136,6 +136,7 @@ static struct clk *periph_clocks[] = {
 static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi0", &spi0_clk),
 	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi1", &spi1_clk),
+	CLKDEV_CON_DEV_ID("hck1", "atmel_lcdfb0", &lcdc_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 0091e2d..a32b4df 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -168,6 +168,57 @@ void at91_add_device_spi(int spi_id, struct at91_spi_platform_data *pdata)
 void __init at91_add_device_spi(int spi_id, struct at91_spi_platform_data *pdata) {}
 #endif
 
+/* --------------------------------------------------------------------
+ *  LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_DRIVER_VIDEO_ATMEL)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+	BUG_ON(!data);
+
+#if defined(CONFIG_FB_ATMEL_STN)
+	at91_set_A_periph(AT91_PIN_PB0, 0);	/* LCDVSYNC */
+	at91_set_A_periph(AT91_PIN_PB1, 0);	/* LCDHSYNC */
+	at91_set_A_periph(AT91_PIN_PB2, 0);	/* LCDDOTCK */
+	at91_set_A_periph(AT91_PIN_PB3, 0);	/* LCDDEN */
+	at91_set_A_periph(AT91_PIN_PB4, 0);	/* LCDCC */
+	at91_set_A_periph(AT91_PIN_PB5, 0);	/* LCDD0 */
+	at91_set_A_periph(AT91_PIN_PB6, 0);	/* LCDD1 */
+	at91_set_A_periph(AT91_PIN_PB7, 0);	/* LCDD2 */
+	at91_set_A_periph(AT91_PIN_PB8, 0);	/* LCDD3 */
+#else
+	at91_set_A_periph(AT91_PIN_PB1, 0);	/* LCDHSYNC */
+	at91_set_A_periph(AT91_PIN_PB2, 0);	/* LCDDOTCK */
+	at91_set_A_periph(AT91_PIN_PB3, 0);	/* LCDDEN */
+	at91_set_A_periph(AT91_PIN_PB4, 0);	/* LCDCC */
+	at91_set_A_periph(AT91_PIN_PB7, 0);	/* LCDD2 */
+	at91_set_A_periph(AT91_PIN_PB8, 0);	/* LCDD3 */
+	at91_set_A_periph(AT91_PIN_PB9, 0);	/* LCDD4 */
+	at91_set_A_periph(AT91_PIN_PB10, 0);	/* LCDD5 */
+	at91_set_A_periph(AT91_PIN_PB11, 0);	/* LCDD6 */
+	at91_set_A_periph(AT91_PIN_PB12, 0);	/* LCDD7 */
+	at91_set_A_periph(AT91_PIN_PB15, 0);	/* LCDD10 */
+	at91_set_A_periph(AT91_PIN_PB16, 0);	/* LCDD11 */
+	at91_set_A_periph(AT91_PIN_PB17, 0);	/* LCDD12 */
+	at91_set_A_periph(AT91_PIN_PB18, 0);	/* LCDD13 */
+	at91_set_A_periph(AT91_PIN_PB19, 0);	/* LCDD14 */
+	at91_set_A_periph(AT91_PIN_PB20, 0);	/* LCDD15 */
+	at91_set_B_periph(AT91_PIN_PB23, 0);	/* LCDD18 */
+	at91_set_B_periph(AT91_PIN_PB24, 0);	/* LCDD19 */
+	at91_set_B_periph(AT91_PIN_PB25, 0);	/* LCDD20 */
+	at91_set_B_periph(AT91_PIN_PB26, 0);	/* LCDD21 */
+	at91_set_B_periph(AT91_PIN_PB27, 0);	/* LCDD22 */
+	at91_set_B_periph(AT91_PIN_PB28, 0);	/* LCDD23 */
+#endif
+
+	add_generic_device("atmel_lcdfb", 0, NULL, AT91SAM9261_LCDC_BASE, SZ_4K,
+			   IORESOURCE_MEM, data);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
 resource_size_t __init at91_configure_dbgu(void)
 {
 	at91_set_A_periph(AT91_PIN_PA9, 0);		/* DRXD */
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 4/5] at91sam9g45: add atmel lcdc frambuffer support
  2012-09-21 12:55 ` [PATCH 1/5] video: add atmel lcdc frambuffer support Jean-Christophe PLAGNIOL-VILLARD
  2012-09-21 12:55   ` [PATCH 2/5] at91sam9263: " Jean-Christophe PLAGNIOL-VILLARD
  2012-09-21 12:55   ` [PATCH 3/5] at91sam9261: " Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-21 12:55   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-21 12:55   ` [PATCH 5/5] at91sam9m10g45ek: add lcdc support Jean-Christophe PLAGNIOL-VILLARD
  2012-09-22 10:34   ` [PATCH 1/5] video: add atmel lcdc frambuffer support Sascha Hauer
  4 siblings, 0 replies; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-21 12:55 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Nicolas Ferre <nicolas.ferre@atmel.com>
---
 arch/arm/mach-at91/at91sam9g45.c         |    1 +
 arch/arm/mach-at91/at91sam9g45_devices.c |   49 ++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index a6717f1..93e815f 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -190,6 +190,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci1", &mmc1_clk),
 	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi0", &spi0_clk),
 	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi1", &spi1_clk),
+	CLKDEV_CON_DEV_ID("hck1", "atmel_lcdfb0", &lcdc_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 22b455e..e08904b 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -324,3 +324,52 @@ void at91_add_device_spi(int spi_id, struct at91_spi_platform_data *pdata)
 #else
 void at91_add_device_spi(int spi_id, struct at91_spi_platform_data *pdata) {}
 #endif
+
+/* --------------------------------------------------------------------
+ *  LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_DRIVER_VIDEO_ATMEL)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+	BUG_ON(!data);
+
+	at91_set_A_periph(AT91_PIN_PE0, 0);	/* LCDDPWR */
+
+	at91_set_A_periph(AT91_PIN_PE2, 0);	/* LCDCC */
+	at91_set_A_periph(AT91_PIN_PE3, 0);	/* LCDVSYNC */
+	at91_set_A_periph(AT91_PIN_PE4, 0);	/* LCDHSYNC */
+	at91_set_A_periph(AT91_PIN_PE5, 0);	/* LCDDOTCK */
+	at91_set_A_periph(AT91_PIN_PE6, 0);	/* LCDDEN */
+	at91_set_A_periph(AT91_PIN_PE7, 0);	/* LCDD0 */
+	at91_set_A_periph(AT91_PIN_PE8, 0);	/* LCDD1 */
+	at91_set_A_periph(AT91_PIN_PE9, 0);	/* LCDD2 */
+	at91_set_A_periph(AT91_PIN_PE10, 0);	/* LCDD3 */
+	at91_set_A_periph(AT91_PIN_PE11, 0);	/* LCDD4 */
+	at91_set_A_periph(AT91_PIN_PE12, 0);	/* LCDD5 */
+	at91_set_A_periph(AT91_PIN_PE13, 0);	/* LCDD6 */
+	at91_set_A_periph(AT91_PIN_PE14, 0);	/* LCDD7 */
+	at91_set_A_periph(AT91_PIN_PE15, 0);	/* LCDD8 */
+	at91_set_A_periph(AT91_PIN_PE16, 0);	/* LCDD9 */
+	at91_set_A_periph(AT91_PIN_PE17, 0);	/* LCDD10 */
+	at91_set_A_periph(AT91_PIN_PE18, 0);	/* LCDD11 */
+	at91_set_A_periph(AT91_PIN_PE19, 0);	/* LCDD12 */
+	at91_set_A_periph(AT91_PIN_PE20, 0);	/* LCDD13 */
+	at91_set_A_periph(AT91_PIN_PE21, 0);	/* LCDD14 */
+	at91_set_A_periph(AT91_PIN_PE22, 0);	/* LCDD15 */
+	at91_set_A_periph(AT91_PIN_PE23, 0);	/* LCDD16 */
+	at91_set_A_periph(AT91_PIN_PE24, 0);	/* LCDD17 */
+	at91_set_A_periph(AT91_PIN_PE25, 0);	/* LCDD18 */
+	at91_set_A_periph(AT91_PIN_PE26, 0);	/* LCDD19 */
+	at91_set_A_periph(AT91_PIN_PE27, 0);	/* LCDD20 */
+	at91_set_A_periph(AT91_PIN_PE28, 0);	/* LCDD21 */
+	at91_set_A_periph(AT91_PIN_PE29, 0);	/* LCDD22 */
+	at91_set_A_periph(AT91_PIN_PE30, 0);	/* LCDD23 */
+
+	add_generic_device("atmel_lcdfb", 0, NULL, AT91SAM9G45_LCDC_BASE, SZ_4K,
+			   IORESOURCE_MEM, data);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 5/5] at91sam9m10g45ek: add lcdc support
  2012-09-21 12:55 ` [PATCH 1/5] video: add atmel lcdc frambuffer support Jean-Christophe PLAGNIOL-VILLARD
                     ` (2 preceding siblings ...)
  2012-09-21 12:55   ` [PATCH 4/5] at91sam9g45: " Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-21 12:55   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-22 10:34   ` [PATCH 1/5] video: add atmel lcdc frambuffer support Sascha Hauer
  4 siblings, 0 replies; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-21 12:55 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 .../arm/boards/at91sam9m10g45ek/env/bin/boot_board |    7 ++++
 arch/arm/boards/at91sam9m10g45ek/env/splash.png    |  Bin 0 -> 22747 bytes
 arch/arm/boards/at91sam9m10g45ek/init.c            |   35 ++++++++++++++++++++
 arch/arm/configs/at91sam9m10g45ek_defconfig        |   11 ++++--
 4 files changed, 50 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/boards/at91sam9m10g45ek/env/splash.png

diff --git a/arch/arm/boards/at91sam9m10g45ek/env/bin/boot_board b/arch/arm/boards/at91sam9m10g45ek/env/bin/boot_board
index 3d7426f..eeb7a76 100644
--- a/arch/arm/boards/at91sam9m10g45ek/env/bin/boot_board
+++ b/arch/arm/boards/at91sam9m10g45ek/env/bin/boot_board
@@ -5,6 +5,13 @@ export PATH
 
 . /env/config
 
+splash=/env/splash.png
+
+if [ -f ${splash} ]; then
+	splash ${splash}
+	fb0.enable=1
+fi
+
 menu -r -m boot
 menu -a -m boot -d "\e[1;36mWelcome on Barebox Boot Sequence\e[0m"
 menu -e -a -m boot -c 'menu_boot'			-d "boot (default)             "
diff --git a/arch/arm/boards/at91sam9m10g45ek/env/splash.png b/arch/arm/boards/at91sam9m10g45ek/env/splash.png
new file mode 100644
index 0000000000000000000000000000000000000000..08f2ac4fc106e6e38e503338b0fb047d20ac1f99
GIT binary patch
literal 22747
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

literal 0
HcmV?d00001

diff --git a/arch/arm/boards/at91sam9m10g45ek/init.c b/arch/arm/boards/at91sam9m10g45ek/init.c
index f1c43cc..d77c998 100644
--- a/arch/arm/boards/at91sam9m10g45ek/init.c
+++ b/arch/arm/boards/at91sam9m10g45ek/init.c
@@ -218,6 +218,40 @@ static int at91sam9m10g45ek_mem_init(void)
 }
 mem_initcall(at91sam9m10g45ek_mem_init);
 
+static struct fb_videomode at91_tft_vga_modes[] = {
+	{
+		.name           = "LG",
+		.refresh	= 60,
+		.xres		= 480,		.yres		= 272,
+		.pixclock	= KHZ2PICOS(9000),
+
+		.left_margin	= 1,		.right_margin	= 1,
+		.upper_margin	= 40,		.lower_margin	= 1,
+		.hsync_len	= 45,		.vsync_len	= 1,
+
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+};
+
+#define AT91SAM9G45_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
+					| ATMEL_LCDC_DISTYPE_TFT \
+					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+
+/* Driver datas */
+static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+	.lcdcon_is_backlight		= true,
+	.default_bpp			= 32,
+	.default_dmacon			= ATMEL_LCDC_DMAEN,
+	.default_lcdcon2		= AT91SAM9G45_DEFAULT_LCDCON2,
+	.guard_time			= 9,
+	.lcd_wiring_mode		= ATMEL_LCDC_WIRING_RGB,
+	.info = {
+		.mode_list		= at91_tft_vga_modes,
+		.num_modes		= ARRAY_SIZE(at91_tft_vga_modes),
+	},
+};
+
 static int at91sam9m10g45ek_devices_init(void)
 {
 	ek_add_device_nand();
@@ -225,6 +259,7 @@ static int at91sam9m10g45ek_devices_init(void)
 	ek_add_device_mci();
 	ek_device_add_leds();
 	ek_device_add_keyboard();
+	at91_add_device_lcdc(&ek_lcdc_data);
 
 	devfs_add_partition("nand0", 0x00000, SZ_128K, DEVFS_PARTITION_FIXED, "at91bootstrap_raw");
 	dev_add_bb_dev("at91bootstrap_raw", "at91bootstrap");
diff --git a/arch/arm/configs/at91sam9m10g45ek_defconfig b/arch/arm/configs/at91sam9m10g45ek_defconfig
index 1fa37d6..7e555b1 100644
--- a/arch/arm/configs/at91sam9m10g45ek_defconfig
+++ b/arch/arm/configs/at91sam9m10g45ek_defconfig
@@ -5,6 +5,7 @@ CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
 CONFIG_PBL_IMAGE=y
 CONFIG_MMU=y
 CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x40000
+CONFIG_MALLOC_SIZE=0x800000
 CONFIG_MALLOC_TLSF=y
 CONFIG_PROMPT="9M10G45-EK:"
 CONFIG_LONGHELP=y
@@ -29,8 +30,6 @@ CONFIG_CMD_PASSWD=y
 CONFIG_CMD_ECHO_E=y
 CONFIG_CMD_LOADB=y
 CONFIG_CMD_MEMINFO=y
-CONFIG_CMD_MTEST=y
-CONFIG_CMD_MTEST_ALTERNATIVE=y
 CONFIG_CMD_FLASH=y
 CONFIG_CMD_BOOTM_SHOW_TYPE=y
 CONFIG_CMD_BOOTM_VERBOSE=y
@@ -38,13 +37,17 @@ CONFIG_CMD_BOOTM_INITRD=y
 CONFIG_CMD_BOOTM_OFTREE=y
 CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y
 CONFIG_CMD_UIMAGE=y
+# CONFIG_CMD_BOOTU is not set
 CONFIG_CMD_RESET=y
 CONFIG_CMD_GO=y
 CONFIG_CMD_OFTREE=y
+CONFIG_CMD_MTEST=y
+CONFIG_CMD_MTEST_ALTERNATIVE=y
 CONFIG_CMD_TIMEOUT=y
 CONFIG_CMD_PARTITION=y
 CONFIG_CMD_MAGICVAR=y
 CONFIG_CMD_MAGICVAR_HELP=y
+CONFIG_CMD_SPLASH=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_UNCOMPRESS=y
 CONFIG_CMD_LED=y
@@ -66,6 +69,8 @@ CONFIG_NAND=y
 # CONFIG_NAND_ECC_HW_NONE is not set
 CONFIG_NAND_ATMEL=y
 CONFIG_UBI=y
+CONFIG_VIDEO=y
+CONFIG_DRIVER_VIDEO_ATMEL=y
 CONFIG_MCI=y
 CONFIG_MCI_STARTUP=y
 CONFIG_MCI_ATMEL=y
@@ -75,4 +80,4 @@ CONFIG_LED_TRIGGERS=y
 CONFIG_FS_FAT=y
 CONFIG_FS_FAT_WRITE=y
 CONFIG_FS_FAT_LFN=y
-CONFIG_LZO_DECOMPRESS=y
+CONFIG_PNG=y
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/5] video: add atmel lcdc frambuffer support
  2012-09-21 12:55 ` [PATCH 1/5] video: add atmel lcdc frambuffer support Jean-Christophe PLAGNIOL-VILLARD
                     ` (3 preceding siblings ...)
  2012-09-21 12:55   ` [PATCH 5/5] at91sam9m10g45ek: add lcdc support Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-22 10:34   ` Sascha Hauer
  2012-09-22 16:11     ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-22 17:44     ` Jean-Christophe PLAGNIOL-VILLARD
  4 siblings, 2 replies; 9+ messages in thread
From: Sascha Hauer @ 2012-09-22 10:34 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox, Nicolas Ferre

On Fri, Sep 21, 2012 at 02:55:29PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> This IP is present on the at91sam9 until the sam9g45, on the sam9x5 we use a
> new IP.
> 
> This driver is based on the linux one.
> 
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
>  arch/arm/mach-at91/include/mach/atmel_lcdc.h |  209 +++++++++++
>  arch/arm/mach-at91/include/mach/board.h      |    4 +
>  drivers/video/Kconfig                        |    4 +
>  drivers/video/Makefile                       |    1 +
>  drivers/video/atmel_lcdfb.c                  |  477 ++++++++++++++++++++++++++
>  5 files changed, 695 insertions(+)
>  create mode 100644 arch/arm/mach-at91/include/mach/atmel_lcdc.h
>  create mode 100644 drivers/video/atmel_lcdfb.c
> 
> diff --git a/arch/arm/mach-at91/include/mach/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h

The register definitions should be besides the driver, not in mach.

> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> new file mode 100644
> index 0000000..8659836
> --- /dev/null
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -0,0 +1,477 @@
> +/*
> + * Driver for AT91/AT32 LCD Controller
> + *
> + * Copyright (C) 2007 Atmel Corporation
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <io.h>
> +#include <init.h>
> +#include <linux/clk.h>
> +#include <fb.h>
> +#include <mach/atmel_lcdc.h>
> +#include <mach/hardware.h>
> +#include <mach/io.h>
> +#include <mach/cpu.h>
> +#include <errno.h>
> +#include <linux/err.h>
> +#include <malloc.h>
> +#include <asm/mmu.h>
> +
> +#define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
> +#define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
> +
> +/* configurable parameters */
> +#define ATMEL_LCDC_CVAL_DEFAULT		0xc8
> +#define ATMEL_LCDC_DMA_BURST_LEN	8	/* words */
> +#define ATMEL_LCDC_FIFO_SIZE		512	/* words */
> +
> +static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
> +{
> +	clk_enable(sinfo->bus_clk);
> +	clk_enable(sinfo->lcdc_clk);
> +}
> +
> +static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
> +{
> +	clk_disable(sinfo->bus_clk);
> +	clk_disable(sinfo->lcdc_clk);
> +}
> +
> +static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
> +{
> +	unsigned long value;
> +
> +	if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
> +		|| cpu_is_at32ap7000()))
> +		return xres;
> +
> +	value = xres;
> +	if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
> +		/* STN display */
> +		if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR)
> +			value *= 3;
> +
> +		if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
> +		   || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
> +		      && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
> +			value = DIV_ROUND_UP(value, 4);
> +		else
> +			value = DIV_ROUND_UP(value, 8);
> +	}
> +
> +	return value;
> +}
> +
> +static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
> +{
> +	/* Turn off the LCD controller and the DMA controller */
> +	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
> +			sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
> +
> +	/* Wait for the LCDC core to become idle */
> +	while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
> +		mdelay(10);
> +
> +	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
> +}
> +
> +static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
> +{
> +	atmel_lcdfb_stop_nowait(sinfo);
> +
> +	/* Wait for DMA engine to become idle... */
> +	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
> +		mdelay(10);
> +}
> +
> +static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
> +{
> +	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
> +	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
> +		(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
> +		| ATMEL_LCDC_PWR);
> +}
> +
> +/**
> + * @param fb_info Framebuffer information
> + */
> +static void atmel_lcdc_enable_controller(struct fb_info *fb_info)
> +{
> +	struct atmel_lcdfb_info *sinfo = fb_info->priv;
> +
> +	if (sinfo->atmel_lcdfb_power_control)
> +		sinfo->atmel_lcdfb_power_control(1);
> +}
> +
> +/**
> + * @param fb_info Framebuffer information
> + */
> +static void atmel_lcdc_disable_controller(struct fb_info *fb_info)
> +{
> +	struct atmel_lcdfb_info *sinfo = fb_info->priv;
> +
> +	if (sinfo->atmel_lcdfb_power_control)
> +		sinfo->atmel_lcdfb_power_control(0);
> +}
> +
> +static void atmel_lcdfb_update_dma(struct fb_info *info)
> +{
> +	struct atmel_lcdfb_info *sinfo = info->priv;
> +	unsigned long dma_addr;
> +
> +	dma_addr = (unsigned long)info->screen_base;
> +
> +	dma_addr &= ~3UL;
> +
> +	/* Set framebuffer DMA base address and pixel offset */
> +	lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
> +}
> +
> +static void atmel_lcdfb_set_par(struct fb_info *info)
> +{
> +	struct atmel_lcdfb_info *sinfo = info->priv;
> +	struct fb_videomode *mode = info->mode;
> +	unsigned long clk_value_khz;
> +	unsigned long value;
> +	unsigned long pix_factor = 2;
> +	unsigned long hozval_linesz;
> +
> +	atmel_lcdfb_stop(sinfo);
> +
> +	/* Re-initialize the DMA engine... */
> +	dev_dbg(&info->dev, "  * update DMA engine\n");
> +	atmel_lcdfb_update_dma(info);
> +
> +	/* ...set frame size and burst length = 8 words (?) */
> +	value = (mode->yres * mode->xres * info->bits_per_pixel) / 32;
> +	value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
> +	lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
> +
> +	/* Now, the LCDC core... */
> +
> +	/* Set pixel clock */
> +	if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
> +		pix_factor = 1;
> +
> +	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
> +
> +	value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(mode->pixclock));
> +
> +	if (value < pix_factor) {
> +		dev_notice(&info->dev, "Bypassing pixel clock divider\n");
> +		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
> +	} else {
> +		value = (value / pix_factor) - 1;
> +		dev_dbg(&info->dev, "  * programming CLKVAL = 0x%08lx\n",
> +				value);
> +		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
> +				value << ATMEL_LCDC_CLKVAL_OFFSET);
> +		mode->pixclock =
> +			KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
> +		dev_dbg(&info->dev, "  updated pixclk:     %lu KHz\n",
> +					PICOS2KHZ(mode->pixclock));
> +	}
> +
> +	/* Initialize control register 2 */
> +	value = sinfo->default_lcdcon2;
> +
> +	if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
> +		value |= ATMEL_LCDC_INVLINE_INVERTED;
> +	if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
> +		value |= ATMEL_LCDC_INVFRAME_INVERTED;
> +
> +	switch (info->bits_per_pixel) {
> +		case 1:	value |= ATMEL_LCDC_PIXELSIZE_1; break;
> +		case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
> +		case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
> +		case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
> +		case 15: /* fall through */
> +		case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
> +		case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
> +		case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
> +		default: BUG(); break;
> +	}
> +	dev_dbg(&info->dev, "  * LCDCON2 = %08lx\n", value);
> +	lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
> +
> +	/* Vertical timing */
> +	value = (mode->vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
> +	value |= mode->upper_margin << ATMEL_LCDC_VBP_OFFSET;
> +	value |= mode->lower_margin;
> +	dev_dbg(&info->dev, "  * LCDTIM1 = %08lx\n", value);
> +	lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
> +
> +	/* Horizontal timing */
> +	value = (mode->right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
> +	value |= (mode->hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
> +	value |= (mode->left_margin - 1);
> +	dev_dbg(&info->dev, "  * LCDTIM2 = %08lx\n", value);
> +	lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
> +
> +	/* Horizontal value (aka line size) */
> +	hozval_linesz = compute_hozval(mode->xres,
> +					lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
> +
> +	/* Display size */
> +	value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
> +	value |= mode->yres - 1;
> +	dev_dbg(&info->dev, "  * LCDFRMCFG = %08lx\n", value);
> +	lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
> +
> +	/* FIFO Threshold: Use formula from data sheet */
> +	value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
> +	lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
> +
> +	/* Toggle LCD_MODE every frame */
> +	lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
> +
> +	/* Disable all interrupts */
> +	lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
> +
> +	/* Enable FIFO & DMA errors */
> +	lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
> +
> +	/* ...wait for DMA engine to become idle... */
> +	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
> +		mdelay(10);
> +
> +	atmel_lcdfb_start(sinfo);
> +
> +	dev_dbg(&info->dev, "  * DONE\n");
> +}
> +
> +static int atmel_lcdfb_check_var(struct fb_info *info)
> +{
> +	struct device_d *dev = &info->dev;
> +	struct atmel_lcdfb_info *sinfo = info->priv;
> +	struct fb_videomode *mode = info->mode;
> +	unsigned long clk_value_khz;
> +
> +	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
> +
> +	dev_dbg(dev, "%s:\n", __func__);
> +
> +	if (!(mode->pixclock && info->bits_per_pixel)) {
> +		dev_err(dev, "needed value not specified\n");
> +		return -EINVAL;
> +	}
> +
> +	dev_dbg(dev, "  resolution: %ux%u\n", mode->xres, mode->yres);
> +	dev_dbg(dev, "  pixclk:     %lu KHz\n", PICOS2KHZ(mode->pixclock));
> +	dev_dbg(dev, "  bpp:        %u\n", info->bits_per_pixel);
> +	dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
> +
> +	if (PICOS2KHZ(mode->pixclock) > clk_value_khz) {
> +		dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(mode->pixclock));
> +		return -EINVAL;
> +	}
> +
> +	/* Saturate vertical and horizontal timings at maximum values */
> +	mode->vsync_len = min_t(u32, mode->vsync_len,
> +			(ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
> +	mode->upper_margin = min_t(u32, mode->upper_margin,
> +			ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
> +	mode->lower_margin = min_t(u32, mode->lower_margin,
> +			ATMEL_LCDC_VFP);
> +	mode->right_margin = min_t(u32, mode->right_margin,
> +			(ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
> +	mode->hsync_len = min_t(u32, mode->hsync_len,
> +			(ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
> +	mode->left_margin = min_t(u32, mode->left_margin,
> +			ATMEL_LCDC_HBP + 1);
> +
> +	/* Some parameters can't be zero */
> +	mode->vsync_len = max_t(u32, mode->vsync_len, 1);
> +	mode->right_margin = max_t(u32, mode->right_margin, 1);
> +	mode->hsync_len = max_t(u32, mode->hsync_len, 1);
> +	mode->left_margin = max_t(u32, mode->left_margin, 1);
> +
> +	switch (info->bits_per_pixel) {
> +	case 1:
> +	case 2:
> +	case 4:
> +	case 8:
> +		info->red.offset = info->green.offset = info->blue.offset = 0;
> +		info->red.length = info->green.length = info->blue.length
> +			= info->bits_per_pixel;
> +		break;
> +	case 16:
> +		if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
> +			/* RGB:565 mode */
> +			info->red.offset = 11;
> +			info->blue.offset = 0;
> +		} else {
> +			/* BGR:565 mode */
> +			info->red.offset = 0;
> +			info->blue.offset = 11;
> +		}
> +		info->green.offset = 5;
> +		info->green.length = 6;
> +		info->red.length = info->blue.length = 5;
> +		break;
> +	case 32:
> +		info->transp.offset = 24;
> +		info->transp.length = 8;
> +		/* fall through */
> +	case 24:
> +		if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
> +			/* RGB:888 mode */
> +			info->red.offset = 16;
> +			info->blue.offset = 0;
> +		} else {
> +			/* BGR:888 mode */
> +			info->red.offset = 0;
> +			info->blue.offset = 16;
> +		}
> +		info->green.offset = 8;
> +		info->red.length = info->green.length = info->blue.length = 8;
> +		break;
> +	default:
> +		dev_err(dev, "color depth %d not supported\n",
> +					info->bits_per_pixel);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
> +{
> +	struct fb_info *info = &sinfo->info;
> +	struct fb_videomode *mode = info->mode;
> +	unsigned int smem_len;
> +
> +	free(info->screen_base);
> +
> +	smem_len = (mode->xres * mode->yres
> +		    * ((info->bits_per_pixel + 7) / 8));
> +	smem_len = max(smem_len, sinfo->smem_len);
> +
> +	info->screen_base = dma_alloc_coherent(smem_len);
> +
> +	if (!info->screen_base)
> +		return -ENOMEM;
> +
> +	memset(info->screen_base, 0, smem_len);
> +
> +	return 0;
> +}
> +
> +/**
> + * Prepare the video hardware for a specified video mode
> + * @param fb_info Framebuffer information
> + * @param mode The video mode description to initialize
> + * @return 0 on success
> + */
> +static int atmel_lcdc_activate_var(struct fb_info *info)
> +{
> +	struct atmel_lcdfb_info *sinfo = info->priv;
> +	unsigned long value;
> +	int ret;
> +
> +	ret = atmel_lcdfb_alloc_video_memory(sinfo);
> +	if (ret)
> +		return ret;
> +
> +	atmel_lcdfb_set_par(info);
> +
> +	/* Set contrast */
> +	value = ATMEL_LCDC_PS_DIV8 |
> +		ATMEL_LCDC_POL_POSITIVE |
> +		ATMEL_LCDC_ENA_PWMENABLE;
> +	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
> +	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
> +
> +	return atmel_lcdfb_check_var(info);
> +}
> +
> +/*
> + * There is only one video hardware instance available.
> + * It makes no sense to dynamically allocate this data
> + */
> +static struct fb_ops atmel_lcdc_ops = {
> +	.fb_activate_var = atmel_lcdc_activate_var,
> +	.fb_enable = atmel_lcdc_enable_controller,
> +	.fb_disable = atmel_lcdc_disable_controller,
> +};
> +
> +static int atmel_lcdc_probe(struct device_d *hw_dev)
> +{
> +	struct atmel_lcdfb_info *sinfo = hw_dev->platform_data;
> +	int ret = 0;
> +	struct fb_info *info;
> +
> +	if (!sinfo)
> +		return -ENODEV;
> +
> +	sinfo->mmio = dev_request_mem_region(hw_dev, 0);
> +
> +	/* just init */
> +	info = &sinfo->info;

No. Separate your platform data from the driver private data.

> +	info->priv = sinfo;
> +	info->fbops = &atmel_lcdc_ops,	

Trailing whitespace

> +	info->mode = &info->mode_list[0];
> +	info->xres = info->mode->xres;
> +	info->yres = info->mode->yres;
> +	info->bits_per_pixel = sinfo->default_bpp;
> +
> +	/* Enable LCDC Clocks */
> +	sinfo->bus_clk = clk_get(hw_dev, "hck1");
> +	if (IS_ERR(sinfo->bus_clk)) {
> +		ret = PTR_ERR(sinfo->bus_clk);
> +		goto err;
> +	}
> +	sinfo->lcdc_clk = clk_get(hw_dev, "lcdc_clk");
> +	if (IS_ERR(sinfo->lcdc_clk)) {
> +		ret = PTR_ERR(sinfo->lcdc_clk);
> +		goto put_bus_clk;
> +	}
> +
> +	atmel_lcdfb_start_clock(sinfo);

This should be in .fb_enable.

> +
> +	ret = register_framebuffer(info);
> +	if (ret != 0) {
> +		dev_err(hw_dev, "Failed to register framebuffer\n");
> +		goto stop_clk;
> +	}
> +
> +	return ret;
> +
> +stop_clk:
> +	atmel_lcdfb_stop_clock(sinfo);
> +	clk_put(sinfo->lcdc_clk);
> +put_bus_clk:
> +	clk_put(sinfo->bus_clk);
> +err:
> +	return ret;
> +}
> +
> +static struct driver_d atmel_lcdc_driver = {
> +	.name	= "atmel_lcdfb",
> +	.probe	= atmel_lcdc_probe,
> +};
> +
> +static int atmel_lcdc_init(void)
> +{
> +	return register_driver(&atmel_lcdc_driver);
> +}
> +device_initcall(atmel_lcdc_init);
> -- 
> 1.7.10.4
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/5] video: add atmel lcdc frambuffer support
  2012-09-22 10:34   ` [PATCH 1/5] video: add atmel lcdc frambuffer support Sascha Hauer
@ 2012-09-22 16:11     ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-22 17:44     ` Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 0 replies; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-22 16:11 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, Nicolas Ferre

On 12:34 Sat 22 Sep     , Sascha Hauer wrote:
> On Fri, Sep 21, 2012 at 02:55:29PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > This IP is present on the at91sam9 until the sam9g45, on the sam9x5 we use a
> > new IP.
> > 
> > This driver is based on the linux one.
> > 
> > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> > Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> > ---
> >  arch/arm/mach-at91/include/mach/atmel_lcdc.h |  209 +++++++++++
> >  arch/arm/mach-at91/include/mach/board.h      |    4 +
> >  drivers/video/Kconfig                        |    4 +
> >  drivers/video/Makefile                       |    1 +
> >  drivers/video/atmel_lcdfb.c                  |  477 ++++++++++++++++++++++++++
> >  5 files changed, 695 insertions(+)
> >  create mode 100644 arch/arm/mach-at91/include/mach/atmel_lcdc.h
> >  create mode 100644 drivers/video/atmel_lcdfb.c
> > 
> > diff --git a/arch/arm/mach-at91/include/mach/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
> 
> The register definitions should be besides the driver, not in mach.
can not  as we need the register for the board setting I can do as in linux we
put the header in include/video

Best Regards,
J.
> 

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/5] video: add atmel lcdc frambuffer support
  2012-09-22 10:34   ` [PATCH 1/5] video: add atmel lcdc frambuffer support Sascha Hauer
  2012-09-22 16:11     ` Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-22 17:44     ` Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 0 replies; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-22 17:44 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, Nicolas Ferre

On 12:34 Sat 22 Sep     , Sascha Hauer wrote:
> On Fri, Sep 21, 2012 at 02:55:29PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > This IP is present on the at91sam9 until the sam9g45, on the sam9x5 we use a
> > new IP.
> > 
> > This driver is based on the linux one.
> > 
> > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> > Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> > ---
> >  arch/arm/mach-at91/include/mach/atmel_lcdc.h |  209 +++++++++++
> >  arch/arm/mach-at91/include/mach/board.h      |    4 +
> >  drivers/video/Kconfig                        |    4 +
> >  drivers/video/Makefile                       |    1 +
> >  drivers/video/atmel_lcdfb.c                  |  477 ++++++++++++++++++++++++++
> >  5 files changed, 695 insertions(+)
> >  create mode 100644 arch/arm/mach-at91/include/mach/atmel_lcdc.h
> >  create mode 100644 drivers/video/atmel_lcdfb.c
> > 
> > diff --git a/arch/arm/mach-at91/include/mach/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
> 
> The register definitions should be besides the driver, not in mach.
> 
> > diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> > new file mode 100644
> > index 0000000..8659836
> > --- /dev/null
> > +++ b/drivers/video/atmel_lcdfb.c
> > @@ -0,0 +1,477 @@
> > +/*
> > + * Driver for AT91/AT32 LCD Controller
> > + *
> > + * Copyright (C) 2007 Atmel Corporation
> > + *
> > + * 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.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> > + * MA 02111-1307 USA
> > + */
> > +
> > +#include <common.h>
> > +#include <io.h>
> > +#include <init.h>
> > +#include <linux/clk.h>
> > +#include <fb.h>
> > +#include <mach/atmel_lcdc.h>
> > +#include <mach/hardware.h>
> > +#include <mach/io.h>
> > +#include <mach/cpu.h>
> > +#include <errno.h>
> > +#include <linux/err.h>
> > +#include <malloc.h>
> > +#include <asm/mmu.h>
> > +
> > +#define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
> > +#define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
> > +
> > +/* configurable parameters */
> > +#define ATMEL_LCDC_CVAL_DEFAULT		0xc8
> > +#define ATMEL_LCDC_DMA_BURST_LEN	8	/* words */
> > +#define ATMEL_LCDC_FIFO_SIZE		512	/* words */
> > +
> > +static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
> > +{
> > +	clk_enable(sinfo->bus_clk);
> > +	clk_enable(sinfo->lcdc_clk);
> > +}
> > +
> > +static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
> > +{
> > +	clk_disable(sinfo->bus_clk);
> > +	clk_disable(sinfo->lcdc_clk);
> > +}
> > +
> > +static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
> > +{
> > +	unsigned long value;
> > +
> > +	if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
> > +		|| cpu_is_at32ap7000()))
> > +		return xres;
> > +
> > +	value = xres;
> > +	if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
> > +		/* STN display */
> > +		if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR)
> > +			value *= 3;
> > +
> > +		if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
> > +		   || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
> > +		      && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
> > +			value = DIV_ROUND_UP(value, 4);
> > +		else
> > +			value = DIV_ROUND_UP(value, 8);
> > +	}
> > +
> > +	return value;
> > +}
> > +
> > +static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
> > +{
> > +	/* Turn off the LCD controller and the DMA controller */
> > +	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
> > +			sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
> > +
> > +	/* Wait for the LCDC core to become idle */
> > +	while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
> > +		mdelay(10);
> > +
> > +	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
> > +}
> > +
> > +static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
> > +{
> > +	atmel_lcdfb_stop_nowait(sinfo);
> > +
> > +	/* Wait for DMA engine to become idle... */
> > +	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
> > +		mdelay(10);
> > +}
> > +
> > +static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
> > +{
> > +	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
> > +	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
> > +		(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
> > +		| ATMEL_LCDC_PWR);
> > +}
> > +
> > +/**
> > + * @param fb_info Framebuffer information
> > + */
> > +static void atmel_lcdc_enable_controller(struct fb_info *fb_info)
> > +{
> > +	struct atmel_lcdfb_info *sinfo = fb_info->priv;
> > +
> > +	if (sinfo->atmel_lcdfb_power_control)
> > +		sinfo->atmel_lcdfb_power_control(1);
> > +}
> > +
> > +/**
> > + * @param fb_info Framebuffer information
> > + */
> > +static void atmel_lcdc_disable_controller(struct fb_info *fb_info)
> > +{
> > +	struct atmel_lcdfb_info *sinfo = fb_info->priv;
> > +
> > +	if (sinfo->atmel_lcdfb_power_control)
> > +		sinfo->atmel_lcdfb_power_control(0);
> > +}
> > +
> > +static void atmel_lcdfb_update_dma(struct fb_info *info)
> > +{
> > +	struct atmel_lcdfb_info *sinfo = info->priv;
> > +	unsigned long dma_addr;
> > +
> > +	dma_addr = (unsigned long)info->screen_base;
> > +
> > +	dma_addr &= ~3UL;
> > +
> > +	/* Set framebuffer DMA base address and pixel offset */
> > +	lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
> > +}
> > +
> > +static void atmel_lcdfb_set_par(struct fb_info *info)
> > +{
> > +	struct atmel_lcdfb_info *sinfo = info->priv;
> > +	struct fb_videomode *mode = info->mode;
> > +	unsigned long clk_value_khz;
> > +	unsigned long value;
> > +	unsigned long pix_factor = 2;
> > +	unsigned long hozval_linesz;
> > +
> > +	atmel_lcdfb_stop(sinfo);
> > +
> > +	/* Re-initialize the DMA engine... */
> > +	dev_dbg(&info->dev, "  * update DMA engine\n");
> > +	atmel_lcdfb_update_dma(info);
> > +
> > +	/* ...set frame size and burst length = 8 words (?) */
> > +	value = (mode->yres * mode->xres * info->bits_per_pixel) / 32;
> > +	value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
> > +	lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
> > +
> > +	/* Now, the LCDC core... */
> > +
> > +	/* Set pixel clock */
> > +	if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
> > +		pix_factor = 1;
> > +
> > +	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
> > +
> > +	value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(mode->pixclock));
> > +
> > +	if (value < pix_factor) {
> > +		dev_notice(&info->dev, "Bypassing pixel clock divider\n");
> > +		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
> > +	} else {
> > +		value = (value / pix_factor) - 1;
> > +		dev_dbg(&info->dev, "  * programming CLKVAL = 0x%08lx\n",
> > +				value);
> > +		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
> > +				value << ATMEL_LCDC_CLKVAL_OFFSET);
> > +		mode->pixclock =
> > +			KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
> > +		dev_dbg(&info->dev, "  updated pixclk:     %lu KHz\n",
> > +					PICOS2KHZ(mode->pixclock));
> > +	}
> > +
> > +	/* Initialize control register 2 */
> > +	value = sinfo->default_lcdcon2;
> > +
> > +	if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
> > +		value |= ATMEL_LCDC_INVLINE_INVERTED;
> > +	if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
> > +		value |= ATMEL_LCDC_INVFRAME_INVERTED;
> > +
> > +	switch (info->bits_per_pixel) {
> > +		case 1:	value |= ATMEL_LCDC_PIXELSIZE_1; break;
> > +		case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
> > +		case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
> > +		case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
> > +		case 15: /* fall through */
> > +		case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
> > +		case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
> > +		case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
> > +		default: BUG(); break;
> > +	}
> > +	dev_dbg(&info->dev, "  * LCDCON2 = %08lx\n", value);
> > +	lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
> > +
> > +	/* Vertical timing */
> > +	value = (mode->vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
> > +	value |= mode->upper_margin << ATMEL_LCDC_VBP_OFFSET;
> > +	value |= mode->lower_margin;
> > +	dev_dbg(&info->dev, "  * LCDTIM1 = %08lx\n", value);
> > +	lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
> > +
> > +	/* Horizontal timing */
> > +	value = (mode->right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
> > +	value |= (mode->hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
> > +	value |= (mode->left_margin - 1);
> > +	dev_dbg(&info->dev, "  * LCDTIM2 = %08lx\n", value);
> > +	lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
> > +
> > +	/* Horizontal value (aka line size) */
> > +	hozval_linesz = compute_hozval(mode->xres,
> > +					lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
> > +
> > +	/* Display size */
> > +	value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
> > +	value |= mode->yres - 1;
> > +	dev_dbg(&info->dev, "  * LCDFRMCFG = %08lx\n", value);
> > +	lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
> > +
> > +	/* FIFO Threshold: Use formula from data sheet */
> > +	value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
> > +	lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
> > +
> > +	/* Toggle LCD_MODE every frame */
> > +	lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
> > +
> > +	/* Disable all interrupts */
> > +	lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
> > +
> > +	/* Enable FIFO & DMA errors */
> > +	lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
> > +
> > +	/* ...wait for DMA engine to become idle... */
> > +	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
> > +		mdelay(10);
> > +
> > +	atmel_lcdfb_start(sinfo);
> > +
> > +	dev_dbg(&info->dev, "  * DONE\n");
> > +}
> > +
> > +static int atmel_lcdfb_check_var(struct fb_info *info)
> > +{
> > +	struct device_d *dev = &info->dev;
> > +	struct atmel_lcdfb_info *sinfo = info->priv;
> > +	struct fb_videomode *mode = info->mode;
> > +	unsigned long clk_value_khz;
> > +
> > +	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
> > +
> > +	dev_dbg(dev, "%s:\n", __func__);
> > +
> > +	if (!(mode->pixclock && info->bits_per_pixel)) {
> > +		dev_err(dev, "needed value not specified\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	dev_dbg(dev, "  resolution: %ux%u\n", mode->xres, mode->yres);
> > +	dev_dbg(dev, "  pixclk:     %lu KHz\n", PICOS2KHZ(mode->pixclock));
> > +	dev_dbg(dev, "  bpp:        %u\n", info->bits_per_pixel);
> > +	dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
> > +
> > +	if (PICOS2KHZ(mode->pixclock) > clk_value_khz) {
> > +		dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(mode->pixclock));
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* Saturate vertical and horizontal timings at maximum values */
> > +	mode->vsync_len = min_t(u32, mode->vsync_len,
> > +			(ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
> > +	mode->upper_margin = min_t(u32, mode->upper_margin,
> > +			ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
> > +	mode->lower_margin = min_t(u32, mode->lower_margin,
> > +			ATMEL_LCDC_VFP);
> > +	mode->right_margin = min_t(u32, mode->right_margin,
> > +			(ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
> > +	mode->hsync_len = min_t(u32, mode->hsync_len,
> > +			(ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
> > +	mode->left_margin = min_t(u32, mode->left_margin,
> > +			ATMEL_LCDC_HBP + 1);
> > +
> > +	/* Some parameters can't be zero */
> > +	mode->vsync_len = max_t(u32, mode->vsync_len, 1);
> > +	mode->right_margin = max_t(u32, mode->right_margin, 1);
> > +	mode->hsync_len = max_t(u32, mode->hsync_len, 1);
> > +	mode->left_margin = max_t(u32, mode->left_margin, 1);
> > +
> > +	switch (info->bits_per_pixel) {
> > +	case 1:
> > +	case 2:
> > +	case 4:
> > +	case 8:
> > +		info->red.offset = info->green.offset = info->blue.offset = 0;
> > +		info->red.length = info->green.length = info->blue.length
> > +			= info->bits_per_pixel;
> > +		break;
> > +	case 16:
> > +		if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
> > +			/* RGB:565 mode */
> > +			info->red.offset = 11;
> > +			info->blue.offset = 0;
> > +		} else {
> > +			/* BGR:565 mode */
> > +			info->red.offset = 0;
> > +			info->blue.offset = 11;
> > +		}
> > +		info->green.offset = 5;
> > +		info->green.length = 6;
> > +		info->red.length = info->blue.length = 5;
> > +		break;
> > +	case 32:
> > +		info->transp.offset = 24;
> > +		info->transp.length = 8;
> > +		/* fall through */
> > +	case 24:
> > +		if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
> > +			/* RGB:888 mode */
> > +			info->red.offset = 16;
> > +			info->blue.offset = 0;
> > +		} else {
> > +			/* BGR:888 mode */
> > +			info->red.offset = 0;
> > +			info->blue.offset = 16;
> > +		}
> > +		info->green.offset = 8;
> > +		info->red.length = info->green.length = info->blue.length = 8;
> > +		break;
> > +	default:
> > +		dev_err(dev, "color depth %d not supported\n",
> > +					info->bits_per_pixel);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
> > +{
> > +	struct fb_info *info = &sinfo->info;
> > +	struct fb_videomode *mode = info->mode;
> > +	unsigned int smem_len;
> > +
> > +	free(info->screen_base);
> > +
> > +	smem_len = (mode->xres * mode->yres
> > +		    * ((info->bits_per_pixel + 7) / 8));
> > +	smem_len = max(smem_len, sinfo->smem_len);
> > +
> > +	info->screen_base = dma_alloc_coherent(smem_len);
> > +
> > +	if (!info->screen_base)
> > +		return -ENOMEM;
> > +
> > +	memset(info->screen_base, 0, smem_len);
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * Prepare the video hardware for a specified video mode
> > + * @param fb_info Framebuffer information
> > + * @param mode The video mode description to initialize
> > + * @return 0 on success
> > + */
> > +static int atmel_lcdc_activate_var(struct fb_info *info)
> > +{
> > +	struct atmel_lcdfb_info *sinfo = info->priv;
> > +	unsigned long value;
> > +	int ret;
> > +
> > +	ret = atmel_lcdfb_alloc_video_memory(sinfo);
> > +	if (ret)
> > +		return ret;
> > +
> > +	atmel_lcdfb_set_par(info);
> > +
> > +	/* Set contrast */
> > +	value = ATMEL_LCDC_PS_DIV8 |
> > +		ATMEL_LCDC_POL_POSITIVE |
> > +		ATMEL_LCDC_ENA_PWMENABLE;
> > +	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
> > +	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
> > +
> > +	return atmel_lcdfb_check_var(info);
> > +}
> > +
> > +/*
> > + * There is only one video hardware instance available.
> > + * It makes no sense to dynamically allocate this data
> > + */
> > +static struct fb_ops atmel_lcdc_ops = {
> > +	.fb_activate_var = atmel_lcdc_activate_var,
> > +	.fb_enable = atmel_lcdc_enable_controller,
> > +	.fb_disable = atmel_lcdc_disable_controller,
> > +};
> > +
> > +static int atmel_lcdc_probe(struct device_d *hw_dev)
> > +{
> > +	struct atmel_lcdfb_info *sinfo = hw_dev->platform_data;
> > +	int ret = 0;
> > +	struct fb_info *info;
> > +
> > +	if (!sinfo)
> > +		return -ENODEV;
> > +
> > +	sinfo->mmio = dev_request_mem_region(hw_dev, 0);
> > +
> > +	/* just init */
> > +	info = &sinfo->info;
> 
> No. Separate your platform data from the driver private data.
> 
> > +	info->priv = sinfo;
> > +	info->fbops = &atmel_lcdc_ops,	
> 
> Trailing whitespace
> 
> > +	info->mode = &info->mode_list[0];
> > +	info->xres = info->mode->xres;
> > +	info->yres = info->mode->yres;
> > +	info->bits_per_pixel = sinfo->default_bpp;
> > +
> > +	/* Enable LCDC Clocks */
> > +	sinfo->bus_clk = clk_get(hw_dev, "hck1");
> > +	if (IS_ERR(sinfo->bus_clk)) {
> > +		ret = PTR_ERR(sinfo->bus_clk);
> > +		goto err;
> > +	}
> > +	sinfo->lcdc_clk = clk_get(hw_dev, "lcdc_clk");
> > +	if (IS_ERR(sinfo->lcdc_clk)) {
> > +		ret = PTR_ERR(sinfo->lcdc_clk);
> > +		goto put_bus_clk;
> > +	}
> > +
> > +	atmel_lcdfb_start_clock(sinfo);
> 
> This should be in .fb_enable.
need the clock always enable

Best Regards,
J.

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-09-22 17:46 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-21 12:51 [PATCH 0/5] at91 framebuffer support Jean-Christophe PLAGNIOL-VILLARD
2012-09-21 12:55 ` [PATCH 1/5] video: add atmel lcdc frambuffer support Jean-Christophe PLAGNIOL-VILLARD
2012-09-21 12:55   ` [PATCH 2/5] at91sam9263: " Jean-Christophe PLAGNIOL-VILLARD
2012-09-21 12:55   ` [PATCH 3/5] at91sam9261: " Jean-Christophe PLAGNIOL-VILLARD
2012-09-21 12:55   ` [PATCH 4/5] at91sam9g45: " Jean-Christophe PLAGNIOL-VILLARD
2012-09-21 12:55   ` [PATCH 5/5] at91sam9m10g45ek: add lcdc support Jean-Christophe PLAGNIOL-VILLARD
2012-09-22 10:34   ` [PATCH 1/5] video: add atmel lcdc frambuffer support Sascha Hauer
2012-09-22 16:11     ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-22 17:44     ` Jean-Christophe PLAGNIOL-VILLARD

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox