From: "Antonino A. Daplas" <adaplas@gmail.com>
To: Alan Hourihane <alanh@fairlite.demon.co.uk>
Cc: linux-kernel@vger.kernel.org
Subject: Re: [PATCH 01/01] New FBDev driver for Intel Vermilion Range
Date: Fri, 06 Apr 2007 08:09:18 +0800 [thread overview]
Message-ID: <1175818158.31131.63.camel@daplas> (raw)
In-Reply-To: <1175769886.10382.29.camel@localhost>
On Thu, 2007-04-05 at 11:44 +0100, Alan Hourihane wrote:
> Attached is a patch against 2.6.21-rc5 which adds the Intel Vermilion
> Range support.
>
> Intel funded Tungsten Graphics to do this work.
>
> If there's any problems or updates needed to be done to get accepted,
> please let me know.
>
Preferably, add sparse annotations and compile with make C=1. I've
included possible sparse annotations (the only ones I can see) below.
>
> +
> +struct cr_sys {
> + struct vml_sys sys;
> + struct pci_dev *mch_dev;
> + struct pci_dev *lpc_dev;
> + __u32 mch_bar;
> + __u8 *mch_regs_base;
void __iomem *mch_regs_base; (sparse)
> + __u32 gpio_bar;
> + __u32 saved_panel_state;
> + __u32 saved_clock;
> +};
> +
>
> +static void crvml_panel_on(const struct vml_sys *sys)
> +{
> + const struct cr_sys *crsys = container_of(sys, struct cr_sys, sys);
> + __u32 addr = crsys->gpio_bar + CRVML_PANEL_PORT;
> + __u32 cur = inl(addr);
> +
> + if (!(cur & CRVML_PANEL_ON)) {
> + /* Make sure LVDS controller is down. */
> + if (cur & 0x00000001) {
> + cur &= ~CRVML_LVDS_ON;
> + outl(cur, addr);
> + }
> + /* Power up Panel */
> + schedule_timeout(HZ / 10);
> + cur |= CRVML_PANEL_ON;
> + outl(cur, addr);
> + }
> +
> + /* Power up LVDS controller */
> +
> + if (!(cur & CRVML_LVDS_ON)) {
> + schedule_timeout(HZ / 10);
> + outl(cur | CRVML_LVDS_ON, addr);
> + }
> +}
> +
> +static void crvml_panel_off(const struct vml_sys *sys)
> +{
> + const struct cr_sys *crsys = container_of(sys, struct cr_sys, sys);
> +
> + __u32 addr = crsys->gpio_bar + CRVML_PANEL_PORT;
> + __u32 cur = inl(addr);
> +
> + /* Power down LVDS controller first to avoid high currents */
> + if (cur & CRVML_LVDS_ON) {
> + cur &= ~CRVML_LVDS_ON;
> + outl(cur, addr);
> + }
> + if (cur & CRVML_PANEL_ON) {
> + schedule_timeout(HZ / 10);
> + outl(cur & ~CRVML_PANEL_ON, addr);
> + }
> +}
> +
> +static void crvml_backlight_on(const struct vml_sys *sys)
> +{
> + const struct cr_sys *crsys = container_of(sys, struct cr_sys, sys);
> + __u32 addr = crsys->gpio_bar + CRVML_PANEL_PORT;
> + __u32 cur = inl(addr);
> +
> + if (cur & CRVML_BACKLIGHT_OFF) {
> + cur &= ~CRVML_BACKLIGHT_OFF;
> + outl(cur, addr);
> + }
> +}
> +
> +static void crvml_backlight_off(const struct vml_sys *sys)
> +{
> + const struct cr_sys *crsys = container_of(sys, struct cr_sys, sys);
> + __u32 addr = crsys->gpio_bar + CRVML_PANEL_PORT;
> + __u32 cur = inl(addr);
> +
> + if (!(cur & CRVML_BACKLIGHT_OFF)) {
> + cur |= CRVML_BACKLIGHT_OFF;
> + outl(cur, addr);
> + }
> +}
>
Perhaps backling_on/off and panel_on/off can be moved to the backlight
subsystem?
> +
>
> +static int crvml_sys_restore(struct vml_sys *sys)
> +{
> + struct cr_sys *crsys = container_of(sys, struct cr_sys, sys);
> + __u32 *clock_reg = (__u32 *) (crsys->mch_regs_base + CRVML_REG_CLOCK);
__u32 __iomem *clock_reg = crsys->mch_regs_base + CRVML_REG_CLOCK; (sparse)
> + __u32 cur = crsys->saved_panel_state;
> +
> + if (cur & CRVML_BACKLIGHT_OFF) {
> + crvml_backlight_off(sys);
> + } else {
> + crvml_backlight_on(sys);
> + }
> +
> + if (cur & CRVML_PANEL_ON) {
> + crvml_panel_on(sys);
> + } else {
> + crvml_panel_off(sys);
> + if (cur & CRVML_LVDS_ON) {
> + ;
> + /* Will not power up LVDS controller while panel is off */
> + }
> + }
> + iowrite32(crsys->saved_clock, clock_reg);
> + ioread32(clock_reg);
> +
> + return 0;
> +}
> +
> +static int crvml_sys_save(struct vml_sys *sys)
> +{
> + struct cr_sys *crsys = container_of(sys, struct cr_sys, sys);
> + __u32 *clock_reg = (__u32 *) (crsys->mch_regs_base + CRVML_REG_CLOCK);
> +
__u32 __iomem *clock_reg = crsys->mch_regs_base + CRVML_REG_CLOCK; (sparse)
> + crsys->saved_panel_state = inl(crsys->gpio_bar + CRVML_PANEL_PORT);
> + crsys->saved_clock = ioread32(clock_reg);
> +
> + return 0;
> +}
> +
> +static int crvml_nearest_index(const struct vml_sys *sys, int clock)
> +{
> +
> + int i;
> + int cur_index;
> + int cur_diff;
> + int diff;
> +
> + cur_index = 0;
> + cur_diff = clock - crvml_clocks[0];
> + cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
> + for (i = 1; i < crvml_num_clocks; ++i) {
> + diff = clock - crvml_clocks[i];
> + diff = (diff < 0) ? -diff : diff;
> + if (diff < cur_diff) {
> + cur_index = i;
> + cur_diff = diff;
> + }
> + }
> + return cur_index;
> +}
> +
> +static int crvml_nearest_clock(const struct vml_sys *sys, int clock)
> +{
> + return crvml_clocks[crvml_nearest_index(sys, clock)];
> +}
> +
> +static int crvml_set_clock(struct vml_sys *sys, int clock)
> +{
> + struct cr_sys *crsys = container_of(sys, struct cr_sys, sys);
> + __u32 *clock_reg = (__u32 *) (crsys->mch_regs_base + CRVML_REG_CLOCK);
>
__u32 __iomem *clock_reg = crsys->mch_regs_base + CRVML_REG_CLOCK; (sparse)
> + int index;
> + __u32 clock_val;
> +
> + index = crvml_nearest_index(sys, clock);
> +
> + if (crvml_clocks[index] != clock)
> + return -EINVAL;
> +
> + clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK;
> + clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT;
> + iowrite32(clock_val, clock_reg);
> + ioread32(clock_reg);
> +
> + return 0;
> +}
> +
> +
> +static int __init crvml_init(void)
> +{
> + int err = 0;
> + struct vml_sys *sys;
> + struct cr_sys *crsys;
> +
> + crsys = (struct cr_sys *)kmalloc(sizeof(*crsys), GFP_KERNEL);
> +
> + if (!crsys)
> + return -ENOMEM;
> +
> + sys = &crsys->sys;
> + err = crvml_sysinit(crsys);
> + if (err) {
> + kfree(crsys);
> + return err;
> + }
> +
> + sys->destroy = crvml_sys_destroy;
> + sys->subsys = crvml_subsys;
> + sys->save = crvml_sys_save;
> + sys->restore = crvml_sys_restore;
> + sys->prog_clock = crvml_false;
> + sys->set_clock = crvml_set_clock;
> + sys->has_panel = crvml_true;
Hmm...
> +
> +#ifndef FB_BLANK_UNBLANK
> +#define FB_BLANK_UNBLANK VESA_NO_BLANKING
> +#endif
> +#ifndef FB_BLANK_NORMAL
> +#define FB_BLANK_NORMAL VESA_NO_BLANKING + 1
> +#endif
> +#ifndef FB_BLANK_VSYNC_SUSPEND
> +#define FB_BLANK_VSYNC_SUSPEND VESA_VSYNC_SUSPEND + 1
> +#endif
> +#ifndef FB_BLANK_HSYNC_SUSPEND
> +#define FB_BLANK_HSYNC_SUSPEND VESA_HSYNC_SUSPEND + 1
> +#endif
> +#ifndef FB_BLANK_POWERDOWN
> +#define FB_BLANK_POWERDOWN VESA_POWERDOWN + 1
> +#endif
Since this driver going to be part of the kernel, the above is redundant,
you don't need it.
>
> +static int __devinit vml_pci_probe(struct pci_dev *dev,
> + const struct pci_device_id *id)
> +{
> + struct vml_info *vinfo;
> + struct fb_info *info;
> + struct vml_par *par;
> + int err = 0;
> +
> + par = kmalloc(sizeof(*par), GFP_KERNEL);
> + if (par == NULL)
> + return -ENOMEM;
> +
> + vinfo = kmalloc(sizeof(*vinfo), GFP_KERNEL);
You can use kzalloc instead of kmalloc.
> + if (vinfo == NULL) {
> + err = -ENOMEM;
> + goto out_err_0;
> + }
> +
> + memset(vinfo, 0, sizeof(*vinfo));
> + memset(par, 0, sizeof(*par));
> +
You can also use framebuffer_alloc()/framebuffer_release() for
struct fb_info and for par. But if it is not possible,
set info->device = dev->dev so your driver can show up in sysfs.
> + vinfo->par = par;
> + vinfo->pipe = 0;
> + par->mutex = &global_mutex;
> + INIT_LIST_HEAD(&par->gpu.head);
> + par->gpu_list = &global_gpu_list;
> + par->vdc = dev;
> + atomic_set(&par->refcount, 1);
> +
> + switch (id->device) {
> + case VML_DEVICE_VDC:
> + if ((err = vmlfb_get_gpu(par)))
> + goto out_err_1;
> + if ((err = pci_enable_device(dev)))
> + goto out_err_1;
> + pci_set_drvdata(dev, &vinfo->info);
> + break;
> + default:
> + err = -ENODEV;
> + goto out_err_1;
> + break;
> + }
> +
> + info = &vinfo->info;
> + info->flags = FBINFO_PARTIAL_PAN_OK;
Since your driver is tristate, do
info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK;
I will probably use this flag later to differentiate driver modules
to fix a bug in the logo drawing code.
You may also wish to add FBINFO_HW_ACCEL_YPAN for faster text scrolling.
>
> +
> +static void vml_wait_vblank(struct vml_info *vinfo)
> +{
> + schedule_timeout(HZ / 40);
>
This is not really wait for vblank, is it?
> +
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
> +static int vmlfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
> + unsigned long arg, struct fb_info *info)
> +#else
> +static int vmlfb_ioctl(struct fb_info *info, unsigned int cmd,
> + unsigned long arg)
> +#endif
>
Similarly, you can remove the above version checks.
Tony
next prev parent reply other threads:[~2007-04-06 0:09 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-05 10:44 [PATCH 01/01] New FBDev driver for Intel Vermilion Range Alan Hourihane
2007-04-05 17:38 ` Valdis.Kletnieks
2007-04-05 18:42 ` James Simmons
2007-04-05 18:58 ` Alan Hourihane
[not found] ` <200704052138.08897.arnd@arndb.de>
2007-04-05 21:42 ` Alan Hourihane
2007-04-05 21:56 ` Arnd Bergmann
2007-04-05 22:00 ` Antonino A. Daplas
2007-04-06 0:09 ` Antonino A. Daplas [this message]
2007-04-06 13:39 ` Alan Hourihane
2007-04-09 20:10 ` Pavel Machek
2007-04-20 9:04 ` Alan Hourihane
2007-04-20 13:51 ` Antonino A. Daplas
2007-04-20 13:54 ` Alan Hourihane
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=1175818158.31131.63.camel@daplas \
--to=adaplas@gmail.com \
--cc=alanh@fairlite.demon.co.uk \
--cc=linux-kernel@vger.kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.