brintos

brintos / linux-shallow public Read only

0
0
Text · 10.5 KiB · f858176 Raw
445 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/arch/arm/mach-omap1/lcd_dma.c4 *5 * Extracted from arch/arm/plat-omap/dma.c6 * Copyright (C) 2003 - 2008 Nokia Corporation7 * Author: Juha Yrjölä <juha.yrjola@nokia.com>8 * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>9 * Graphics DMA and LCD DMA graphics tranformations10 * by Imre Deak <imre.deak@nokia.com>11 * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.12 * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>13 * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.14 *15 * Copyright (C) 2009 Texas Instruments16 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>17 *18 * Support functions for the OMAP internal DMA channels.19 */20 21#include <linux/module.h>22#include <linux/spinlock.h>23#include <linux/interrupt.h>24#include <linux/io.h>25 26#include <linux/omap-dma.h>27 28#include <linux/soc/ti/omap1-soc.h>29#include <linux/soc/ti/omap1-io.h>30 31#include "lcdc.h"32#include "lcd_dma.h"33 34int omap_lcd_dma_running(void)35{36	/*37	 * On OMAP1510, internal LCD controller will start the transfer38	 * when it gets enabled, so assume DMA running if LCD enabled.39	 */40	if (cpu_is_omap15xx())41		if (omap_readw(OMAP_LCDC_CONTROL) & OMAP_LCDC_CTRL_LCD_EN)42			return 1;43 44	/* Check if LCD DMA is running */45	if (cpu_is_omap16xx())46		if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)47			return 1;48 49	return 0;50}51 52static struct lcd_dma_info {53	spinlock_t lock;54	int reserved;55	void (*callback)(u16 status, void *data);56	void *cb_data;57 58	int active;59	unsigned long addr;60	int rotate, data_type, xres, yres;61	int vxres;62	int mirror;63	int xscale, yscale;64	int ext_ctrl;65	int src_port;66	int single_transfer;67} lcd_dma;68 69void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,70			 int data_type)71{72	lcd_dma.addr = addr;73	lcd_dma.data_type = data_type;74	lcd_dma.xres = fb_xres;75	lcd_dma.yres = fb_yres;76}77EXPORT_SYMBOL(omap_set_lcd_dma_b1);78 79void omap_set_lcd_dma_ext_controller(int external)80{81	lcd_dma.ext_ctrl = external;82}83EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller);84 85void omap_set_lcd_dma_single_transfer(int single)86{87	lcd_dma.single_transfer = single;88}89EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);90 91void omap_set_lcd_dma_b1_rotation(int rotate)92{93	if (cpu_is_omap15xx()) {94		printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n");95		BUG();96		return;97	}98	lcd_dma.rotate = rotate;99}100EXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation);101 102void omap_set_lcd_dma_b1_mirror(int mirror)103{104	if (cpu_is_omap15xx()) {105		printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n");106		BUG();107	}108	lcd_dma.mirror = mirror;109}110EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror);111 112void omap_set_lcd_dma_b1_vxres(unsigned long vxres)113{114	if (cpu_is_omap15xx()) {115		pr_err("DMA virtual resolution is not supported in 1510 mode\n");116		BUG();117	}118	lcd_dma.vxres = vxres;119}120EXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres);121 122void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale)123{124	if (cpu_is_omap15xx()) {125		printk(KERN_ERR "DMA scale is not supported in 1510 mode\n");126		BUG();127	}128	lcd_dma.xscale = xscale;129	lcd_dma.yscale = yscale;130}131EXPORT_SYMBOL(omap_set_lcd_dma_b1_scale);132 133static void set_b1_regs(void)134{135	unsigned long top, bottom;136	int es;137	u16 w;138	unsigned long en, fn;139	long ei, fi;140	unsigned long vxres;141	unsigned int xscale, yscale;142 143	switch (lcd_dma.data_type) {144	case OMAP_DMA_DATA_TYPE_S8:145		es = 1;146		break;147	case OMAP_DMA_DATA_TYPE_S16:148		es = 2;149		break;150	case OMAP_DMA_DATA_TYPE_S32:151		es = 4;152		break;153	default:154		BUG();155		return;156	}157 158	vxres = lcd_dma.vxres ? lcd_dma.vxres : lcd_dma.xres;159	xscale = lcd_dma.xscale ? lcd_dma.xscale : 1;160	yscale = lcd_dma.yscale ? lcd_dma.yscale : 1;161	BUG_ON(vxres < lcd_dma.xres);162 163#define PIXADDR(x, y) (lcd_dma.addr +					\164		((y) * vxres * yscale + (x) * xscale) * es)165#define PIXSTEP(sx, sy, dx, dy) (PIXADDR(dx, dy) - PIXADDR(sx, sy) - es + 1)166 167	switch (lcd_dma.rotate) {168	case 0:169		if (!lcd_dma.mirror) {170			top = PIXADDR(0, 0);171			bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);172			/* 1510 DMA requires the bottom address to be 2 more173			 * than the actual last memory access location. */174			if (cpu_is_omap15xx() &&175				lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32)176					bottom += 2;177			ei = PIXSTEP(0, 0, 1, 0);178			fi = PIXSTEP(lcd_dma.xres - 1, 0, 0, 1);179		} else {180			top = PIXADDR(lcd_dma.xres - 1, 0);181			bottom = PIXADDR(0, lcd_dma.yres - 1);182			ei = PIXSTEP(1, 0, 0, 0);183			fi = PIXSTEP(0, 0, lcd_dma.xres - 1, 1);184		}185		en = lcd_dma.xres;186		fn = lcd_dma.yres;187		break;188	case 90:189		if (!lcd_dma.mirror) {190			top = PIXADDR(0, lcd_dma.yres - 1);191			bottom = PIXADDR(lcd_dma.xres - 1, 0);192			ei = PIXSTEP(0, 1, 0, 0);193			fi = PIXSTEP(0, 0, 1, lcd_dma.yres - 1);194		} else {195			top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);196			bottom = PIXADDR(0, 0);197			ei = PIXSTEP(0, 1, 0, 0);198			fi = PIXSTEP(1, 0, 0, lcd_dma.yres - 1);199		}200		en = lcd_dma.yres;201		fn = lcd_dma.xres;202		break;203	case 180:204		if (!lcd_dma.mirror) {205			top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);206			bottom = PIXADDR(0, 0);207			ei = PIXSTEP(1, 0, 0, 0);208			fi = PIXSTEP(0, 1, lcd_dma.xres - 1, 0);209		} else {210			top = PIXADDR(0, lcd_dma.yres - 1);211			bottom = PIXADDR(lcd_dma.xres - 1, 0);212			ei = PIXSTEP(0, 0, 1, 0);213			fi = PIXSTEP(lcd_dma.xres - 1, 1, 0, 0);214		}215		en = lcd_dma.xres;216		fn = lcd_dma.yres;217		break;218	case 270:219		if (!lcd_dma.mirror) {220			top = PIXADDR(lcd_dma.xres - 1, 0);221			bottom = PIXADDR(0, lcd_dma.yres - 1);222			ei = PIXSTEP(0, 0, 0, 1);223			fi = PIXSTEP(1, lcd_dma.yres - 1, 0, 0);224		} else {225			top = PIXADDR(0, 0);226			bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);227			ei = PIXSTEP(0, 0, 0, 1);228			fi = PIXSTEP(0, lcd_dma.yres - 1, 1, 0);229		}230		en = lcd_dma.yres;231		fn = lcd_dma.xres;232		break;233	default:234		BUG();235		return;	/* Suppress warning about uninitialized vars */236	}237 238	if (cpu_is_omap15xx()) {239		omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);240		omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);241		omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);242		omap_writew(bottom, OMAP1510_DMA_LCD_BOT_F1_L);243 244		return;245	}246 247	/* 1610 regs */248	omap_writew(top >> 16, OMAP1610_DMA_LCD_TOP_B1_U);249	omap_writew(top, OMAP1610_DMA_LCD_TOP_B1_L);250	omap_writew(bottom >> 16, OMAP1610_DMA_LCD_BOT_B1_U);251	omap_writew(bottom, OMAP1610_DMA_LCD_BOT_B1_L);252 253	omap_writew(en, OMAP1610_DMA_LCD_SRC_EN_B1);254	omap_writew(fn, OMAP1610_DMA_LCD_SRC_FN_B1);255 256	w = omap_readw(OMAP1610_DMA_LCD_CSDP);257	w &= ~0x03;258	w |= lcd_dma.data_type;259	omap_writew(w, OMAP1610_DMA_LCD_CSDP);260 261	w = omap_readw(OMAP1610_DMA_LCD_CTRL);262	/* Always set the source port as SDRAM for now*/263	w &= ~(0x03 << 6);264	if (lcd_dma.callback != NULL)265		w |= 1 << 1;		/* Block interrupt enable */266	else267		w &= ~(1 << 1);268	omap_writew(w, OMAP1610_DMA_LCD_CTRL);269 270	if (!(lcd_dma.rotate || lcd_dma.mirror ||271	      lcd_dma.vxres || lcd_dma.xscale || lcd_dma.yscale))272		return;273 274	w = omap_readw(OMAP1610_DMA_LCD_CCR);275	/* Set the double-indexed addressing mode */276	w |= (0x03 << 12);277	omap_writew(w, OMAP1610_DMA_LCD_CCR);278 279	omap_writew(ei, OMAP1610_DMA_LCD_SRC_EI_B1);280	omap_writew(fi >> 16, OMAP1610_DMA_LCD_SRC_FI_B1_U);281	omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L);282}283 284static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id)285{286	u16 w;287 288	w = omap_readw(OMAP1610_DMA_LCD_CTRL);289	if (unlikely(!(w & (1 << 3)))) {290		printk(KERN_WARNING "Spurious LCD DMA IRQ\n");291		return IRQ_NONE;292	}293	/* Ack the IRQ */294	w |= (1 << 3);295	omap_writew(w, OMAP1610_DMA_LCD_CTRL);296	lcd_dma.active = 0;297	if (lcd_dma.callback != NULL)298		lcd_dma.callback(w, lcd_dma.cb_data);299 300	return IRQ_HANDLED;301}302 303int omap_request_lcd_dma(void (*callback)(u16 status, void *data),304			 void *data)305{306	spin_lock_irq(&lcd_dma.lock);307	if (lcd_dma.reserved) {308		spin_unlock_irq(&lcd_dma.lock);309		printk(KERN_ERR "LCD DMA channel already reserved\n");310		BUG();311		return -EBUSY;312	}313	lcd_dma.reserved = 1;314	spin_unlock_irq(&lcd_dma.lock);315	lcd_dma.callback = callback;316	lcd_dma.cb_data = data;317	lcd_dma.active = 0;318	lcd_dma.single_transfer = 0;319	lcd_dma.rotate = 0;320	lcd_dma.vxres = 0;321	lcd_dma.mirror = 0;322	lcd_dma.xscale = 0;323	lcd_dma.yscale = 0;324	lcd_dma.ext_ctrl = 0;325	lcd_dma.src_port = 0;326 327	return 0;328}329EXPORT_SYMBOL(omap_request_lcd_dma);330 331void omap_free_lcd_dma(void)332{333	spin_lock(&lcd_dma.lock);334	if (!lcd_dma.reserved) {335		spin_unlock(&lcd_dma.lock);336		printk(KERN_ERR "LCD DMA is not reserved\n");337		BUG();338		return;339	}340	if (!cpu_is_omap15xx())341		omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1,342			    OMAP1610_DMA_LCD_CCR);343	lcd_dma.reserved = 0;344	spin_unlock(&lcd_dma.lock);345}346EXPORT_SYMBOL(omap_free_lcd_dma);347 348void omap_enable_lcd_dma(void)349{350	u16 w;351 352	/*353	 * Set the Enable bit only if an external controller is354	 * connected. Otherwise the OMAP internal controller will355	 * start the transfer when it gets enabled.356	 */357	if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)358		return;359 360	w = omap_readw(OMAP1610_DMA_LCD_CTRL);361	w |= 1 << 8;362	omap_writew(w, OMAP1610_DMA_LCD_CTRL);363 364	lcd_dma.active = 1;365 366	w = omap_readw(OMAP1610_DMA_LCD_CCR);367	w |= 1 << 7;368	omap_writew(w, OMAP1610_DMA_LCD_CCR);369}370EXPORT_SYMBOL(omap_enable_lcd_dma);371 372void omap_setup_lcd_dma(void)373{374	BUG_ON(lcd_dma.active);375	if (!cpu_is_omap15xx()) {376		/* Set some reasonable defaults */377		omap_writew(0x5440, OMAP1610_DMA_LCD_CCR);378		omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP);379		omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL);380	}381	set_b1_regs();382	if (!cpu_is_omap15xx()) {383		u16 w;384 385		w = omap_readw(OMAP1610_DMA_LCD_CCR);386		/*387		 * If DMA was already active set the end_prog bit to have388		 * the programmed register set loaded into the active389		 * register set.390		 */391		w |= 1 << 11;		/* End_prog */392		if (!lcd_dma.single_transfer)393			w |= (3 << 8);	/* Auto_init, repeat */394		omap_writew(w, OMAP1610_DMA_LCD_CCR);395	}396}397EXPORT_SYMBOL(omap_setup_lcd_dma);398 399void omap_stop_lcd_dma(void)400{401	u16 w;402 403	lcd_dma.active = 0;404	if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)405		return;406 407	w = omap_readw(OMAP1610_DMA_LCD_CCR);408	w &= ~(1 << 7);409	omap_writew(w, OMAP1610_DMA_LCD_CCR);410 411	w = omap_readw(OMAP1610_DMA_LCD_CTRL);412	w &= ~(1 << 8);413	omap_writew(w, OMAP1610_DMA_LCD_CTRL);414}415EXPORT_SYMBOL(omap_stop_lcd_dma);416 417static int __init omap_init_lcd_dma(void)418{419	int r;420 421	if (!cpu_class_is_omap1())422		return -ENODEV;423 424	if (cpu_is_omap16xx()) {425		u16 w;426 427		/* this would prevent OMAP sleep */428		w = omap_readw(OMAP1610_DMA_LCD_CTRL);429		w &= ~(1 << 8);430		omap_writew(w, OMAP1610_DMA_LCD_CTRL);431	}432 433	spin_lock_init(&lcd_dma.lock);434 435	r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,436			"LCD DMA", NULL);437	if (r != 0)438		pr_err("unable to request IRQ for LCD DMA (error %d)\n", r);439 440	return r;441}442 443arch_initcall(omap_init_lcd_dma);444 445