summaryrefslogtreecommitdiff
path: root/drivers/media/video/tiler/dmm_ll_drv.c
blob: fa794e7a8bd856c2821a762c322efd80d34e5e30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*
 * dmm_ll_drv.c
 *
 * DMM driver support functions for TI OMAP processors.
 *
 * Copyright (C) 2009-2010 Texas Instruments, Inc.
 *
 * This package is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <linux/module.h>
#include <linux/io.h>
#include "dmm_def.h"
#include "dmm_2d_alloc.h"
#include "dmm_prv.h"
#include "dmm_reg.h"
MODULE_LICENSE("GPL v2");

struct pat_area {
	int x0:8;
	int y0:8;
	int x1:8;
	int y1:8;
};

struct pat_ctrl {
	int start:4;
	int direction:4;
	int lut_id:8;
	int sync:12;
	int initiator:4;
};

struct pat_desc {
	struct pat_desc *next;
	struct pat_area area;
	struct pat_ctrl ctrl;
	unsigned long data;
};

static void pat_ctrl_set(struct pat_ctrl *ctrl, char id)
{
	void __iomem *reg = NULL;
	unsigned long reg_val = 0x0;
	unsigned long new_val = 0x0;
	unsigned long bit_field = 0x0;
	unsigned long field_pos = 0x0;

	/* set PAT_CTRL register */
	/* TODO: casting as unsigned long */

	reg = (void __iomem *)(
			(unsigned long)dmm_base |
			(unsigned long)PAT_CTRL__0);
	reg_val = __raw_readl(reg);

	bit_field = BITFIELD(31, 28);
	field_pos = 28;
	new_val = (reg_val & (~(bit_field))) |
			((((unsigned long)ctrl->initiator) <<
							field_pos) & bit_field);
	__raw_writel(new_val, reg);

	reg_val = __raw_readl(reg);
	bit_field = BITFIELD(16, 16);
	field_pos = 16;
	new_val = (reg_val & (~(bit_field))) |
		((((unsigned long)ctrl->sync) << field_pos) & bit_field);
	__raw_writel(new_val, reg);

	reg_val = __raw_readl(reg);
	bit_field = BITFIELD(9, 8);
	field_pos = 8;
	new_val = (reg_val & (~(bit_field))) |
		((((unsigned long)ctrl->lut_id) << field_pos) & bit_field);
	__raw_writel(new_val, reg);

	reg_val = __raw_readl(reg);
	bit_field = BITFIELD(6, 4);
	field_pos = 4;
	new_val = (reg_val & (~(bit_field))) |
		((((unsigned long)ctrl->direction) << field_pos) & bit_field);
	__raw_writel(new_val, reg);

	reg_val = __raw_readl(reg);
	bit_field = BITFIELD(0, 0);
	field_pos = 0;
	new_val = (reg_val & (~(bit_field))) |
		((((unsigned long)ctrl->start) << field_pos) & bit_field);
	__raw_writel(new_val, reg);

	dsb();
}

/* ========================================================================== */
/**
 *  dmm_pat_area_refill()
 *
 * @brief  Initiate a PAT area refill (or terminate an ongoing - consult
 * documentation).
 *
 * @param patDesc - PATDescrT* - [in] Pointer to a PAT area descriptor that's
 * needed to extract settings from for the refill procedure initation.
 *
 * @param dmmPatAreaSel - signed long - [in] Selects which PAT area will be
 *  configured for a area refill procedure.
 *
 * @param refillType - dmmPATRefillMethodT - [in] Selects the refill method -
 * manual or automatic.
 *
 * @param forcedRefill - int - [in] Selects if forced refill should be used
 * effectively terminating any ongoing area refills related to the selected area
 *
 * @return errorCodeT
 *
 * @pre If forced mode is not used, no refills should be ongoing for the
 *  selected area - error status returned if this occurs.
 *
 * @post If non valid data is provided for patDesc and the refill engines fail
 * to perform the request, an error status is returned.
 *
 * @see errorCodeT,  PATDescrT, dmmPATRefillMethodT, int for further detail
 */
/* ========================================================================== */
enum errorCodeT dmm_pat_area_refill(struct PATDescrT *patDesc,
				    signed long dmmPatAreaSel,
				    enum dmmPATRefillMethodT refillType,
				    int forcedRefill)
{
	enum errorCodeT eCode = DMM_NO_ERROR;
	void __iomem *reg = NULL;
	unsigned long regval = 0xffffffff;
	unsigned long writeval = 0xffffffff;
	unsigned long f = 0xffffffff; /* field */
	unsigned long fp = 0xffffffff; /* field position */
	struct pat_desc pat_desc = {0};

	struct dmmPATStatusT areaStat;

	if (forcedRefill == 0) {
		eCode = dmm_pat_refill_area_status_get(
				dmmPatAreaSel, &areaStat);

		if (eCode == DMM_NO_ERROR) {
			if (areaStat.ready == 0 || areaStat.engineRunning) {
				printk(KERN_ALERT "hw not ready\n");
				eCode = DMM_HRDW_NOT_READY;
			}
		}
	}

	if (dmmPatAreaSel < 0 || dmmPatAreaSel > 3) {
		eCode = DMM_WRONG_PARAM;
	} else if (eCode == DMM_NO_ERROR) {
		if (refillType == AUTO) {
			reg = (void __iomem *)
				((unsigned long)dmm_base |
				(0x500ul + 0x0));
			regval = __raw_readl(reg);
			f  = BITFIELD(31, 4);
			fp = 4;
			writeval = (regval & (~(f))) |
				   ((((unsigned long)patDesc) << fp) & f);
			__raw_writel(writeval, reg);
		} else if (refillType == MANUAL) {
			/* check that the PAT_STATUS register has not reported
			 * an error.
			 */
			reg = (void __iomem *)(
					(unsigned long)dmm_base |
						(unsigned long)PAT_STATUS__0);
			regval = __raw_readl(reg);
			if ((regval & 0xFC00) != 0) {
				while (1) {
					printk(KERN_ERR "%s()::%d: ERROR\n",
						__func__, __LINE__);
				}
			}

			/* set DESC register to NULL */
			reg = (void __iomem *)
				((unsigned long)dmm_base |
				(0x500ul + 0x0));
			regval = __raw_readl(reg);
			f  = BITFIELD(31, 4);
			fp = 4;
			writeval = (regval & (~(f))) |
				   ((((unsigned long)NULL) << fp) & f);
			__raw_writel(writeval, reg);
			reg = (void __iomem *)
				((unsigned long)dmm_base |
				(0x500ul + 0x4));
			regval = __raw_readl(reg);

			/* set area to be refilled */
			f  = BITFIELD(30, 24);
			fp = 24;
			writeval = (regval & (~(f))) |
				   ((((char)patDesc->area.y1) << fp) & f);
			__raw_writel(writeval, reg);

			regval = __raw_readl(reg);
			f  = BITFIELD(23, 16);
			fp = 16;
			writeval = (regval & (~(f))) |
				   ((((char)patDesc->area.x1) << fp) & f);
			__raw_writel(writeval, reg);

			regval = __raw_readl(reg);
			f  = BITFIELD(14, 8);
			fp = 8;
			writeval = (regval & (~(f))) |
				   ((((char)patDesc->area.y0) << fp) & f);
			__raw_writel(writeval, reg);

			regval = __raw_readl(reg);
			f  = BITFIELD(7, 0);
			fp = 0;
			writeval = (regval & (~(f))) |
				   ((((char)patDesc->area.x0) << fp) & f);
			__raw_writel(writeval, reg);

			printk(KERN_NOTICE
				"\nx0=(%d),y0=(%d),x1=(%d),y1=(%d)\n",
				(char)patDesc->area.x0,
				(char)patDesc->area.y0,
				(char)patDesc->area.x1,
				(char)patDesc->area.y1);
			dsb();

			/* First, clear the PAT_IRQSTATUS register */
			reg = (void __iomem *)(
					(unsigned long)dmm_base |
					(unsigned long)PAT_IRQSTATUS);
			__raw_writel(0xFFFFFFFF, reg);
			dsb();

			reg = (void __iomem *)(
					(unsigned long)dmm_base |
					(unsigned long)PAT_IRQSTATUS_RAW);
			regval = 0xFFFFFFFF;
			while (regval != 0x0) {
				regval = __raw_readl(reg);
				regdump("PAT_IRQSTATUS_RAW", regval);
			}

			/* fill data register */
			reg = (void __iomem *)
			((unsigned long)dmm_base | (0x500ul + 0xc));
			regval = __raw_readl(reg);

			/* Apply 4 bit lft shft to counter the 4 bit rt shft */
			f  = BITFIELD(31, 4);
			fp = 4;
			writeval = (regval & (~(f))) | ((((unsigned long)
					(patDesc->data >> 4)) << fp) & f);
			__raw_writel(writeval, reg);
			dsb();

			/* read back PAT_DATA__0 to see if it got set */
			regval = 0x0;
			while (regval != patDesc->data) {
				regval = __raw_readl(reg);
				regdump("PAT_DATA__0", regval);
			}

			pat_desc.ctrl.start = 1;
			pat_desc.ctrl.direction = 0;
			pat_desc.ctrl.lut_id = 0;
			pat_desc.ctrl.sync = 0;
			pat_desc.ctrl.initiator = 0;
			pat_ctrl_set(&pat_desc.ctrl, 0);

			/* Now, check if PAT_IRQSTATUS_RAW has been set after
			the PAT has been refilled */
			reg = (void __iomem *)(
					(unsigned long)dmm_base |
					(unsigned long)PAT_IRQSTATUS_RAW);
			regval = 0x0;
			while ((regval & 0x3) != 0x3) {
				regval = __raw_readl(reg);
				regdump("PAT_IRQSTATUS_RAW", regval);
			}
		} else {
			eCode = DMM_WRONG_PARAM;
		}
		if (eCode == DMM_NO_ERROR) {
			eCode = dmm_pat_refill_area_status_get(dmmPatAreaSel,
							       &areaStat);

			if (eCode == DMM_NO_ERROR) {
				if (areaStat.validDescriptor == 0) {
					eCode = DMM_HRDW_CONFIG_FAILED;
					printk(KERN_ALERT "hw config fail\n");
				}
			}

			while (!areaStat.done && !areaStat.ready &&
					eCode == DMM_NO_ERROR) {
				eCode = dmm_pat_refill_area_status_get(
						dmmPatAreaSel,
						&areaStat);
			}

			if (areaStat.error) {
				eCode = DMM_HRDW_CONFIG_FAILED;
				printk(KERN_ALERT "hw config fail\n");
			}
		}
	}
	return eCode;
}

/* ========================================================================== */
/**
 *  dmm_pat_refill_area_status_get()
 *
 * @brief  Gets the status for the selected PAT area.
 *
 * @param dmmPatAreaSel - signed long - [in] Selects which PAT area status will
 *  be queried.
 *
 * @param areaStatus - dmmPATStatusT* - [out] Structure containing the PAT area
 * status that will be filled by dmmPatRefillAreaStatusGet().
 *
 * @return errorCodeT
 *
 * @pre There is no pre conditions.
 *
 * @post If the query fails the provided areaStatus structure is not updated
 *  at all!
 *
 * @see errorCodeT, dmmPATStatusT for further detail.
 */
/* ========================================================================== */
enum errorCodeT dmm_pat_refill_area_status_get(signed long dmmPatAreaStatSel,
		struct dmmPATStatusT *areaStatus)
{
	enum errorCodeT eCode = DMM_NO_ERROR;

	unsigned long stat = 0xffffffff;
	void __iomem *statreg = (void __iomem *)
				((unsigned long)dmm_base | 0x4c0ul);

	if (dmmPatAreaStatSel >= 0 && dmmPatAreaStatSel <= 3) {
		stat = __raw_readl(statreg);

		areaStatus->remainingLinesCounter = stat & BITFIELD(24, 16);
		areaStatus->error = (enum dmmPATStatusErrT)
				    (stat & BITFIELD(15, 10));
		areaStatus->linkedReconfig = stat & BITFIELD(4, 4);
		areaStatus->done = stat & BITFIELD(3, 3);
		areaStatus->engineRunning = stat & BITFIELD(2, 2);
		areaStatus->validDescriptor = stat & BITFIELD(1, 1);
		areaStatus->ready = stat & BITFIELD(0, 0);

	} else {
		eCode = DMM_WRONG_PARAM;
		printk(KERN_ALERT "wrong parameter\n");
	}

	return eCode;
}