Re: [RFC/PATCH 4/6] FBDEV: JZ4740: Add Smart LCD controller support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> On 03/01/2011 01:06 PM, Maurus Cuelenaere wrote:
>> This patch adds SLCD support to the Ingenic Jz4740 framebuffer driver.
>> Besides adding the new LCD types to the platform data, this adds chip select
>> and register select active low support (SLCD only). Also, this exports some
>> functions related to starting and stopping the SLCD image transfer and sending
>> commands.
>>
>> A lot of this code was based on work by Maarten ter Huurne:
>> https://github.com/mthuurne/opendingux-kernel/commit/3dba5b5e7a868b1067acae8d1b5a19121b77bc6a
>>
>> Signed-off-by: Maurus Cuelenaere <mcuelenaere@xxxxxxxxx>
> Looks mostly good :)
>
>> ---
>>  arch/mips/include/asm/mach-jz4740/jz4740_fb.h |   33 ++
>>  drivers/video/jz4740_fb.c                     |  435 ++++++++++++++++++++++---
>>  2 files changed, 429 insertions(+), 39 deletions(-)
>>
>> diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_fb.h b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h
>> index 6a50e6f..eaaac43 100644
>> --- a/arch/mips/include/asm/mach-jz4740/jz4740_fb.h
>> +++ b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h
>> @@ -30,6 +30,13 @@ enum jz4740_fb_lcd_type {
>>  	JZ_LCD_TYPE_DUAL_COLOR_STN = 10,
>>  	JZ_LCD_TYPE_DUAL_MONOCHROME_STN = 11,
>>  	JZ_LCD_TYPE_8BIT_SERIAL = 12,
>> +
>> +	JZ_SLCD_TYPE_PARALLEL_8_BIT = 1 | (1 << 5),
>> +	JZ_SLCD_TYPE_PARALLEL_16_BIT = 0 | (1 << 5),
>> +	JZ_SLCD_TYPE_PARALLEL_18_BIT = 2 | (1 << 5),
>> +	JZ_SLCD_TYPE_SERIAL_8_BIT = 1 | (3 << 5),
>> +	JZ_SLCD_TYPE_SERIAL_16_BIT = 0 | (3 << 5),
>> +	JZ_SLCD_TYPE_SERIAL_18_BIT = 2 | (3 << 5),
> I would prefer
> JZ_LCD_TYPE_SLCD_...

Ok.

>>  };
> Maybe add
> #define JZ_LCD_TYPE_SLCD (1 << 5)
> #define JZ_LCD_TYPE_SLCD_SERIAL (JZ_LCD_TYPE_SLCD | (1 << 6))

Ok.

>
>>  
>>  #define JZ4740_FB_SPECIAL_TFT_CONFIG(start, stop) (((start) << 16) | (stop))
>> @@ -62,6 +69,32 @@ struct jz4740_fb_platform_data {
>>  
>>  	unsigned pixclk_falling_edge:1;
>>  	unsigned date_enable_active_low:1;
>> +	unsigned chip_select_active_low:1;
>> +	unsigned register_select_active_low:1;
>>  };
>>  
>> +struct platform_device;
>> +
>> +/*
>> + * JzFB SLCD related functions
>> + *
>> + * jz4740_fb_slcd_disable_transfer: disables the current image transfer going
>> + *       on between memory and the LCD controller
>> + * jz4740_fb_slcd_enable_transfer: the reverse operation of the above
>> + * jz4740_fb_slcd_send_cmd: sends a command without any data to the LCD
>> + *       controller
>> + * jz4740_fb_slcd_send_cmd_data: sends a command with a data argument to the LCD
>> + *       controller
>> + *
>> + * These functions can sleep and thus should not be called from an atomic
>> + * context. Also, make sure you disable the SLCD image transfer *before* sending
>> + * any commands and do not forget to re-enable it.
>> + */
>> +extern void jz4740_fb_slcd_disable_transfer(struct platform_device *pdev);
>> +extern void jz4740_fb_slcd_enable_transfer(struct platform_device *pdev);
>> +extern void jz4740_fb_slcd_send_cmd_data(struct platform_device *pdev,
>> +					 unsigned int cmd, unsigned int data);
>> +extern void jz4740_fb_slcd_send_cmd(struct platform_device *pdev,
>> +				    unsigned int cmd);
>> +
>>  #endif
>> diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c
>> index 2f3ea57..4064812 100644
>> --- a/drivers/video/jz4740_fb.c
>> +++ b/drivers/video/jz4740_fb.c
>> @@ -26,6 +26,7 @@
>>  
>>  #include <linux/dma-mapping.h>
>>  
>> +#include <asm/mach-jz4740/dma.h>
>>  #include <asm/mach-jz4740/jz4740_fb.h>
>>  #include <asm/mach-jz4740/gpio.h>
>>  
>> @@ -107,6 +108,40 @@
>>  
>>  #define JZ_LCD_STATE_DISABLED BIT(0)
>>  
>> +#define JZ_REG_SLCD_CFG		0xA0
>> +#define JZ_REG_SLCD_CTRL	0xA4
>> +#define JZ_REG_SLCD_STATE	0xA8
>> +#define JZ_REG_SLCD_DATA	0xAC
>> +#define JZ_REG_SLCD_FIFO	0xB0
>> +
>> +#define JZ_SLCD_CFG_BURST_8_WORD	BIT(14)
>> +#define JZ_SLCD_CFG_DWIDTH_MASK		(7 << 10)
>> +#define JZ_SLCD_CFG_DWIDTH_18		(0 << 10)
>> +#define JZ_SLCD_CFG_DWIDTH_16		(1 << 10)
>> +#define JZ_SLCD_CFG_DWIDTH_8_x3		(2 << 10)
>> +#define JZ_SLCD_CFG_DWIDTH_8_x2		(3 << 10)
>> +#define JZ_SLCD_CFG_DWIDTH_8_x1		(4 << 10)
>> +#define JZ_SLCD_CFG_DWIDTH_9_x2		(7 << 10)
>> +#define JZ_SLCD_CFG_CWIDTH_MASK		(3 << 8)
>> +#define JZ_SLCD_CFG_CWIDTH(n)		((n) << 8)
>> +#define JZ_SLCD_CFG_CWIDTH_16BIT	(0 << 8)
>> +#define JZ_SLCD_CFG_CWIDTH_8BIT		(1 << 8)
>> +#define JZ_SLCD_CFG_CWIDTH_18BIT	(2 << 8)
>> +#define JZ_SLCD_CFG_CS_ACTIVE_HIGH	BIT(4)
>> +#define JZ_SLCD_CFG_RS_CMD_HIGH		BIT(3)
>> +#define JZ_SLCD_CFG_CLK_ACTIVE_RISING	BIT(1)
>> +#define JZ_SLCD_CFG_TYPE_SERIAL		BIT(0)
>> +
>> +#define JZ_SLCD_CTRL_DMA_EN		(1 << 0)
>> +
>> +#define JZ_SLCD_STATE_BUSY		(1 << 0)
>> +
>> +#define JZ_SLCD_DATA_RS_DATA		(0 << 31)
>> +#define JZ_SLCD_DATA_RS_COMMAND		(1 << 31)
>> +
>> +#define JZ_SLCD_FIFO_RS_DATA		(0 << 31)
>> +#define JZ_SLCD_FIFO_RS_COMMAND		(1 << 31)
>> +
>>  struct jzfb_framedesc {
>>  	uint32_t next;
>>  	uint32_t addr;
>> @@ -118,6 +153,7 @@ struct jzfb {
>>  	struct fb_info *fb;
>>  	struct platform_device *pdev;
>>  	void __iomem *base;
>> +	phys_t phys_base;
>>  	struct resource *mem;
>>  	struct jz4740_fb_platform_data *pdata;
>>  
>> @@ -126,6 +162,7 @@ struct jzfb {
>>  	dma_addr_t vidmem_phys;
>>  	struct jzfb_framedesc *framedesc;
>>  	dma_addr_t framedesc_phys;
>> +	struct jz4740_dma_chan *slcd_dma;
>>  
>>  	struct clk *ldclk;
>>  	struct clk *lpclk;
>> @@ -136,6 +173,9 @@ struct jzfb {
>>  	uint32_t pseudo_palette[16];
>>  };
>>  
>> +#define JZFB_IS_SLCD(jzfb) ((jzfb)->pdata->lcd_type & (1 << 5))
>> +#define JZFB_IS_SLCD_SERIAL_TYPE(jzfb) ((jzfb)->pdata->lcd_type & (2 << 5))
> These two should be static inline bool.

Ok.

>> +static void send_panel_command(struct jzfb *jzfb, u32 cmd)
> You've been using u{16,32} throughout the whole patch, since the existing code
> uses uint_{16,32}t you should stick to them.

Ok, probably a restant from the original opendingux patch.

>> +{
>> +	u16 slcd_cfg = readw(jzfb->base + JZ_REG_SLCD_CFG);
>> +
>> +	jzfb_slcd_wait(jzfb);
>> +
>> +	switch (slcd_cfg & JZ_SLCD_CFG_CWIDTH_MASK) {
>> +	case JZ_SLCD_CFG_CWIDTH_8BIT:
>> +		writel(JZ_SLCD_DATA_RS_COMMAND | ((cmd & 0xff00) >> 8),
>> +		       jzfb->base + JZ_REG_SLCD_DATA);
>> +		jzfb_slcd_wait(jzfb);
>> +		writel(JZ_SLCD_DATA_RS_COMMAND | (cmd & 0xff),
>> +		       jzfb->base + JZ_REG_SLCD_DATA);
>> +		break;
>> +
>> +	case JZ_SLCD_CFG_CWIDTH_16BIT:
>> +		writel(JZ_SLCD_DATA_RS_COMMAND | (cmd & 0xffff),
>> +		       jzfb->base + JZ_REG_SLCD_DATA);
>> +		break;
>> +
>> +	case JZ_SLCD_CFG_CWIDTH_18BIT:
>> +		writel(JZ_SLCD_DATA_RS_COMMAND | ((cmd & 0xff00) << 2) |
>> +		       ((cmd & 0xff) << 1), jzfb->base + JZ_REG_SLCD_DATA);
>> +		break;
>> +	}
>> +}
>> +
>> +static void send_panel_data(struct jzfb *jzfb, u32 data)
>> +{
>> +	u16 slcd_cfg = readw(jzfb->base + JZ_REG_SLCD_CFG);
>> +
>> +	switch (slcd_cfg & JZ_SLCD_CFG_DWIDTH_MASK) {
>> +	case JZ_SLCD_CFG_DWIDTH_18:
>> +	case JZ_SLCD_CFG_DWIDTH_9_x2:
>> +		data = ((data & 0xff) << 1) | ((data & 0xff00) << 2);
>> +		data = ((data << 6) & 0xfc0000) | ((data << 4) & 0xfc00) |
>> +		       ((data << 2) & 0x0000fc);
>> +		break;
>> +
>> +	case JZ_SLCD_CFG_DWIDTH_16:
>> +	default:
>> +		data &= 0xffff;
>> +		break;
>> +	}
>> +
>> +	jzfb_slcd_wait(jzfb);
>> +	writel(JZ_SLCD_DATA_RS_DATA | data, jzfb->base + JZ_REG_SLCD_DATA);
>> +}
>> +
>> +void jz4740_fb_slcd_disable_transfer(struct platform_device *pdev)
>> +{
>> +	struct jzfb *jzfb = platform_get_drvdata(pdev);
>> +
>> +	mutex_lock(&jzfb->lock);
>> +
>> +	if (jzfb->is_enabled) {
>> +		jz4740_dma_disable(jzfb->slcd_dma);
>> +		jzfb_slcd_wait(jzfb);
>> +	}
>> +
>> +	mutex_unlock(&jzfb->lock);
>> +}
>> +EXPORT_SYMBOL_GPL(jz4740_fb_slcd_disable_transfer);
>> +
>> +void jz4740_fb_slcd_enable_transfer(struct platform_device *pdev)
>> +{
>> +	struct jzfb *jzfb = platform_get_drvdata(pdev);
>> +
>> +	mutex_lock(&jzfb->lock);
>> +
>> +	if (jzfb->is_enabled)
>> +		jzfb_slcd_start_dma(jzfb);
>> +
>> +	mutex_unlock(&jzfb->lock);
>> +}
>> +EXPORT_SYMBOL_GPL(jz4740_fb_slcd_enable_transfer);
>> +
>> +void jz4740_fb_slcd_send_cmd_data(struct platform_device *pdev,
>> +				  unsigned int cmd, unsigned int data)
>> +{
>> +	struct jzfb *jzfb = platform_get_drvdata(pdev);
>> +
>> +	mutex_lock(&jzfb->lock);
>> +
>> +	if (!jzfb->is_enabled)
>> +		clk_enable(jzfb->ldclk);
>> +
>> +	send_panel_command(jzfb, cmd);
>> +	send_panel_data(jzfb, data);
>> +
>> +	if (!jzfb->is_enabled) {
>> +		jzfb_slcd_wait(jzfb);
>> +		clk_disable(jzfb->ldclk);
>> +	}
>> +
>> +	mutex_unlock(&jzfb->lock);
>> +}
>> +EXPORT_SYMBOL_GPL(jz4740_fb_slcd_send_cmd_data);
>> +
>> +void jz4740_fb_slcd_send_cmd(struct platform_device *pdev, unsigned int cmd)
>> +{
>> +	struct jzfb *jzfb = platform_get_drvdata(pdev);
>> +
>> +	mutex_lock(&jzfb->lock);
>> +
>> +	if (!jzfb->is_enabled)
>> +		clk_enable(jzfb->ldclk);
>> +
>> +	send_panel_command(jzfb, cmd);
>> +
>> +	if (!jzfb->is_enabled) {
>> +		jzfb_slcd_wait(jzfb);
>> +		clk_disable(jzfb->ldclk);
>> +	}
>> +
>> +	mutex_unlock(&jzfb->lock);
>> +}
>> +EXPORT_SYMBOL_GPL(jz4740_fb_slcd_send_cmd);
> jz4740_fb_slcd_send_cmd_data and jz4740_fb_slcd_send_cmd are almost identical
> it might makes sense to merge them.

Something like
void jz4740_fb_slcd_send_cmd(struct platform_device *pdev, unsigned int cmd,
unsigned int data, bool with_data);
?

You can't use data == 0 as "do not send data" as this could be a valid parameter.

> I don't like the idea of adding a jzfb specific interface for talking to the
> lcd panels, because it will tightly couple the panel driver to the framebuffer
> driver and it won't be possible to reuse for some board using the same panel
> but a different SoC.
>

Me neither, but the only "good" way forward I see is emulating an SPI interface
over this..
Do you think this is acceptable?

-- 
Maurus Cuelenaere

--
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Tourism]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux