File Index
Files and directories
Sign in
FILE

lcdc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/omap/lcdc.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * OMAP1 internal LCD controller
  4 *
  5 * Copyright (C) 2004 Nokia Corporation
  6 * Author: Imre Deak <imre.deak@nokia.com>
  7 */
  8
  9#include <linux/module.h>
 10#include <linux/device.h>
 11#include <linux/export.h>
 12#include <linux/interrupt.h>
 13#include <linux/spinlock.h>
 14#include <linux/err.h>
 15#include <linux/mm.h>
 16#include <linux/fb.h>
 17#include <linux/dma-mapping.h>
 18#include <linux/vmalloc.h>
 19#include <linux/clk.h>
 20#include <linux/gfp.h>
 21
 22#include <linux/soc/ti/omap1-io.h>
 23#include <linux/soc/ti/omap1-soc.h>
 24#include <linux/omap-dma.h>
 25
 26#include <asm/mach-types.h>
 27
 28#include "omapfb.h"
 29
 30#include "lcdc.h"
 31#include "lcd_dma.h"
 32
 33#define MODULE_NAME			"lcdc"
 34
 35#define MAX_PALETTE_SIZE		PAGE_SIZE
 36
 37enum lcdc_load_mode {
 38	OMAP_LCDC_LOAD_PALETTE,
 39	OMAP_LCDC_LOAD_FRAME,
 40	OMAP_LCDC_LOAD_PALETTE_AND_FRAME
 41};
 42
 43static struct omap_lcd_controller {
 44	enum omapfb_update_mode	update_mode;
 45	int			ext_mode;
 46
 47	unsigned long		frame_offset;
 48	int			screen_width;
 49	int			xres;
 50	int			yres;
 51
 52	enum omapfb_color_format	color_mode;
 53	int			bpp;
 54	void			*palette_virt;
 55	dma_addr_t		palette_phys;
 56	int			palette_code;
 57	int			palette_size;
 58
 59	unsigned int		irq_mask;
 60	struct completion	last_frame_complete;
 61	struct completion	palette_load_complete;
 62	struct clk		*lcd_ck;
 63	struct omapfb_device	*fbdev;
 64
 65	void			(*dma_callback)(void *data);
 66	void			*dma_callback_data;
 67
 68	dma_addr_t		vram_phys;
 69	void			*vram_virt;
 70	unsigned long		vram_size;
 71} lcdc;
 72
 73static inline void enable_irqs(int mask)
 74{
 75	lcdc.irq_mask |= mask;
 76}
 77
 78static inline void disable_irqs(int mask)
 79{
 80	lcdc.irq_mask &= ~mask;
 81}
 82
 83static void set_load_mode(enum lcdc_load_mode mode)
 84{
 85	u32 l;
 86
 87	l = omap_readl(OMAP_LCDC_CONTROL);
 88	l &= ~(3 << 20);
 89	switch (mode) {
 90	case OMAP_LCDC_LOAD_PALETTE:
 91		l |= 1 << 20;
 92		break;
 93	case OMAP_LCDC_LOAD_FRAME:
 94		l |= 2 << 20;
 95		break;
 96	case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
 97		break;
 98	default:
 99		BUG();
100	}
101	omap_writel(l, OMAP_LCDC_CONTROL);
102}
103
104static void enable_controller(void)
105{
106	u32 l;
107
108	l = omap_readl(OMAP_LCDC_CONTROL);
109	l |= OMAP_LCDC_CTRL_LCD_EN;
110	l &= ~OMAP_LCDC_IRQ_MASK;
111	l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE;	/* enabled IRQs */
112	omap_writel(l, OMAP_LCDC_CONTROL);
113}
114
115static void disable_controller_async(void)
116{
117	u32 l;
118	u32 mask;
119
120	l = omap_readl(OMAP_LCDC_CONTROL);
121	mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
122	/*
123	 * Preserve the DONE mask, since we still want to get the
124	 * final DONE irq. It will be disabled in the IRQ handler.
125	 */
126	mask &= ~OMAP_LCDC_IRQ_DONE;
127	l &= ~mask;
128	omap_writel(l, OMAP_LCDC_CONTROL);
129}
130
131static void disable_controller(void)
132{
133	init_completion(&lcdc.last_frame_complete);
134	disable_controller_async();
135	if (!wait_for_completion_timeout(&lcdc.last_frame_complete,
136				msecs_to_jiffies(500)))
137		dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
138}
139
140static void reset_controller(u32 status)
141{
142	static unsigned long reset_count;
143	static unsigned long last_jiffies;
144
145	disable_controller_async();
146	reset_count++;
147	if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
148		dev_err(lcdc.fbdev->dev,
149			  "resetting (status %#010x,reset count %lu)\n",
150			  status, reset_count);
151		last_jiffies = jiffies;
152	}
153	if (reset_count < 100) {
154		enable_controller();
155	} else {
156		reset_count = 0;
157		dev_err(lcdc.fbdev->dev,
158			"too many reset attempts, giving up.\n");
159	}
160}
161
162/*
163 * Configure the LCD DMA according to the current mode specified by parameters
164 * in lcdc.fbdev and fbdev->var.
165 */
166static void setup_lcd_dma(void)
167{
168	static const int dma_elem_type[] = {
169		0,
170		OMAP_DMA_DATA_TYPE_S8,
171		OMAP_DMA_DATA_TYPE_S16,
172		0,
173		OMAP_DMA_DATA_TYPE_S32,
174	};
175	struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par;
176	struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
177	unsigned long	src;
178	int		esize, xelem, yelem;
179
180	src = lcdc.vram_phys + lcdc.frame_offset;
181
182	switch (var->rotate) {
183	case 0:
184		if (plane->info.mirror || (src & 3) ||
185		    lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
186		    (lcdc.xres & 1))
187			esize = 2;
188		else
189			esize = 4;
190		xelem = lcdc.xres * lcdc.bpp / 8 / esize;
191		yelem = lcdc.yres;
192		break;
193	case 90:
194	case 180:
195	case 270:
196		if (cpu_is_omap15xx()) {
197			BUG();
198		}
199		esize = 2;
200		xelem = lcdc.yres * lcdc.bpp / 16;
201		yelem = lcdc.xres;
202		break;
203	default:
204		BUG();
205		return;
206	}
207#ifdef VERBOSE
208	dev_dbg(lcdc.fbdev->dev,
209		 "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
210		 src, esize, xelem, yelem);
211#endif
212	omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
213	if (!cpu_is_omap15xx()) {
214		int bpp = lcdc.bpp;
215
216		/*
217		 * YUV support is only for external mode when we have the
218		 * YUV window embedded in a 16bpp frame buffer.
219		 */
220		if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
221			bpp = 16;
222		/* Set virtual xres elem size */
223		omap_set_lcd_dma_b1_vxres(
224			lcdc.screen_width * bpp / 8 / esize);
225		/* Setup transformations */
226		omap_set_lcd_dma_b1_rotation(var->rotate);
227		omap_set_lcd_dma_b1_mirror(plane->info.mirror);
228	}
229	omap_setup_lcd_dma();
230}
231
232static irqreturn_t lcdc_irq_handler(int irq, void *dev_id)
233{
234	u32 status;
235
236	status = omap_readl(OMAP_LCDC_STATUS);
237
238	if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
239		reset_controller(status);
240	else {
241		if (status & OMAP_LCDC_STAT_DONE) {
242			u32 l;
243
244			/*
245			 * Disable IRQ_DONE. The status bit will be cleared
246			 * only when the controller is reenabled and we don't
247			 * want to get more interrupts.
248			 */
249			l = omap_readl(OMAP_LCDC_CONTROL);
250			l &= ~OMAP_LCDC_IRQ_DONE;
251			omap_writel(l, OMAP_LCDC_CONTROL);
252			complete(&lcdc.last_frame_complete);
253		}
254		if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
255			disable_controller_async();
256			complete(&lcdc.palette_load_complete);
257		}
258	}
259
260	/*
261	 * Clear these interrupt status bits.
262	 * Sync_lost, FUF bits were cleared by disabling the LCD controller
263	 * LOADED_PALETTE can be cleared this way only in palette only
264	 * load mode. In other load modes it's cleared by disabling the
265	 * controller.
266	 */
267	status &= ~(OMAP_LCDC_STAT_VSYNC |
268		    OMAP_LCDC_STAT_LOADED_PALETTE |
269		    OMAP_LCDC_STAT_ABC |
270		    OMAP_LCDC_STAT_LINE_INT);
271	omap_writel(status, OMAP_LCDC_STATUS);
272	return IRQ_HANDLED;
273}
274
275/*
276 * Change to a new video mode. We defer this to a later time to avoid any
277 * flicker and not to mess up the current LCD DMA context. For this we disable
278 * the LCD controller, which will generate a DONE irq after the last frame has
279 * been transferred. Then it'll be safe to reconfigure both the LCD controller
280 * as well as the LCD DMA.
281 */
282static int omap_lcdc_setup_plane(int plane, int channel_out,
283				 unsigned long offset, int screen_width,
284				 int pos_x, int pos_y, int width, int height,
285				 int color_mode)
286{
287	struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
288	struct lcd_panel *panel = lcdc.fbdev->panel;
289	int rot_x, rot_y;
290
291	if (var->rotate == 0) {
292		rot_x = panel->x_res;
293		rot_y = panel->y_res;
294	} else {
295		rot_x = panel->y_res;
296		rot_y = panel->x_res;
297	}
298	if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
299	    width > rot_x || height > rot_y) {
300#ifdef VERBOSE
301		dev_dbg(lcdc.fbdev->dev,
302			"invalid plane params plane %d pos_x %d pos_y %d "
303			"w %d h %d\n", plane, pos_x, pos_y, width, height);
304#endif
305		return -EINVAL;
306	}
307
308	lcdc.frame_offset = offset;
309	lcdc.xres = width;
310	lcdc.yres = height;
311	lcdc.screen_width = screen_width;
312	lcdc.color_mode = color_mode;
313
314	switch (color_mode) {
315	case OMAPFB_COLOR_CLUT_8BPP:
316		lcdc.bpp = 8;
317		lcdc.palette_code = 0x3000;
318		lcdc.palette_size = 512;
319		break;
320	case OMAPFB_COLOR_RGB565:
321		lcdc.bpp = 16;
322		lcdc.palette_code = 0x4000;
323		lcdc.palette_size = 32;
324		break;
325	case OMAPFB_COLOR_RGB444:
326		lcdc.bpp = 16;
327		lcdc.palette_code = 0x4000;
328		lcdc.palette_size = 32;
329		break;
330	case OMAPFB_COLOR_YUV420:
331		if (lcdc.ext_mode) {
332			lcdc.bpp = 12;
333			break;
334		}
335		fallthrough;
336	case OMAPFB_COLOR_YUV422:
337		if (lcdc.ext_mode) {
338			lcdc.bpp = 16;
339			break;
340		}
341		fallthrough;
342	default:
343		/* FIXME: other BPPs.
344		 * bpp1: code  0,     size 256
345		 * bpp2: code  0x1000 size 256
346		 * bpp4: code  0x2000 size 256
347		 * bpp12: code 0x4000 size 32
348		 */
349		dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode);
350		BUG();
351		return -1;
352	}
353
354	if (lcdc.ext_mode) {
355		setup_lcd_dma();
356		return 0;
357	}
358
359	if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
360		disable_controller();
361		omap_stop_lcd_dma();
362		setup_lcd_dma();
363		enable_controller();
364	}
365
366	return 0;
367}
368
369static int omap_lcdc_enable_plane(int plane, int enable)
370{
371	dev_dbg(lcdc.fbdev->dev,
372		"plane %d enable %d update_mode %d ext_mode %d\n",
373		plane, enable, lcdc.update_mode, lcdc.ext_mode);
374	if (plane != OMAPFB_PLANE_GFX)
375		return -EINVAL;
376
377	return 0;
378}
379
380/*
381 * Configure the LCD DMA for a palette load operation and do the palette
382 * downloading synchronously. We don't use the frame+palette load mode of
383 * the controller, since the palette can always be downloaded separately.
384 */
385static void load_palette(void)
386{
387	u16	*palette;
388
389	palette = (u16 *)lcdc.palette_virt;
390
391	*(u16 *)palette &= 0x0fff;
392	*(u16 *)palette |= lcdc.palette_code;
393
394	omap_set_lcd_dma_b1(lcdc.palette_phys,
395		lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
396
397	omap_set_lcd_dma_single_transfer(1);
398	omap_setup_lcd_dma();
399
400	init_completion(&lcdc.palette_load_complete);
401	enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
402	set_load_mode(OMAP_LCDC_LOAD_PALETTE);
403	enable_controller();
404	if (!wait_for_completion_timeout(&lcdc.palette_load_complete,
405				msecs_to_jiffies(500)))
406		dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
407	/* The controller gets disabled in the irq handler */
408	disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
409	omap_stop_lcd_dma();
410
411	omap_set_lcd_dma_single_transfer(lcdc.ext_mode);
412}
413
414/* Used only in internal controller mode */
415static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
416			       u16 transp, int update_hw_pal)
417{
418	u16 *palette;
419
420	if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
421		return -EINVAL;
422
423	palette = (u16 *)lcdc.palette_virt;
424
425	palette[regno] &= ~0x0fff;
426	palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
427			   (blue >> 12);
428
429	if (update_hw_pal) {
430		disable_controller();
431		omap_stop_lcd_dma();
432		load_palette();
433		setup_lcd_dma();
434		set_load_mode(OMAP_LCDC_LOAD_FRAME);
435		enable_controller();
436	}
437
438	return 0;
439}
440
441static void calc_ck_div(int is_tft, int pck, int *pck_div)
442{
443	unsigned long lck;
444
445	pck = max(1, pck);
446	lck = clk_get_rate(lcdc.lcd_ck);
447	*pck_div = (lck + pck - 1) / pck;
448	if (is_tft)
449		*pck_div = max(2, *pck_div);
450	else
451		*pck_div = max(3, *pck_div);
452	if (*pck_div > 255) {
453		/* FIXME: try to adjust logic clock divider as well */
454		*pck_div = 255;
455		dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",
456			 pck / 1000);
457	}
458}
459
460static inline void setup_regs(void)
461{
462	u32 l;
463	struct lcd_panel *panel = lcdc.fbdev->panel;
464	int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
465	unsigned long lck;
466	int pcd;
467
468	l = omap_readl(OMAP_LCDC_CONTROL);
469	l &= ~OMAP_LCDC_CTRL_LCD_TFT;
470	l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
471#ifdef CONFIG_MACH_OMAP_PALMTE
472/* FIXME:if (machine_is_omap_palmte()) { */
473		/* PalmTE uses alternate TFT setting in 8BPP mode */
474		l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;
475/*	} */
476#endif
477	omap_writel(l, OMAP_LCDC_CONTROL);
478
479	l = omap_readl(OMAP_LCDC_TIMING2);
480	l &= ~(((1 << 6) - 1) << 20);
481	l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
482	omap_writel(l, OMAP_LCDC_TIMING2);
483
484	l = panel->x_res - 1;
485	l |= (panel->hsw - 1) << 10;
486	l |= (panel->hfp - 1) << 16;
487	l |= (panel->hbp - 1) << 24;
488	omap_writel(l, OMAP_LCDC_TIMING0);
489
490	l = panel->y_res - 1;
491	l |= (panel->vsw - 1) << 10;
492	l |= panel->vfp << 16;
493	l |= panel->vbp << 24;
494	omap_writel(l, OMAP_LCDC_TIMING1);
495
496	l = omap_readl(OMAP_LCDC_TIMING2);
497	l &= ~0xff;
498
499	lck = clk_get_rate(lcdc.lcd_ck);
500
501	if (!panel->pcd)
502		calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
503	else {
504		dev_warn(lcdc.fbdev->dev,
505		    "Pixel clock divider value is obsolete.\n"
506		    "Try to set pixel_clock to %lu and pcd to 0 "
507		    "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
508			lck / panel->pcd / 1000, panel->name);
509
510		pcd = panel->pcd;
511	}
512	l |= pcd & 0xff;
513	l |= panel->acb << 8;
514	omap_writel(l, OMAP_LCDC_TIMING2);
515
516	/* update panel info with the exact clock */
517	panel->pixel_clock = lck / pcd / 1000;
518}
519
520/*
521 * Configure the LCD controller, download the color palette and start a looped
522 * DMA transfer of the frame image data. Called only in internal
523 * controller mode.
524 */
525static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
526{
527	int r = 0;
528
529	if (mode != lcdc.update_mode) {
530		switch (mode) {
531		case OMAPFB_AUTO_UPDATE:
532			setup_regs();
533			load_palette();
534
535			/* Setup and start LCD DMA */
536			setup_lcd_dma();
537
538			set_load_mode(OMAP_LCDC_LOAD_FRAME);
539			enable_irqs(OMAP_LCDC_IRQ_DONE);
540			/* This will start the actual DMA transfer */
541			enable_controller();
542			lcdc.update_mode = mode;
543			break;
544		case OMAPFB_UPDATE_DISABLED:
545			disable_controller();
546			omap_stop_lcd_dma();
547			lcdc.update_mode = mode;
548			break;
549		default:
550			r = -EINVAL;
551		}
552	}
553
554	return r;
555}
556
557static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
558{
559	return lcdc.update_mode;
560}
561
562/* PM code called only in internal controller mode */
563static void omap_lcdc_suspend(void)
564{
565	omap_lcdc_set_update_mode(OMAPFB_UPDATE_DISABLED);
566}
567
568static void omap_lcdc_resume(void)
569{
570	omap_lcdc_set_update_mode(OMAPFB_AUTO_UPDATE);
571}
572
573static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
574{
575	return;
576}
577
578int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
579{
580	BUG_ON(callback == NULL);
581
582	if (lcdc.dma_callback)
583		return -EBUSY;
584	else {
585		lcdc.dma_callback = callback;
586		lcdc.dma_callback_data = data;
587	}
588	return 0;
589}
590EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
591
592void omap_lcdc_free_dma_callback(void)
593{
594	lcdc.dma_callback = NULL;
595}
596EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
597
598static void lcdc_dma_handler(u16 status, void *data)
599{
600	if (lcdc.dma_callback)
601		lcdc.dma_callback(lcdc.dma_callback_data);
602}
603
604static int alloc_palette_ram(void)
605{
606	lcdc.palette_virt = dma_alloc_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
607					 &lcdc.palette_phys, GFP_KERNEL);
608	if (lcdc.palette_virt == NULL) {
609		dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");
610		return -ENOMEM;
611	}
612	memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
613
614	return 0;
615}
616
617static void free_palette_ram(void)
618{
619	dma_free_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE, lcdc.palette_virt,
620		    lcdc.palette_phys);
621}
622
623static int alloc_fbmem(struct omapfb_mem_region *region)
624{
625	int bpp;
626	int frame_size;
627	struct lcd_panel *panel = lcdc.fbdev->panel;
628
629	bpp = panel->bpp;
630	if (bpp == 12)
631		bpp = 16;
632	frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res);
633	if (region->size > frame_size)
634		frame_size = region->size;
635	lcdc.vram_size = frame_size;
636	lcdc.vram_virt = dma_alloc_wc(lcdc.fbdev->dev, lcdc.vram_size,
637				      &lcdc.vram_phys, GFP_KERNEL);
638	if (lcdc.vram_virt == NULL) {
639		dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");
640		return -ENOMEM;
641	}
642	region->size = frame_size;
643	region->paddr = lcdc.vram_phys;
644	region->vaddr = lcdc.vram_virt;
645	region->alloc = 1;
646
647	memset(lcdc.vram_virt, 0, lcdc.vram_size);
648
649	return 0;
650}
651
652static void free_fbmem(void)
653{
654	dma_free_wc(lcdc.fbdev->dev, lcdc.vram_size, lcdc.vram_virt,
655		    lcdc.vram_phys);
656}
657
658static int setup_fbmem(struct omapfb_mem_desc *req_md)
659{
660	if (!req_md->region_cnt) {
661		dev_err(lcdc.fbdev->dev, "no memory regions defined\n");
662		return -EINVAL;
663	}
664
665	if (req_md->region_cnt > 1) {
666		dev_err(lcdc.fbdev->dev, "only one plane is supported\n");
667		req_md->region_cnt = 1;
668	}
669
670	return alloc_fbmem(&req_md->region[0]);
671}
672
673static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
674			  struct omapfb_mem_desc *req_vram)
675{
676	int r;
677	u32 l;
678	int rate;
679	struct clk *tc_ck;
680
681	lcdc.irq_mask = 0;
682
683	lcdc.fbdev = fbdev;
684	lcdc.ext_mode = ext_mode;
685
686	l = 0;
687	omap_writel(l, OMAP_LCDC_CONTROL);
688
689	/* FIXME:
690	 * According to errata some platforms have a clock rate limitiation
691	 */
692	lcdc.lcd_ck = clk_get(fbdev->dev, "lcd_ck");
693	if (IS_ERR(lcdc.lcd_ck)) {
694		dev_err(fbdev->dev, "unable to access LCD clock\n");
695		r = PTR_ERR(lcdc.lcd_ck);
696		goto fail0;
697	}
698
699	tc_ck = clk_get(fbdev->dev, "tc_ck");
700	if (IS_ERR(tc_ck)) {
701		dev_err(fbdev->dev, "unable to access TC clock\n");
702		r = PTR_ERR(tc_ck);
703		goto fail1;
704	}
705
706	rate = clk_get_rate(tc_ck);
707	clk_put(tc_ck);
708
709	if (machine_is_ams_delta())
710		rate /= 4;
711	r = clk_set_rate(lcdc.lcd_ck, rate);
712	if (r) {
713		dev_err(fbdev->dev, "failed to adjust LCD rate\n");
714		goto fail1;
715	}
716	clk_prepare_enable(lcdc.lcd_ck);
717
718	r = request_irq(fbdev->int_irq, lcdc_irq_handler, 0, MODULE_NAME, fbdev);
719	if (r) {
720		dev_err(fbdev->dev, "unable to get IRQ\n");
721		goto fail2;
722	}
723
724	r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
725	if (r) {
726		dev_err(fbdev->dev, "unable to get LCD DMA\n");
727		goto fail3;
728	}
729
730	omap_set_lcd_dma_single_transfer(ext_mode);
731	omap_set_lcd_dma_ext_controller(ext_mode);
732
733	if (!ext_mode)
734		if ((r = alloc_palette_ram()) < 0)
735			goto fail4;
736
737	if ((r = setup_fbmem(req_vram)) < 0)
738		goto fail5;
739
740	pr_info("omapfb: LCDC initialized\n");
741
742	return 0;
743fail5:
744	if (!ext_mode)
745		free_palette_ram();
746fail4:
747	omap_free_lcd_dma();
748fail3:
749	free_irq(fbdev->int_irq, lcdc.fbdev);
750fail2:
751	clk_disable_unprepare(lcdc.lcd_ck);
752fail1:
753	clk_put(lcdc.lcd_ck);
754fail0:
755	return r;
756}
757
758static void omap_lcdc_cleanup(void)
759{
760	if (!lcdc.ext_mode)
761		free_palette_ram();
762	free_fbmem();
763	omap_free_lcd_dma();
764	free_irq(lcdc.fbdev->int_irq, lcdc.fbdev);
765	clk_disable_unprepare(lcdc.lcd_ck);
766	clk_put(lcdc.lcd_ck);
767}
768
769const struct lcd_ctrl omap1_int_ctrl = {
770	.name			= "internal",
771	.init			= omap_lcdc_init,
772	.cleanup		= omap_lcdc_cleanup,
773	.get_caps		= omap_lcdc_get_caps,
774	.set_update_mode	= omap_lcdc_set_update_mode,
775	.get_update_mode	= omap_lcdc_get_update_mode,
776	.update_window		= NULL,
777	.suspend		= omap_lcdc_suspend,
778	.resume			= omap_lcdc_resume,
779	.setup_plane		= omap_lcdc_setup_plane,
780	.enable_plane		= omap_lcdc_enable_plane,
781	.setcolreg		= omap_lcdc_setcolreg,
782};
~/ Read-only file preview.