linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eric Miao <eric.y.miao@gmail.com>
To: Jaya Kumar <jayakumar.lkml@gmail.com>
Cc: ymiao3@marvell.com, linux-fbdev-devel@lists.sourceforge.net,
	linux-arm-kernel@lists.arm.linux.org.uk
Subject: Re: [RFC 2.6.26-rc3 08/10] am200epd: convert to shared fb and use gpio api
Date: Fri, 13 Jun 2008 10:20:58 +0800	[thread overview]
Message-ID: <4851D98A.5000508@gmail.com> (raw)
In-Reply-To: <1213289961-1562-9-git-send-email-jayakumar.lkml@gmail.com>

Jaya Kumar wrote:
> This patch converts am200epd to use pxafb's fb and to stop performing
> direct access to LCDC registers. It now uses the generic GPIO api.
> 

Mmm..., this patch makes the code much cleaner now, see my comments below.

> Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com>
> ---
>  arch/arm/mach-pxa/am200epd.c |  342 ++++++++++++++++++++++++------------------
>  arch/arm/mach-pxa/devices.c  |    1 +
>  2 files changed, 198 insertions(+), 145 deletions(-)
> 
> diff --git a/arch/arm/mach-pxa/am200epd.c b/arch/arm/mach-pxa/am200epd.c
> index 51e26c1..67bed6c 100644
> --- a/arch/arm/mach-pxa/am200epd.c
> +++ b/arch/arm/mach-pxa/am200epd.c
> @@ -1,5 +1,5 @@
>  /*
> - * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit
> + * am200epd.c -- Platform device for AM200 EPD kit
>   *
>   * Copyright (C) 2008, Jaya Kumar
>   *
> @@ -18,6 +18,8 @@
>   *
>   */
>  
> +#define DEBUG 1
> +
>  #include <linux/module.h>
>  #include <linux/kernel.h>
>  #include <linux/errno.h>
> @@ -27,13 +29,72 @@
>  #include <linux/fb.h>
>  #include <linux/init.h>
>  #include <linux/platform_device.h>
> -#include <linux/list.h>
> -#include <linux/uaccess.h>
>  #include <linux/irq.h>
> +#include <linux/gpio.h>
> +
> +#include <asm/arch/pxafb.h>
>  
>  #include <video/metronomefb.h>
>  
> -#include <asm/arch/pxa-regs.h>
> +#include "generic.h"
> +#include "devices.h"
> +
> +static unsigned int panel_type = 6;
> +static struct platform_device *am200_device;
> +static struct metronome_board am200_board;
> +
> +static struct pxafb_mode_info am200_fb_mode_9inch7 = {
> +	.pixclock	= 40000,
> +	.xres		= 1200,
> +	.yres		= 842,
> +	.bpp		= 16,
> +	.hsync_len	= 2,
> +	.left_margin	= 2,
> +	.right_margin	= 2,
> +	.vsync_len	= 1,
> +	.upper_margin	= 2,
> +	.lower_margin	= 25,
> +	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +};
> +
> +static struct pxafb_mode_info am200_fb_mode_8inch = {
> +	.pixclock	= 40000,
> +	.xres		= 1088,
> +	.yres		= 791,
> +	.bpp		= 16,
> +	.hsync_len	= 28,
> +	.left_margin	= 8,
> +	.right_margin	= 30,
> +	.vsync_len	= 8,
> +	.upper_margin	= 10,
> +	.lower_margin	= 8,
> +	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +};
> +
> +static struct pxafb_mode_info am200_fb_mode_6inch = {
> +	.pixclock	= 40189,
> +	.xres		= 832,
> +	.yres		= 622,
> +	.bpp		= 16,
> +	.hsync_len	= 28,
> +	.left_margin	= 34,
> +	.right_margin	= 34,
> +	.vsync_len	= 25,
> +	.upper_margin	= 0,
> +	.lower_margin	= 2,
> +	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +};
> +
> +static struct pxafb_mach_info am200_fb_info = {
> +	.modes		= &am200_fb_mode_6inch,
> +	.num_modes	= 1,
> +	.lccr0		= LCCR0_Pas | LCCR0_Sngl | LCCR0_Color,
> +	.lccr3		= 0,
> +	.lcd_conn	= LCD_TYPE_COLOR_TFT | LCD_PCLK_EDGE_FALL |
> +			  LCD_AC_BIAS_FREQ(24),

You don't need to specify both lccrX and lcd_conn, the pxafb.c should
be smart enough to guess a correct LCCRx setting based on lcd_conn.

> +	.clkdev		= &pxa_device_fb.dev,
> +	.custom_xfer_div = 2,
> +};
>  
>  /* register offsets for gpio control */
>  #define LED_GPIO_PIN 51
> @@ -42,163 +103,144 @@
>  #define RDY_GPIO_PIN 32
>  #define ERR_GPIO_PIN 17
>  #define PCBPWR_GPIO_PIN 16
> +static int gpios[] = { LED_GPIO_PIN , STDBY_GPIO_PIN , RST_GPIO_PIN,
> +			RDY_GPIO_PIN, ERR_GPIO_PIN, PCBPWR_GPIO_PIN };
> +static char *gpio_names[] = { "LED" , "STDBY" , "RST", "RDY", "ERR", "PCBPWR" };
>  
> -#define AF_SEL_GPIO_N 0x3
> -#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
> -#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
> -#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
> -#define GPDR1_OFFSET(pin) (pin - 32)
> -#define GPCR1_OFFSET(pin) (pin - 32)
> -#define GPSR1_OFFSET(pin) (pin - 32)
> -#define GPCR0_OFFSET(pin) (pin)
> -#define GPSR0_OFFSET(pin) (pin)
> -
> -static void am200_set_gpio_output(int pin, int val)
> +static int am200_init_gpio_regs(struct metronomefb_par *par)
>  {
> -	u8 index;
> +	int i;
> +	int err;
> +
> +	for (i = 0; i < ARRAY_SIZE(gpios); i++) {
> +		err = gpio_request(gpios[i], gpio_names[i]);
> +		if (err) {
> +			dev_err(&am200_device->dev, "failed requesting "
> +				"gpio %s, err=%d\n", gpio_names[i], err);
> +			goto err_req_gpio;
> +		}
> +	}
>  
> -	index = pin >> 4;
> +	gpio_direction_output(LED_GPIO_PIN, 0);
> +	gpio_direction_output(STDBY_GPIO_PIN, 0);
> +	gpio_direction_output(RST_GPIO_PIN, 0);
>  
> -	switch (index) {
> -	case 1:
> -		if (val)
> -			GPSR0 |= (1 << GPSR0_OFFSET(pin));
> -		else
> -			GPCR0 |= (1 << GPCR0_OFFSET(pin));
> -		break;
> -	case 2:
> -		break;
> -	case 3:
> -		if (val)
> -			GPSR1 |= (1 << GPSR1_OFFSET(pin));
> -		else
> -			GPCR1 |= (1 << GPCR1_OFFSET(pin));
> -		break;
> -	default:
> -		printk(KERN_ERR "unimplemented\n");
> -	}
> +	gpio_direction_input(RDY_GPIO_PIN);
> +	gpio_direction_input(ERR_GPIO_PIN);
> +
> +	gpio_direction_output(PCBPWR_GPIO_PIN, 0);
> +
> +	return 0;
> +
> +err_req_gpio:
> +	while (i > 0)
> +		gpio_free(gpios[i--]);
> +
> +	return err;
>  }
>  
> -static void __devinit am200_init_gpio_pin(int pin, int dir)
> +static void am200_cleanup(struct metronomefb_par *par)
>  {
> -	u8 index;
> -	/* dir 0 is output, 1 is input
> -	- do 2 things here:
> -	- set gpio alternate function to standard gpio
> -	- set gpio direction to input or output  */
> -
> -	index = pin >> 4;
> -	switch (index) {
> -	case 1:
> -		GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
> -
> -		if (dir)
> -			GPDR0 &= ~(1 << pin);
> -		else
> -			GPDR0 |= (1 << pin);
> -		break;
> -	case 2:
> -		GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
> +	int i;
>  
> -		if (dir)
> -			GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
> -		else
> -			GPDR1 |= (1 << GPDR1_OFFSET(pin));
> -		break;
> -	case 3:
> -		GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
> +	free_irq(IRQ_GPIO(RDY_GPIO_PIN), par->info);
>  
> -		if (dir)
> -			GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
> -		else
> -			GPDR1 |= (1 << GPDR1_OFFSET(pin));
> -		break;
> -	default:
> -		printk(KERN_ERR "unimplemented\n");
> -	}
> +	for (i = 0; i < ARRAY_SIZE(gpios); i++)
> +		gpio_free(gpios[i]);
>  }
>  
> -static void am200_init_gpio_regs(struct metronomefb_par *par)
> +static struct platform_device *am200_pxa_device_fb;
> +
> +static int am200_pxa_register_device(struct platform_device *dev,
> +					struct pxafb_mach_info *data)
>  {
> -	am200_init_gpio_pin(LED_GPIO_PIN, 0);
> -	am200_set_gpio_output(LED_GPIO_PIN, 0);
> +	int ret;
>  
> -	am200_init_gpio_pin(STDBY_GPIO_PIN, 0);
> -	am200_set_gpio_output(STDBY_GPIO_PIN, 0);
> +	am200_pxa_device_fb = platform_device_alloc("pxa2xx-fb", -1);
> +	if (!am200_pxa_device_fb)
> +		return -ENOMEM;
>  
> -	am200_init_gpio_pin(RST_GPIO_PIN, 0);
> -	am200_set_gpio_output(RST_GPIO_PIN, 0);
> +	platform_device_add_data(am200_pxa_device_fb, data, sizeof(*data));
>  
> -	am200_init_gpio_pin(RDY_GPIO_PIN, 1);
> +	platform_device_add_resources(am200_pxa_device_fb,
> +					pxa_device_fb.resource,
> +					pxa_device_fb.num_resources);
>  
> -	am200_init_gpio_pin(ERR_GPIO_PIN, 1);
> +	am200_pxa_device_fb->dev.dma_mask = pxa_device_fb.dev.dma_mask;
> +	am200_pxa_device_fb->dev.coherent_dma_mask =
> +					pxa_device_fb.dev.coherent_dma_mask;
>  
> -	am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
> -	am200_set_gpio_output(PCBPWR_GPIO_PIN, 0);
> -}
> +	ret = platform_device_add(am200_pxa_device_fb);
>  
> -static void am200_disable_lcd_controller(struct metronomefb_par *par)
> -{
> -	LCSR = 0xffffffff;	/* Clear LCD Status Register */
> -	LCCR0 |= LCCR0_DIS;	/* Disable LCD Controller */
> +	if (ret) {
> +		dev_err(&am200_device->dev, "failed adding pxafb %d\n", ret);
> +		platform_device_put(am200_pxa_device_fb);
> +	}
>  
> -	/* we reset and just wait for things to settle */
> -	msleep(200);
> +	return ret;
>  }

Can set_pxa_fb_info() be used here instead of re-allocating a new
platform_device with almost same setting as pxa_device_fb?

>  
> -static void am200_enable_lcd_controller(struct metronomefb_par *par)
> +static int am200_share_video_mem(char __iomem *video_mem, dma_addr_t dma,
> +					struct module *fbmaster, void *data)
>  {
> -	LCSR = 0xffffffff;
> -	FDADR0 = par->metromem_desc_dma;
> -	LCCR0 |= LCCR0_ENB;
> +	struct metronomefb_par *par = data;
> +
> +	/* try to refcount the caller since we are the consumer after this */
> +	if (!try_module_get(fbmaster))
> +		return -ENODEV;
> +
> +	dev_dbg(&am200_device->dev, "mod_get %p\n", fbmaster);
> +	am200_board.fbmaster = fbmaster;
> +	par->metromem = (unsigned char __force *)video_mem;
> +	par->metromem_dma = dma;
> +
> +	return 0;
>  }
>  
> -static void am200_init_lcdc_regs(struct metronomefb_par *par)
> +static void am200_unshare_video_mem(void *data)
>  {
> -	/* here we do:
> -	- disable the lcd controller
> -	- setup lcd control registers
> -	- setup dma descriptor
> -	- reenable lcd controller
> -	*/
> -
> -	/* disable the lcd controller */
> -	am200_disable_lcd_controller(par);
> -
> -	/* setup lcd control registers */
> -	LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
> -		| LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
> -
> -	LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */
> -		| (27 << 10) /* hsync pulse width - 1 */
> -		| (33 << 16) /* eol pixel count */
> -		| (33 << 24); /* bol pixel count */
> -
> -	LCCR2 = (par->info->var.yres - 1) /* lines per panel */
> -		| (24 << 10) /* vsync pulse width - 1 */
> -		| (2 << 16) /* eof pixel count */
> -		| (0 << 24); /* bof pixel count */
> -
> -	LCCR3 = 2 /* pixel clock divisor */
> -		| (24 << 8) /* AC Bias pin freq */
> -		| LCCR3_16BPP /* BPP */
> -		| LCCR3_PCP;  /* PCP falling edge */
> +	struct metronomefb_par *par = data;
>  
> +	dev_dbg(&am200_device->dev, "ENTER %s\n", __func__);
> +	par->metromem = NULL;
> +	par->metromem_dma = 0;
> +	dev_dbg(&am200_device->dev, "mod_put %p\n", am200_board.fbmaster);
> +	module_put(am200_board.fbmaster);
>  }
>  
> -static void am200_post_dma_setup(struct metronomefb_par *par)
> +static int am200_setup_fb(struct metronomefb_par *par)
>  {
> -	par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
> -	par->metromem_desc->mFSADR0 = par->metromem_dma;
> -	par->metromem_desc->mFIDR0 = 0;
> -	par->metromem_desc->mLDCMD0 = par->info->var.xres
> -					* par->info->var.yres;
> -	am200_enable_lcd_controller(par);
> +	int ret;
> +
> +	am200_fb_info.extra_video_mem = par->extra_size;
> +	am200_fb_info.extra_data = (void *) par;
> +	am200_fb_info.share_video_mem = am200_share_video_mem;
> +	am200_fb_info.unshare_video_mem = am200_unshare_video_mem;
> +
> +	switch (panel_type) {
> +	case 6:
> +		am200_fb_info.modes = &am200_fb_mode_6inch;
> +		break;
> +	case 8:
> +		am200_fb_info.modes = &am200_fb_mode_8inch;
> +		break;
> +	case 97:
> +		am200_fb_info.modes = &am200_fb_mode_9inch7;
> +		break;
> +	default:
> +		dev_err(&am200_device->dev, "invalid panel_type selection,"
> +						" setting to 6\n");
> +		am200_fb_info.modes = &am200_fb_mode_6inch;
> +		break;
> +	}
> +
> +	ret = am200_pxa_register_device(&pxa_device_fb, &am200_fb_info);
> +	return ret;
>  }
>  
> -static void am200_free_irq(struct fb_info *info)
> +static int am200_get_panel_type(void)
>  {
> -	free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
> +	return panel_type;
>  }
>  
>  static irqreturn_t am200_handle_irq(int irq, void *dev_id)
> @@ -212,53 +254,59 @@ static irqreturn_t am200_handle_irq(int irq, void *dev_id)
>  
>  static int am200_setup_irq(struct fb_info *info)
>  {
> -	int retval;
> +	int ret;
>  
> -	retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq,
> +	ret = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq,
>  				IRQF_DISABLED, "AM200", info);
> -	if (retval) {
> -		printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval);
> -		return retval;
> +	if (ret) {
> +		dev_err(&am200_device->dev, "request_irq failed: %d\n", ret);
> +		return ret;
>  	}
>  
> -	return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING);
> +	ret = set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING);

This can be specified in request_irq(), e.g.

	request_irq(..., IRQF_DISABLED | IRQF_TRIGGER_FALLING, ...)

the rest of the edge configuration work will be automatically done.

> +	if (ret)
> +		dev_err(&am200_device->dev, "set_irq_type failed: %d\n", ret);
> +
> +	return ret;
>  }
>  
>  static void am200_set_rst(struct metronomefb_par *par, int state)
>  {
> -	am200_set_gpio_output(RST_GPIO_PIN, state);
> +	gpio_set_value(RST_GPIO_PIN, state);
>  }
>  
>  static void am200_set_stdby(struct metronomefb_par *par, int state)
>  {
> -	am200_set_gpio_output(STDBY_GPIO_PIN, state);
> +	gpio_set_value(STDBY_GPIO_PIN, state);
>  }
>  
>  static int am200_wait_event(struct metronomefb_par *par)
>  {
> -	return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
> +	return wait_event_timeout(par->waitq, gpio_get_value(RDY_GPIO_PIN), HZ);
>  }
>  
>  static int am200_wait_event_intr(struct metronomefb_par *par)
>  {
> -	return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ);
> +	int ret;
> +
> +	ret = wait_event_interruptible_timeout(par->waitq,
> +					gpio_get_value(RDY_GPIO_PIN), HZ);
> +	return ret;
>  }
>  
>  static struct metronome_board am200_board = {
>  	.owner			= THIS_MODULE,
> -	.free_irq		= am200_free_irq,
>  	.setup_irq		= am200_setup_irq,
> -	.init_gpio_regs		= am200_init_gpio_regs,
> -	.init_lcdc_regs		= am200_init_lcdc_regs,
> -	.post_dma_setup		= am200_post_dma_setup,
> +	.setup_io		= am200_init_gpio_regs,
> +	.setup_fb		= am200_setup_fb,
>  	.set_rst		= am200_set_rst,
>  	.set_stdby		= am200_set_stdby,
>  	.met_wait_event		= am200_wait_event,
>  	.met_wait_event_intr	= am200_wait_event_intr,
> +	.get_panel_type		= am200_get_panel_type,
> +	.cleanup		= am200_cleanup,
>  };
>  
> -static struct platform_device *am200_device;
> -
>  static int __init am200_init(void)
>  {
>  	int ret;
> @@ -284,9 +332,13 @@ static int __init am200_init(void)
>  
>  static void __exit am200_exit(void)
>  {
> +	platform_device_unregister(am200_pxa_device_fb);
>  	platform_device_unregister(am200_device);
>  }
>  
> +module_param(panel_type, uint, 0);
> +MODULE_PARM_DESC(panel_type, "Select the panel type: 6, 8, 97");
> +
>  module_init(am200_init);
>  module_exit(am200_exit);
>  
> diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
> index b72b73a..fe0eb07 100644
> --- a/arch/arm/mach-pxa/devices.c
> +++ b/arch/arm/mach-pxa/devices.c
> @@ -127,6 +127,7 @@ struct platform_device pxa_device_fb = {
>  	.num_resources	= ARRAY_SIZE(pxafb_resources),
>  	.resource	= pxafb_resources,
>  };
> +EXPORT_SYMBOL_GPL(pxa_device_fb);
>  
>  void __init set_pxa_fb_info(struct pxafb_mach_info *info)
>  {


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php

  reply	other threads:[~2008-06-13  2:21 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-06-12 16:59 [RFC 2.6.26-rc3 0/10] am200epd, pxafb, metronomefb changes v4 Jaya Kumar
2008-06-12 16:59 ` [RFC 2.6.26-rc3 01/10] pxafb: fix ifdef for command line option handling Jaya Kumar
     [not found]   ` <20080612203541.0baa5586.krzysztof.h1@poczta.fm>
2008-06-13  1:22     ` Eric Miao
2008-06-13  7:37   ` Russell King - ARM Linux
2008-06-12 16:59 ` [RFC 2.6.26-rc3 02/10] pxafb: cleanup and fix order of failure handling Jaya Kumar
2008-06-12 18:36   ` Krzysztof Helt
2008-06-13  1:23     ` Eric Miao
2008-06-13  7:37   ` Russell King - ARM Linux
2008-06-12 16:59 ` [RFC 2.6.26-rc3 03/10] pxafb: fix __devinit/exit annotations Jaya Kumar
2008-06-12 18:36   ` [Linux-fbdev-devel] " Krzysztof Helt
2008-06-13  1:24     ` Eric Miao
2008-06-13  7:38   ` Russell King - ARM Linux
2008-06-12 16:59 ` [RFC 2.6.26-rc3 04/10] pxafb: add exit and remove handlers Jaya Kumar
2008-06-12 18:37   ` [Linux-fbdev-devel] " Krzysztof Helt
2008-06-13  1:24   ` Eric Miao
2008-06-13  7:39   ` Russell King - ARM Linux
2008-06-12 16:59 ` [RFC 2.6.26-rc3 05/10] pxafb: add shared framebuffer interface Jaya Kumar
2008-06-15  6:26   ` [Linux-fbdev-devel] " Krzysztof Helt
2008-06-15  6:49     ` Jaya Kumar
2008-06-12 16:59 ` [RFC 2.6.26-rc3 06/10] gumstix: conversion to MFP support and add bluetooth support Jaya Kumar
2008-06-13  2:01   ` Eric Miao
2008-06-15  5:51     ` Jaya Kumar
2008-06-16  2:21       ` Eric Miao
2008-07-04  5:01         ` Jaya Kumar
2008-07-08  0:52     ` Jaya Kumar
2008-06-13  7:42   ` Russell King - ARM Linux
2008-06-15  5:54     ` Jaya Kumar
2008-07-31  9:04   ` Andrew Morton
2008-06-12 16:59 ` [RFC 2.6.26-rc3 07/10] am200epd: move am200epd to mach-pxa Jaya Kumar
2008-06-13  2:12   ` Eric Miao
2008-06-15  6:23     ` Jaya Kumar
2008-06-16  2:29       ` Eric Miao
2008-06-12 16:59 ` [RFC 2.6.26-rc3 08/10] am200epd: convert to shared fb and use gpio api Jaya Kumar
2008-06-13  2:20   ` Eric Miao [this message]
2008-06-15  6:42     ` Jaya Kumar
2008-06-16  2:35       ` Eric Miao
2008-07-08 12:43         ` Jaya Kumar
2008-06-12 16:59 ` [RFC 2.6.26-rc3 09/10] metronomefb: convert printk to dev_dbg/err messages Jaya Kumar
2008-06-13  2:22   ` Eric Miao
2008-06-12 16:59 ` [RFC 2.6.26-rc3 10/10] metronomefb: changes to use separate framebuffer Jaya Kumar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4851D98A.5000508@gmail.com \
    --to=eric.y.miao@gmail.com \
    --cc=jayakumar.lkml@gmail.com \
    --cc=linux-arm-kernel@lists.arm.linux.org.uk \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    --cc=ymiao3@marvell.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).