Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
  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
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
#ifndef __RADEONFB_H__
#define __RADEONFB_H__

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>


#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>

#include <asm/io.h>

#include <video/radeon.h>

/***************************************************************
 * Most of the definitions here are adapted right from XFree86 *
 ***************************************************************/


/*
 * Chip families. Must fit in the low 16 bits of a long word
 */
enum radeon_family {
	CHIP_FAMILY_UNKNOW,
	CHIP_FAMILY_LEGACY,
	CHIP_FAMILY_RADEON,
	CHIP_FAMILY_RV100,
	CHIP_FAMILY_RS100,    /* U1 (IGP320M) or A3 (IGP320)*/
	CHIP_FAMILY_RV200,
	CHIP_FAMILY_RS200,    /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350), RS250 (IGP 7000) */
	CHIP_FAMILY_R200,
	CHIP_FAMILY_RV250,
	CHIP_FAMILY_RS300,    /* Radeon 9000 IGP */
	CHIP_FAMILY_RV280,
	CHIP_FAMILY_R300,
	CHIP_FAMILY_R350,
	CHIP_FAMILY_RV350,
	CHIP_FAMILY_LAST,
};

/*
 * Chip flags
 */
enum radeon_chip_flags {
	CHIP_FAMILY_MASK	= 0x0000ffffUL,
	CHIP_FLAGS_MASK		= 0xffff0000UL,
	CHIP_IS_MOBILITY	= 0x00010000UL,
	CHIP_IS_IGP		= 0x00020000UL,
	CHIP_HAS_CRTC2		= 0x00040000UL,	
};


/*
 * Monitor types
 */
enum radeon_montype {
	MT_NONE = 0,
	MT_CRT,		/* CRT */
	MT_LCD,		/* LCD */
	MT_DFP,		/* DVI */
	MT_CTV,		/* composite TV */
	MT_STV		/* S-Video out */
};

/*
 * DDC i2c ports
 */
enum ddc_type {
	ddc_none,
	ddc_monid,
	ddc_dvi,
	ddc_vga,
	ddc_crt2,
};

/*
 * Connector types
 */
enum conn_type {
	conn_none,
	conn_proprietary,
	conn_crt,
	conn_DVI_I,
	conn_DVI_D,
};


/*
 * PLL infos
 */
struct pll_info {
	int ppll_max;
	int ppll_min;
	int sclk, mclk;
	int ref_div;
	int ref_clk;
};

/*
 * VRAM infos
 */
struct ram_info {
	int ml;
	int mb;
	int trcd;
	int trp;
	int twr;
	int cl;
	int tr2w;
	int loop_latency;
	int rloop;
};


/*
 * This structure contains the various registers manipulated by this
 * driver for setting or restoring a mode. It's mostly copied from
 * XFree's RADEONSaveRec structure. A few chip settings might still be
 * tweaked without beeing reflected or saved in these registers though
 */
struct radeon_regs {
	/* Common registers */
	u32		ovr_clr;
	u32		ovr_wid_left_right;
	u32		ovr_wid_top_bottom;
	u32		ov0_scale_cntl;
	u32		mpp_tb_config;
	u32		mpp_gp_config;
	u32		subpic_cntl;
	u32		viph_control;
	u32		i2c_cntl_1;
	u32		gen_int_cntl;
	u32		cap0_trig_cntl;
	u32		cap1_trig_cntl;
	u32		bus_cntl;
	u32		surface_cntl;
	u32		bios_5_scratch;

	/* Other registers to save for VT switches or driver load/unload */
	u32		dp_datatype;
	u32		rbbm_soft_reset;
	u32		clock_cntl_index;
	u32		amcgpio_en_reg;
	u32		amcgpio_mask;

	/* Surface/tiling registers */
	u32		surf_lower_bound[8];
	u32		surf_upper_bound[8];
	u32		surf_info[8];

	/* CRTC registers */
	u32		crtc_gen_cntl;
	u32		crtc_ext_cntl;
	u32		dac_cntl;
	u32		crtc_h_total_disp;
	u32		crtc_h_sync_strt_wid;
	u32		crtc_v_total_disp;
	u32		crtc_v_sync_strt_wid;
	u32		crtc_offset;
	u32		crtc_offset_cntl;
	u32		crtc_pitch;
	u32		disp_merge_cntl;
	u32		grph_buffer_cntl;
	u32		crtc_more_cntl;

	/* CRTC2 registers */
	u32		crtc2_gen_cntl;
	u32		dac2_cntl;
	u32		disp_output_cntl;
	u32		disp_hw_debug;
	u32		disp2_merge_cntl;
	u32		grph2_buffer_cntl;
	u32		crtc2_h_total_disp;
	u32		crtc2_h_sync_strt_wid;
	u32		crtc2_v_total_disp;
	u32		crtc2_v_sync_strt_wid;
	u32		crtc2_offset;
	u32		crtc2_offset_cntl;
	u32		crtc2_pitch;

	/* Flat panel regs */
	u32 		fp_crtc_h_total_disp;
	u32		fp_crtc_v_total_disp;
	u32		fp_gen_cntl;
	u32		fp2_gen_cntl;
	u32		fp_h_sync_strt_wid;
	u32		fp2_h_sync_strt_wid;
	u32		fp_horz_stretch;
	u32		fp_panel_cntl;
	u32		fp_v_sync_strt_wid;
	u32		fp2_v_sync_strt_wid;
	u32		fp_vert_stretch;
	u32		lvds_gen_cntl;
	u32		lvds_pll_cntl;
	u32		tmds_crc;
	u32		tmds_transmitter_cntl;

	/* Computed values for PLL */
	u32		dot_clock_freq;
	int		feedback_div;
	int		post_div;	

	/* PLL registers */
	u32		ppll_div_3;
	u32		ppll_ref_div;
	u32		vclk_ecp_cntl;

	/* Computed values for PLL2 */
	u32		dot_clock_freq_2;
	int		feedback_div_2;
	int		post_div_2;

	/* PLL2 registers */
	u32		p2pll_ref_div;
	u32		p2pll_div_0;
	u32		htotal_cntl2;

       	/* Palette */
	int		palette_valid;
	u32		palette[256];
	u32		palette2[256];
};

struct panel_info {
	int xres, yres;
	int valid;
	int clock;
	int hOver_plus, hSync_width, hblank;
	int vOver_plus, vSync_width, vblank;
	int hAct_high, vAct_high, interlaced;
	int pwr_delay;
	int use_bios_dividers;
	int ref_divider;
	int post_divider;
	int fbk_divider;
};

struct radeonfb_info;

#ifdef CONFIG_FB_RADEON_I2C
struct radeon_i2c_chan {
	struct radeonfb_info		*rinfo;
	u32		 		ddc_reg;
	struct i2c_adapter		adapter;
	struct i2c_algo_bit_data	algo;
};
#endif

struct radeonfb_info {
	struct fb_info		*info;

	struct radeon_regs 	state;
	struct radeon_regs	init_state;

	char			name[DEVICE_NAME_SIZE];
	char			ram_type[12];

	unsigned long		mmio_base_phys;
	unsigned long		fb_base_phys;

	unsigned long		mmio_base;
	unsigned long		fb_base;

	unsigned long 		fb_local_base;

	struct pci_dev		*pdev;

	u8			*bios_seg;
	int			fp_bios_start;

	u32			pseudo_palette[17];
	struct { u8 red, green, blue, pad; }
				palette[256];

	int			chipset;
	u8			family;
	u8			rev;
	unsigned long		video_ram;
	unsigned long		mapped_vram;

	int			pitch, bpp, depth;

	int			has_CRTC2;
	int			is_mobility;
	int			is_IGP;
	int			R300_cg_workaround;
	int			reversed_DAC;
	int			reversed_TMDS;
	struct panel_info	panel_info;
	int			mon1_type;
	u8			*mon1_EDID;
	struct fb_videomode	*mon1_modedb;
	int			mon1_dbsize;
	int			mon2_type;
	u8		        *mon2_EDID;

	u32			dp_gui_master_cntl;

	struct pll_info		pll;

	struct ram_info		ram;

	int			mtrr_hdl;

	int			pm_reg;
	u32			save_regs[64];
	int			asleep;
	int			lock_blank;

	/* Lock on register access */
	spinlock_t		reg_lock;

	/* Timer used for delayed LVDS operations */
	struct timer_list	lvds_timer;
	u32			pending_lvds_gen_cntl;
	u32			pending_pixclks_cntl;

#ifdef CONFIG_FB_RADEON_I2C
	struct radeon_i2c_chan 	i2c[4];
#endif
};


#define PRIMARY_MONITOR(rinfo)	(rinfo->mon1_type)


/*
 * Debugging stuffs
 */
#ifdef CONFIG_FB_RADEON_DEBUG
#define DEBUG		1
#else
#define DEBUG		0
#endif

#if DEBUG
#define RTRACE		printk
#else
#define RTRACE		if(0) printk
#endif


/*
 * IO macros
 */

#define INREG8(addr)		readb((rinfo->mmio_base)+addr)
#define OUTREG8(addr,val)	writeb(val, (rinfo->mmio_base)+addr)
#define INREG(addr)		readl((rinfo->mmio_base)+addr)
#define OUTREG(addr,val)	writel(val, (rinfo->mmio_base)+addr)

static inline void R300_cg_workardound(struct radeonfb_info *rinfo)
{
	u32 save, tmp;
	save = INREG(CLOCK_CNTL_INDEX);
	tmp = save & ~(0x3f | PLL_WR_EN);
	OUTREG(CLOCK_CNTL_INDEX, tmp);
	tmp = INREG(CLOCK_CNTL_DATA);
	OUTREG(CLOCK_CNTL_INDEX, save);
}

#define __OUTPLL(addr,val)	\
	do {	\
		OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000003f) | 0x00000080); \
		OUTREG(CLOCK_CNTL_DATA, val); \
} while(0)


static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
{
	u32 data;
	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
	data = (INREG(CLOCK_CNTL_DATA));
	if (rinfo->R300_cg_workaround)
		R300_cg_workardound(rinfo);
	return data;
}

static inline u32 _INPLL(struct radeonfb_info *rinfo, u32 addr)
{
       	unsigned long flags;
	u32 data;

	spin_lock_irqsave(&rinfo->reg_lock, flags);
	data = __INPLL(rinfo, addr);
	spin_unlock_irqrestore(&rinfo->reg_lock, flags);
	return data;
}

#define INPLL(addr)		_INPLL(rinfo, addr)

#define OUTPLL(addr,val)	\
	do {	\
		unsigned long flags;\
		spin_lock_irqsave(&rinfo->reg_lock, flags); \
		__OUTPLL(addr, val); \
		spin_unlock_irqrestore(&rinfo->reg_lock, flags); \
	} while(0)

#define OUTPLLP(addr,val,mask)  					\
	do {								\
		unsigned long flags;                                    \
		unsigned int _tmp;					\
		spin_lock_irqsave(&rinfo->reg_lock, flags); 		\
		_tmp  = __INPLL(rinfo,addr);				\
		_tmp &= (mask);						\
		_tmp |= (val);						\
		__OUTPLL(addr, _tmp);					\
		spin_unlock_irqrestore(&rinfo->reg_lock, flags); 	\
	} while (0)

#define OUTREGP(addr,val,mask)  					\
	do {								\
		unsigned long flags;                                    \
		unsigned int _tmp;					\
		spin_lock_irqsave(&rinfo->reg_lock, flags); 		\
		_tmp = INREG(addr);				       	\
		_tmp &= (mask);						\
		_tmp |= (val);						\
		OUTREG(addr, _tmp);					\
		spin_unlock_irqrestore(&rinfo->reg_lock, flags); 	\
	} while (0)

#define MS_TO_HZ(ms)       ((ms * HZ + 999) / 1000)

#define BIOS_IN8(v)  	(readb(rinfo->bios_seg + (v)))
#define BIOS_IN16(v) 	(readb(rinfo->bios_seg + (v)) | \
			  (readb(rinfo->bios_seg + (v) + 1) << 8))
#define BIOS_IN32(v) 	(readb(rinfo->bios_seg + (v)) | \
			  (readb(rinfo->bios_seg + (v) + 1) << 8) | \
			  (readb(rinfo->bios_seg + (v) + 2) << 16) | \
			  (readb(rinfo->bios_seg + (v) + 3) << 24))

/*
 * Inline utilities
 */

static inline void wait_ms(unsigned long ms)
{
	set_current_state(TASK_UNINTERRUPTIBLE);
	schedule_timeout((ms * HZ + 999) / 1000);
}



static inline int round_div(int num, int den)
{
        return (num + (den / 2)) / den;
}

static inline int var_to_depth(const struct fb_var_screeninfo *var)
{
	if (var->bits_per_pixel != 16)
		return var->bits_per_pixel;
	return (var->green.length == 5) ? 15 : 16;
}

static inline u32 radeon_get_dstbpp(u16 depth)
{
	switch (depth) {
       	case 8:
       		return DST_8BPP;
       	case 15:
       		return DST_15BPP;
       	case 16:
       		return DST_16BPP;
       	case 32:
       		return DST_32BPP;
       	default:
       		return 0;
	}
}

/*
 * 2D Engine helper routines
 */
static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
{
	int i;

	/* initiate flush */
	OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
	        ~RB2D_DC_FLUSH_ALL);

	for (i=0; i < 2000000; i++) {
		if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
			return;
		udelay(1);
	}
	printk(KERN_ERR "radeonfb: Flush Timeout !\n");
}


static inline void _radeon_fifo_wait (struct radeonfb_info *rinfo, int entries)
{
	int i;

	for (i=0; i<2000000; i++) {
		if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
			return;
		udelay(1);
	}
	printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
}


static inline void _radeon_engine_idle (struct radeonfb_info *rinfo)
{
	int i;

	/* ensure FIFO is empty before waiting for idle */
	_radeon_fifo_wait (rinfo, 64);

	for (i=0; i<2000000; i++) {
		if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
			radeon_engine_flush (rinfo);
			return;
		}
		udelay(1);
	}
	printk(KERN_ERR "radeonfb: Idle Timeout !\n");
}

static inline int radeon_accel_disabled(void)
{
	extern int radeonfb_noaccel;
	return radeonfb_noaccel;
}

#define radeon_engine_idle()		_radeon_engine_idle(rinfo)
#define radeon_fifo_wait(entries)	_radeon_fifo_wait(rinfo,entries)


/* I2C Functions */
extern void radeon_create_i2c_busses(struct radeonfb_info *rinfo);
extern void radeon_delete_i2c_busses(struct radeonfb_info *rinfo);
extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid);

/* PM Functions */
extern void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo);
extern void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo);
extern int radeonfb_pci_suspend(struct pci_dev *pdev, u32 state);
extern int radeonfb_pci_resume(struct pci_dev *pdev);

/* Monitor probe functions */
extern void radeon_probe_screens(struct radeonfb_info *rinfo,
				 const char *monitor_layout, int ignore_edid);
extern void radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option);
extern int radeon_match_mode(struct radeonfb_info *rinfo,
			     struct fb_var_screeninfo *dest,
			     const struct fb_var_screeninfo *src);

/* Accel functions */
extern void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region);
extern void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
extern void radeonfb_imageblit(struct fb_info *p, const struct fb_image *image);
extern int radeonfb_sync(struct fb_info *info);
extern void radeonfb_engine_init (struct radeonfb_info *rinfo);
extern void radeonfb_engine_reset(struct radeonfb_info *rinfo);

/* Other functions */
extern int radeonfb_blank(int blank, struct fb_info *info);
extern int radeonfb_set_par(struct fb_info *info);

#endif /* __RADEONFB_H__ */