Re: [PATCH 01/01] New FBDev driver for Intel Vermilion Range

From: Antonino A. Daplas
Date: Thu Apr 05 2007 - 20:10:00 EST


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

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