[patch 17/18] PS3: Frame buffer system-bus rework

Geert Uytterhoeven Geert.Uytterhoeven at sonycom.com
Wed Jun 6 16:51:05 EST 2007


This one should go through linux-fbdev-devel (CC) for review, but Paul can
merge it because it depends on the PS3 system bus device rework.

On Tue, 5 Jun 2007, Geoff Levand wrote:
> Convert the ps3fb device from a platform device to a PS3 system bus device.
> Fix the remove and shutdown methods to support kexec and to make ps3fb a
> loadable module.
> 
> Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven at sonycom.com>
> Signed-off-by: Geoff Levand <geoffrey.levand at am.sony.com>
> ---
>  arch/powerpc/platforms/ps3/setup.c |    9 -
>  drivers/video/Kconfig              |    4 
>  drivers/video/ps3fb.c              |  300 +++++++++++++++++--------------------
>  include/asm-powerpc/ps3fb.h        |   12 -
>  4 files changed, 145 insertions(+), 180 deletions(-)
> 
> --- a/arch/powerpc/platforms/ps3/setup.c
> +++ b/arch/powerpc/platforms/ps3/setup.c
> @@ -107,7 +107,7 @@ static void ps3_panic(char *str)
>  	while(1);
>  }
>  
> -#ifdef CONFIG_FB_PS3
> +#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE)
>  static void prealloc(struct ps3_prealloc *p)
>  {
>  	if (!p->size)
> @@ -125,10 +125,11 @@ static void prealloc(struct ps3_prealloc
>  }
>  
>  struct ps3_prealloc ps3fb_videomemory = {
> -    .name = "ps3fb videomemory",
> -    .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024,
> -    .align = 1024*1024			/* the GPU requires 1 MiB alignment */
> +	.name = "ps3fb videomemory",
> +	.size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024,
> +	.align = 1024*1024		/* the GPU requires 1 MiB alignment */
>  };
> +EXPORT_SYMBOL_GPL(ps3fb_videomemory);
>  #define prealloc_ps3fb_videomemory()	prealloc(&ps3fb_videomemory)
>  
>  static int __init early_parse_ps3fb(char *p)
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -1790,8 +1790,8 @@ config FB_IBM_GXT4500
>  	  adaptor, found on some IBM System P (pSeries) machines.
>  
>  config FB_PS3
> -	bool "PS3 GPU framebuffer driver"
> -	depends on (FB = y) && PS3_PS3AV
> +	tristate "PS3 GPU framebuffer driver"
> +	depends on FB && PS3_PS3AV
>  	select FB_SYS_FILLRECT
>  	select FB_SYS_COPYAREA
>  	select FB_SYS_IMAGEBLIT
> --- a/drivers/video/ps3fb.c
> +++ b/drivers/video/ps3fb.c
> @@ -27,7 +27,6 @@
>  #include <linux/vmalloc.h>
>  #include <linux/delay.h>
>  #include <linux/interrupt.h>
> -#include <linux/platform_device.h>
>  #include <linux/console.h>
>  #include <linux/ioctl.h>
>  #include <linux/notifier.h>
> @@ -46,6 +45,9 @@
>  #include <asm/ps3fb.h>
>  #include <asm/ps3.h>
>  
> +
> +#define DEVICE_NAME		"ps3fb"
> +
>  #ifdef PS3FB_DEBUG
>  #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
>  #else
> @@ -126,7 +128,6 @@ struct gpu_driver_info {
>  
>  struct ps3fb_priv {
>  	unsigned int irq_no;
> -	void *dev;
>  
>  	u64 context_handle, memory_handle;
>  	void *xdr_ea;
> @@ -171,7 +172,7 @@ static const struct ps3fb_res_table ps3f
>  	{    0,    0,   0,   0 , 0} };
>  
>  /* default resolution */
> -#define GPU_RES_INDEX 0		/* 720 x 480 */
> +#define GPU_RES_INDEX	0		/* 720 x 480 */
>  
>  static const struct fb_videomode ps3fb_modedb[] = {
>      /* 60 Hz broadcast modes (modes "1" to "5") */
> @@ -298,10 +299,9 @@ static const struct fb_videomode ps3fb_m
>  #define FB_OFF(i)	(GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
>  
>  static int ps3fb_mode;
> -module_param(ps3fb_mode, bool, 0);
> -
> -static char *mode_option __initdata;
> +module_param(ps3fb_mode, int, 0);
>  
> +static char *mode_option __devinitdata;
>  
>  static int ps3fb_get_res_table(u32 xres, u32 yres)
>  {
> @@ -681,15 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc)
>  
>  EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
>  
> -void ps3fb_flip_ctl(int on)
> +void ps3fb_flip_ctl(int on, void *data)
>  {
> +	struct ps3fb_priv *priv = data;
>  	if (on)
> -		atomic_dec_if_positive(&ps3fb.ext_flip);
> +		atomic_dec_if_positive(&priv->ext_flip);
>  	else
> -		atomic_inc(&ps3fb.ext_flip);
> +		atomic_inc(&priv->ext_flip);
>  }
>  
> -EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
>  
>      /*
>       * ioctl
> @@ -851,37 +851,9 @@ static irqreturn_t ps3fb_vsync_interrupt
>  	return IRQ_HANDLED;
>  }
>  
> -#ifndef MODULE
> -static int __init ps3fb_setup(char *options)
> -{
> -	char *this_opt;
> -	int mode = 0;
> -
> -	if (!options || !*options)
> -		return 0;	/* no options */
> -
> -	while ((this_opt = strsep(&options, ",")) != NULL) {
> -		if (!*this_opt)
> -			continue;
> -		if (!strncmp(this_opt, "mode:", 5))
> -			mode = simple_strtoul(this_opt + 5, NULL, 0);
> -		else
> -			mode_option = this_opt;
> -	}
> -	return mode;
> -}
> -#endif	/* MODULE */
> -
> -    /*
> -     *  Initialisation
> -     */
> -
> -static void ps3fb_platform_release(struct device *device)
> -{
> -	/* This is called when the reference count goes to zero. */
> -}
>  
> -static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
> +static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
> +				struct ps3_system_bus_device *dev)
>  {
>  	int error;
>  
> @@ -897,7 +869,6 @@ static int ps3fb_vsync_settings(struct g
>  		return -EINVAL;
>  	}
>  
> -	ps3fb.dev = dev;
>  	error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
>  				   &ps3fb.irq_no);
>  	if (error) {
> @@ -907,7 +878,7 @@ static int ps3fb_vsync_settings(struct g
>  	}
>  
>  	error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
> -			    "ps3fb vsync", ps3fb.dev);
> +			    DEVICE_NAME, dev);
>  	if (error) {
>  		printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
>  		       error);
> @@ -966,16 +937,47 @@ static struct fb_ops ps3fb_ops = {
>  };
>  
>  static struct fb_fix_screeninfo ps3fb_fix __initdata = {
> -	.id =		"PS3 FB",
> +	.id =		DEVICE_NAME,
>  	.type =		FB_TYPE_PACKED_PIXELS,
>  	.visual =	FB_VISUAL_TRUECOLOR,
>  	.accel =	FB_ACCEL_NONE,
>  };
>  
> -static int __init ps3fb_probe(struct platform_device *dev)
> +static int ps3fb_set_sync(void)
> +{
> +	int status;
> +
> +#ifdef HEAD_A
> +	status = lv1_gpu_context_attribute(0x0,
> +					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
> +					   0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
> +	if (status) {
> +		printk(KERN_ERR
> +		       "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
> +		       __func__, status);
> +		return -1;
> +	}
> +#endif
> +#ifdef HEAD_B
> +	status = lv1_gpu_context_attribute(0x0,
> +					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
> +					   1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
> +
> +	if (status) {
> +		printk(KERN_ERR
> +		       "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
> +		       __func__, status);
> +		return -1;
> +	}
> +#endif
> +	return 0;
> +}
> +
> +static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
>  {
>  	struct fb_info *info;
>  	int retval = -ENOMEM;
> +	u32 xres, yres;
>  	u64 ddr_lpar = 0;
>  	u64 lpar_dma_control = 0;
>  	u64 lpar_driver_info = 0;
> @@ -986,6 +988,32 @@ static int __init ps3fb_probe(struct pla
>  	unsigned long offset;
>  	struct task_struct *task;
>  
> +	printk(" -> %s:%u\n", __func__, __LINE__);
> +
> +	status = ps3_open_hv_device(dev);
> +	if (status) {
> +		printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__);
> +		goto err;
> +	}
> +
> +	if (!ps3fb_mode)
> +		ps3fb_mode = ps3av_get_mode();
> +	DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
> +
> +	if (ps3fb_mode > 0 &&
> +	    !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
> +		ps3fb.res_index = ps3fb_get_res_table(xres, yres);
> +		DPRINTK("res_index:%d\n", ps3fb.res_index);
> +	} else
> +		ps3fb.res_index = GPU_RES_INDEX;
> +
> +	atomic_set(&ps3fb.f_count, -1);	/* fbcon opens ps3fb */
> +	atomic_set(&ps3fb.ext_flip, 0);	/* for flip with vsync */
> +	init_waitqueue_head(&ps3fb.wait_vsync);
> +	ps3fb.num_frames = 1;
> +
> +	ps3fb_set_sync();
> +
>  	/* get gpu context handle */
>  	status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
>  					 &ps3fb.memory_handle, &ddr_lpar);
> @@ -1029,7 +1057,7 @@ static int __init ps3fb_probe(struct pla
>  	 * leakage into userspace
>  	 */
>  	memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
> -	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
> +	info = framebuffer_alloc(sizeof(u32) * 16, &dev->core);
>  	if (!info)
>  		goto err_free_irq;
>  
> @@ -1061,20 +1089,22 @@ static int __init ps3fb_probe(struct pla
>  	if (retval < 0)
>  		goto err_fb_dealloc;
>  
> -	platform_set_drvdata(dev, info);
> +	dev->core.driver_data = info;
>  
>  	printk(KERN_INFO
>  	       "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
>  	       info->node, ps3fb_videomemory.size >> 10);
>  
> -	task = kthread_run(ps3fbd, info, "ps3fbd");
> +	task = kthread_run(ps3fbd, info, DEVICE_NAME);
>  	if (IS_ERR(task)) {
>  		retval = PTR_ERR(task);
>  		goto err_unregister_framebuffer;
>  	}
>  
>  	ps3fb.task = task;
> +	ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
>  
> +	printk(" <- %s:%u\n", __func__, __LINE__);
>  	return 0;
>  
>  err_unregister_framebuffer:
> @@ -1084,7 +1114,7 @@ err_fb_dealloc:
>  err_framebuffer_release:
>  	framebuffer_release(info);
>  err_free_irq:
> -	free_irq(ps3fb.irq_no, ps3fb.dev);
> +	free_irq(ps3fb.irq_no, dev);
>  	ps3_irq_plug_destroy(ps3fb.irq_no);
>  err_iounmap_dinfo:
>  	iounmap((u8 __iomem *)ps3fb.dinfo);
> @@ -1096,26 +1126,39 @@ err:
>  	return retval;
>  }
>  
> -static void ps3fb_shutdown(struct platform_device *dev)
> +static int __devexit ps3fb_remove(struct ps3_system_bus_device *dev)
>  {
> -	ps3fb_flip_ctl(0);	/* flip off */
> -	ps3fb.dinfo->irq.mask = 0;
> -	free_irq(ps3fb.irq_no, ps3fb.dev);
> -	ps3_irq_plug_destroy(ps3fb.irq_no);
> -	iounmap((u8 __iomem *)ps3fb.dinfo);
> +	BUG();
> +	return 0;
>  }
>  
> -void ps3fb_cleanup(void)
> +static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
>  {
>  	int status;
> +	struct fb_info *info = dev->core.driver_data;
> +
> +	printk(" -> %s:%d\n", __func__, __LINE__);
> +
> +	// is this stuff ok here??
> +	// just set .shutdown = ps3fb_remove???
> +
> +	ps3fb_flip_ctl(0, &ps3fb);	/* flip off */
> +	ps3fb.dinfo->irq.mask = 0;
> +
> +	if (info) {
> +		unregister_framebuffer(info);
> +		fb_dealloc_cmap(&info->cmap);
> +		framebuffer_release(info);
> +	}
>  
> +	ps3av_register_flip_ctl(NULL, NULL);
>  	if (ps3fb.task) {
>  		struct task_struct *task = ps3fb.task;
>  		ps3fb.task = NULL;
>  		kthread_stop(task);
>  	}
>  	if (ps3fb.irq_no) {
> -		free_irq(ps3fb.irq_no, ps3fb.dev);
> +		free_irq(ps3fb.irq_no, dev);
>  		ps3_irq_plug_destroy(ps3fb.irq_no);
>  	}
>  	iounmap((u8 __iomem *)ps3fb.dinfo);
> @@ -1128,134 +1171,67 @@ void ps3fb_cleanup(void)
>  	if (status)
>  		DPRINTK("lv1_gpu_memory_free failed: %d\n", status);
>  
> -	ps3av_dev_close();
> -}
> -
> -EXPORT_SYMBOL_GPL(ps3fb_cleanup);
> +	ps3_close_hv_device(dev);
> +	printk(" <- %s:%d\n", __func__, __LINE__);
>  
> -static int ps3fb_remove(struct platform_device *dev)
> -{
> -	struct fb_info *info = platform_get_drvdata(dev);
> -
> -	if (info) {
> -		unregister_framebuffer(info);
> -		fb_dealloc_cmap(&info->cmap);
> -		framebuffer_release(info);
> -	}
> -	ps3fb_cleanup();
>  	return 0;
>  }
>  
> -static struct platform_driver ps3fb_driver = {
> -	.probe	= ps3fb_probe,
> -	.remove = ps3fb_remove,
> -	.shutdown = ps3fb_shutdown,
> -	.driver = { .name = "ps3fb" }
> -};
> -
> -static struct platform_device ps3fb_device = {
> -	.name	= "ps3fb",
> -	.id	= 0,
> -	.dev	= { .release = ps3fb_platform_release }
> +static struct ps3_system_bus_driver ps3fb_driver = {
> +	.match_id	= PS3_MATCH_ID_GRAPHICS,
> +	.core.name	= DEVICE_NAME,
> +	.core.owner	= THIS_MODULE,
> +	.probe		= ps3fb_probe,
> +	.remove		= __devexit_p(ps3fb_remove),
> +	.shutdown	= ps3fb_shutdown,
>  };
>  
> -int ps3fb_set_sync(void)
> +static int __init ps3fb_setup(void)
>  {
> -	int status;
> +	char *options, *this_opt;
>  
> -#ifdef HEAD_A
> -	status = lv1_gpu_context_attribute(0x0,
> -					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
> -					   0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
> -	if (status) {
> -		printk(KERN_ERR
> -		       "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
> -		       __func__, status);
> -		return -1;
> -	}
> +#ifdef MODULE
> +	return 0;
>  #endif
> -#ifdef HEAD_B
> -	status = lv1_gpu_context_attribute(0x0,
> -					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
> -					   1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
>  
> -	if (status) {
> -		printk(KERN_ERR
> -		       "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
> -		       __func__, status);
> -		return -1;
> +	if (fb_get_options(DEVICE_NAME, &options))
> +		return -ENXIO;
> +
> +	if (!options || !*options)
> +		return 0;
> +
> +	while ((this_opt = strsep(&options, ",")) != NULL) {
> +		if (!*this_opt)
> +			continue;
> +		if (!strncmp(this_opt, "mode:", 5))
> +			ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0);
> +		else
> +			mode_option = this_opt;
>  	}
> -#endif
>  	return 0;
>  }
>  
> -EXPORT_SYMBOL_GPL(ps3fb_set_sync);
> -
>  static int __init ps3fb_init(void)
>  {
> -	int error;
> -#ifndef MODULE
> -	int mode;
> -	char *option = NULL;
> -
> -	if (fb_get_options("ps3fb", &option))
> -		goto err;
> -#endif
> -
> -	if (!ps3fb_videomemory.address)
> -		goto err;
> -
> -	error = ps3av_dev_open();
> -	if (error) {
> -		printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
> -		goto err;
> -	}
> -
> -	ps3fb_mode = ps3av_get_mode();
> -	DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
> -#ifndef MODULE
> -	mode = ps3fb_setup(option);	/* check boot option */
> -	if (mode)
> -		ps3fb_mode = mode;
> -#endif
> -	if (ps3fb_mode > 0) {
> -		u32 xres, yres;
> -		ps3av_video_mode2res(ps3fb_mode, &xres, &yres);
> -		ps3fb.res_index = ps3fb_get_res_table(xres, yres);
> -		DPRINTK("res_index:%d\n", ps3fb.res_index);
> -	} else
> -		ps3fb.res_index = GPU_RES_INDEX;
> -
> -	atomic_set(&ps3fb.f_count, -1);	/* fbcon opens ps3fb */
> -	atomic_set(&ps3fb.ext_flip, 0);	/* for flip with vsync */
> -	init_waitqueue_head(&ps3fb.wait_vsync);
> -	ps3fb.num_frames = 1;
> -
> -	error = platform_driver_register(&ps3fb_driver);
> -	if (!error) {
> -		error = platform_device_register(&ps3fb_device);
> -		if (error)
> -			platform_driver_unregister(&ps3fb_driver);
> -	}
> -
> -	ps3fb_set_sync();
> -
> -	return error;
> +	if (!ps3fb_videomemory.address ||  ps3fb_setup())
> +		return -ENXIO;
>  
> -err:
> -	return -ENXIO;
> +	return ps3_system_bus_driver_register(&ps3fb_driver);
>  }
>  
> -module_init(ps3fb_init);
> -
> -#ifdef MODULE
>  static void __exit ps3fb_exit(void)
>  {
> -	platform_device_unregister(&ps3fb_device);
> -	platform_driver_unregister(&ps3fb_driver);
> +	printk(" -> %s:%d\n", __func__, __LINE__);
> +	ps3_system_bus_driver_unregister(&ps3fb_driver);
> +	printk(" <- %s:%d\n", __func__, __LINE__);
>  }
>  
> -module_exit(ps3fb_exit);
> +module_init(ps3fb_init);
> +#if 0
> +module_exit(ps3fb_exit);	/* FIXME: need to fix fbcon to support remove */
> +#endif
>  
>  MODULE_LICENSE("GPL");
> -#endif				/* MODULE */
> +MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
> +MODULE_AUTHOR("Sony Computer Entertainment Inc.");
> +MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);
> --- a/include/asm-powerpc/ps3fb.h
> +++ b/include/asm-powerpc/ps3fb.h
> @@ -41,16 +41,4 @@ struct ps3fb_ioctl_res {
>  	__u32 num_frames; /* num of frame buffers */
>  };
>  
> -#ifdef __KERNEL__
> -
> -#ifdef CONFIG_FB_PS3
> -extern void ps3fb_flip_ctl(int on);
> -extern void ps3fb_cleanup(void);
> -#else
> -static inline void ps3fb_flip_ctl(int on) {}
> -static inline void ps3fb_cleanup(void) {}
> -#endif
> -
> -#endif /* __KERNEL__ */
> -
>  #endif /* _ASM_POWERPC_PS3FB_H_ */
> 
> -- 
> 
> 

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- Sony Network and Software Technology Center Europe (NSCE)
Geert.Uytterhoeven at sonycom.com ------- The Corporate Village, Da Vincilaan 7-D1
Voice +32-2-7008453 Fax +32-2-7008622 ---------------- B-1935 Zaventem, Belgium



More information about the Linuxppc-dev mailing list