Subversion Repositories Kolibri OS

Rev

Rev 883 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
883 serge 1
#define RADEON_SCRATCH_REG0     0x15e0
2
#define RADEON_SCRATCH_REG1		0x15e4
3
#define RADEON_SCRATCH_REG2		0x15e8
4
#define RADEON_SCRATCH_REG3		0x15ec
5
#define RADEON_SCRATCH_REG4		0x15f0
6
#define RADEON_SCRATCH_REG5		0x15f4
7
#define RADEON_SCRATCH_UMSK		0x0770
8
#define RADEON_SCRATCH_ADDR		0x0774
9
 
10
#   define RS400_BUS_MASTER_DIS      (1 << 14)
11
//#   define RADEON_BUS_MASTER_DIS     (1 <<  6)
12
 
13
#define RADEON_ISYNC_CNTL       0x1724
14
#	define RADEON_ISYNC_ANY2D_IDLE3D	(1 << 0)
15
#	define RADEON_ISYNC_ANY3D_IDLE2D	(1 << 1)
16
#	define RADEON_ISYNC_TRIG2D_IDLE3D	(1 << 2)
17
#	define RADEON_ISYNC_TRIG3D_IDLE2D	(1 << 3)
18
#	define RADEON_ISYNC_WAIT_IDLEGUI	(1 << 4)
19
#	define RADEON_ISYNC_CPSCRATCH_IDLEGUI	(1 << 5)
20
 
21
 
22
#define RADEON_IDLE_RETRY      16 /* Fall out of idle loops after this count */
23
#define RADEON_TIMEOUT    2000000 /* Fall out of wait loops after this count */
24
 
25
 
26
void RADEONPllErrataAfterIndex()
27
{
28
    if (!(rhd.ChipErrata & CHIP_ERRATA_PLL_DUMMYREADS))
29
       return;
30
 
31
    /* This workaround is necessary on rv200 and RS200 or PLL
32
     * reads may return garbage (among others...)
33
     */
34
    (void)INREG(RADEON_CLOCK_CNTL_DATA);
35
    (void)INREG(RADEON_CRTC_GEN_CNTL);
36
}
37
 
38
 
39
void RADEONPllErrataAfterData()
40
{
41
 
42
    /* This function is required to workaround a hardware bug in some (all?)
43
     * revisions of the R300.  This workaround should be called after every
44
     * CLOCK_CNTL_INDEX register access.  If not, register reads afterward
45
     * may not be correct.
46
     */
47
    if (rhd.ChipFamily <= CHIP_FAMILY_RV380)
48
    {
49
        u32_t save, tmp;
50
 
51
	save = INREG(RADEON_CLOCK_CNTL_INDEX);
52
	tmp = save & ~(0x3f | RADEON_PLL_WR_EN);
53
	OUTREG(RADEON_CLOCK_CNTL_INDEX, tmp);
54
	tmp = INREG(RADEON_CLOCK_CNTL_DATA);
55
	OUTREG(RADEON_CLOCK_CNTL_INDEX, save);
56
    }
57
}
58
 
59
 
60
/* Read PLL register */
61
u32_t RADEONINPLL(int addr)
62
{
63
    u32_t       data;
64
 
65
    OUTREG8(RADEON_CLOCK_CNTL_INDEX, addr & 0x3f);
66
    RADEONPllErrataAfterIndex();
67
    data = INREG(RADEON_CLOCK_CNTL_DATA);
68
    RADEONPllErrataAfterData();
69
 
70
    return data;
71
};
72
 
73
/* Write PLL information */
74
void RADEONOUTPLL(int addr, u32_t data)
75
{
76
    OUTREG8(RADEON_CLOCK_CNTL_INDEX, (((addr) & 0x3f) |
77
				      RADEON_PLL_WR_EN));
78
    RADEONPllErrataAfterIndex();
79
    OUTREG(RADEON_CLOCK_CNTL_DATA, data);
80
    RADEONPllErrataAfterData();
81
}
82
 
83
void RADEONEngineFlush(RHDPtr info)
84
{
85
     int i;
86
 
87
     if (info->ChipFamily <= CHIP_FAMILY_RV280)
88
     {
89
        MASKREG(RADEON_RB3D_DSTCACHE_CTLSTAT,RADEON_RB3D_DC_FLUSH_ALL,
90
                                             ~RADEON_RB3D_DC_FLUSH_ALL);
91
        for (i = 0; i < RADEON_TIMEOUT; i++) {
92
           if (!(INREG(RADEON_RB3D_DSTCACHE_CTLSTAT) & RADEON_RB3D_DC_BUSY))
93
            break;
94
        }
95
        if (i == RADEON_TIMEOUT) {
96
           dbgprintf("DC flush timeout: %x\n",
97
                     (u32_t)INREG(RADEON_RB3D_DSTCACHE_CTLSTAT));
98
        }
99
     }
100
     else
101
     {
102
//        MASKREG(R300_DSTCACHE_CTLSTAT,R300_RB2D_DC_FLUSH_ALL,
103
//                                      ~R300_RB2D_DC_FLUSH_ALL);
104
//        for (i = 0; i < RADEON_TIMEOUT; i++) {
105
//            if (!(INREG(R300_DSTCACHE_CTLSTAT) & R300_RB2D_DC_BUSY))
106
//            break;
107
//        }
108
//        if (i == RADEON_TIMEOUT) {
109
//           dbgprintf("DC flush timeout: %x\n",
110
//                     (u32_t)INREG(R300_DSTCACHE_CTLSTAT));
111
//        }
112
     }
113
}
114
 
115
static Bool R5xxFIFOWaitLocal(u32_t required)             //R100-R500
116
{
117
     int i;
118
 
119
     for (i = 0; i < RADEON_TIMEOUT; i++)
120
        if (required <= (INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK))
121
           return TRUE;
122
 
123
     dbgprintf("%s: Timeout 0x%08X.\n", __func__, (u32_t) INREG(RADEON_RBBM_STATUS));
124
     return FALSE;
125
}
126
 
127
static int radeon_do_wait_for_idle()
128
{
129
	int i, ret;
130
 
131
    ret = R5xxFIFOWaitLocal(64);
132
	if (ret)
133
		return ret;
134
 
135
    for (i = 0; i < RADEON_TIMEOUT; i++)
136
    {
137
        if (!(INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE)) {
138
            RADEONEngineFlush(&rhd);
139
			return 0;
140
		}
141
        usleep(1);
142
	}
143
    dbgprintf("wait idle failed status : 0x%08X 0x%08X\n",
144
               INREG(RADEON_RBBM_STATUS),
145
               INREG(R300_VAP_CNTL_STATUS));
146
 
147
    return 1;
148
}
149
 
150
 
151
static void init_pipes(RHDPtr info)
152
{
153
     u32_t gb_tile_config = 0;
154
 
155
     if ( (info->ChipFamily == CHIP_FAMILY_RV410) ||
156
          (info->ChipFamily == CHIP_FAMILY_R420)  ||
157
          (info->ChipFamily == CHIP_FAMILY_RS600) ||
158
          (info->ChipFamily == CHIP_FAMILY_RS690) ||
159
          (info->ChipFamily == CHIP_FAMILY_RS740) ||
160
          (info->ChipFamily == CHIP_FAMILY_RS400) ||
161
          (info->ChipFamily == CHIP_FAMILY_RS480) || IS_R500_3D)
162
     {
163
         u32_t gb_pipe_sel = INREG(R400_GB_PIPE_SELECT);
164
 
165
         info->num_gb_pipes = ((gb_pipe_sel >> 12) & 0x3) + 1;
166
         if (IS_R500_3D)
167
            OUTPLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4));
168
     }
169
     else
170
     {
171
        if ((info->ChipFamily == CHIP_FAMILY_R300) ||
172
            (info->ChipFamily == CHIP_FAMILY_R350))
173
        {
174
         /* R3xx chips */
175
            info->num_gb_pipes = 2;
176
        }
177
        else {
178
         /* RV3xx chips */
179
           info->num_gb_pipes = 1;
180
        }
181
     }
182
 
183
     if (IS_R300_3D || IS_R500_3D)
184
     {
185
 
186
        dbgprintf("num quad-pipes is %d\n", info->num_gb_pipes);
187
 
188
        switch(info->num_gb_pipes) {
189
           case 2: gb_tile_config |= R300_PIPE_COUNT_R300; break;
190
           case 3: gb_tile_config |= R300_PIPE_COUNT_R420_3P; break;
191
           case 4: gb_tile_config |= R300_PIPE_COUNT_R420; break;
192
           default:
193
           case 1: gb_tile_config |= R300_PIPE_COUNT_RV350; break;
194
        }
195
 
196
        OUTREG(R300_GB_TILE_CONFIG, gb_tile_config);
197
        OUTREG(RADEON_WAIT_UNTIL, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN);
198
        OUTREG(R300_DST_PIPE_CONFIG, INREG(R300_DST_PIPE_CONFIG) | R300_PIPE_AUTO_CONFIG);
199
        OUTREG(R300_RB2D_DSTCACHE_MODE, (INREG(R300_RB2D_DSTCACHE_MODE) |
200
                                        R300_DC_AUTOFLUSH_ENABLE |
201
                                        R300_DC_DC_DISABLE_IGNORE_PE));
202
    }
203
    else
204
       OUTREG(RADEON_RB3D_CNTL, 0);
205
};
206
 
207
/* ================================================================
208
 * CP control, initialization
209
 */
210
 
211
/* Load the microcode for the CP */
212
 
213
#include "radeon_microcode.h"
214
 
215
static void load_microcode(RHDPtr info)
216
{
217
	int i;
218
    const u32_t (*microcode)[2];
219
 
220
     OUTREG(RADEON_CP_ME_RAM_ADDR, 0);
221
 
222
     if ( (info->ChipFamily  == CHIP_FAMILY_LEGACY ) ||
223
          (info->ChipFamily  == CHIP_FAMILY_RADEON ) ||
224
          (info->ChipFamily  == CHIP_FAMILY_RV100  ) ||
225
          (info->ChipFamily  == CHIP_FAMILY_RV200  ) ||
226
          (info->ChipFamily  == CHIP_FAMILY_RS100  ) ||
227
          (info->ChipFamily  == CHIP_FAMILY_RS200  ))
228
     {
229
        microcode = R100_cp_microcode;
230
        dbgprintf("Loading R100 Microcode\n");
231
     }
232
     else if ((info->ChipFamily == CHIP_FAMILY_R200 ) ||
233
              (info->ChipFamily == CHIP_FAMILY_RV250) ||
234
              (info->ChipFamily == CHIP_FAMILY_RV280) ||
235
              (info->ChipFamily == CHIP_FAMILY_RS300))
236
     {
237
        microcode = R200_cp_microcode;
238
        dbgprintf("Loading R200 Microcode\n");
239
     }
240
     else if ((info->ChipFamily == CHIP_FAMILY_R300)  ||
241
              (info->ChipFamily == CHIP_FAMILY_R350)  ||
242
              (info->ChipFamily == CHIP_FAMILY_RV350) ||
243
              (info->ChipFamily == CHIP_FAMILY_RV380) ||
244
              (info->ChipFamily == CHIP_FAMILY_RS400) ||
245
              (info->ChipFamily == CHIP_FAMILY_RS480))
246
     {
247
        dbgprintf("Loading R300 Microcode\n");
248
        microcode = R300_cp_microcode;
249
     }
250
     else if ((info->ChipFamily == CHIP_FAMILY_R420)  ||
251
              (info->ChipFamily == CHIP_FAMILY_RV410))
252
     {
253
        dbgprintf("Loading R400 Microcode\n");
254
        microcode = R420_cp_microcode;
255
 
256
     }
257
     else if ((info->ChipFamily == CHIP_FAMILY_RS600) ||
258
              (info->ChipFamily == CHIP_FAMILY_RS690) ||
259
              (info->ChipFamily == CHIP_FAMILY_RS740))
260
     {
261
        dbgprintf("Loading RS690/RS740 Microcode\n");
262
        microcode = RS690_cp_microcode;
263
     }
264
     else if ((info->ChipFamily == CHIP_FAMILY_RV515) ||
265
              (info->ChipFamily == CHIP_FAMILY_R520)  ||
266
              (info->ChipFamily == CHIP_FAMILY_RV530) ||
267
              (info->ChipFamily == CHIP_FAMILY_R580)  ||
268
              (info->ChipFamily == CHIP_FAMILY_RV560) ||
269
              (info->ChipFamily == CHIP_FAMILY_RV570))
270
     {
271
        dbgprintf("Loading R500 Microcode\n");
272
        microcode = R520_cp_microcode;
273
     }
274
 
275
     for (i = 0; i < 256; i++) {
276
       OUTREG(RADEON_CP_ME_RAM_DATAH, microcode[i][1]);
277
       OUTREG(RADEON_CP_ME_RAM_DATAL, microcode[i][0]);
278
     }
279
}
280
 
281
 
282
void init_ring_buffer(RHDPtr info)
283
{
284
     u32_t ring_base;
285
     u32_t tmp;
286
 
287
     info->ringBase = CreateRingBuffer( 64*1024, PG_SW);
288
 
289
     dbgprintf("create cp ring buffer %x\n", rhd.ringBase);
290
     ring_base = GetPgAddr(rhd.ringBase);
291
     dbgprintf("ring base %x\n", ring_base);
292
 
293
     OUTREG(RADEON_CP_RB_BASE, ring_base);
294
 
295
     info->ring_avail = 64*1024/4 ;
296
 
297
	/* Set the write pointer delay */
298
     OUTREG(RADEON_CP_RB_WPTR_DELAY, 0);
299
 
300
	/* Initialize the ring buffer's read and write pointers */
301
     rhd.ring_rp = rhd.ring_wp = INREG(RADEON_CP_RB_RPTR);
302
     rhd.host_rp =  rhd.ring_rp;
303
 
304
     OUTREG(RADEON_CP_RB_WPTR,rhd.ring_rp);
305
 
885 serge 306
     tmp = (((u32_t)&rhd.host_rp) & 4095) + GetPgAddr((void*)&rhd.host_rp);
883 serge 307
 
308
     OUTREG(RADEON_CP_RB_RPTR_ADDR, tmp); // ring buffer read pointer
309
 
310
	/* Set ring buffer size */
311
     OUTREG(RADEON_CP_RB_CNTL, (1<<27)|(0<<18)|(10<<8)|13);
312
 
313
	/* Initialize the scratch register pointer.  This will cause
314
	 * the scratch register values to be written out to memory
315
	 * whenever they are updated.
316
	 *
317
	 * We simply put this behind the ring read pointer, this works
318
	 * with PCI GART as well as (whatever kind of) AGP GART
319
	 */
320
 
885 serge 321
     tmp = (((u32_t)&rhd.scratch0) & 4095) + GetPgAddr((void*)&rhd.scratch0);
883 serge 322
     OUTREG(RADEON_SCRATCH_ADDR, tmp);
323
 
324
     OUTREG(RADEON_SCRATCH_UMSK, 0x0);
325
     //OUTREG(0x778, 1);
326
 
327
	/* Turn on bus mastering */
328
     if ( (info->ChipFamily == CHIP_FAMILY_RS400) ||
329
          (info->ChipFamily == CHIP_FAMILY_RS690) ||
330
          (info->ChipFamily == CHIP_FAMILY_RS740) )
331
     {
332
		/* rs400, rs690/rs740 */
333
        tmp = INREG(RADEON_BUS_CNTL) & ~RS400_BUS_MASTER_DIS;
334
        OUTREG(RADEON_BUS_CNTL, tmp);
335
     }
336
     else if (!((info->ChipFamily == CHIP_FAMILY_RV380) ||
337
                (info->ChipFamily >= CHIP_FAMILY_R420)))
338
     {
339
		/* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
340
        tmp = INREG(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
341
        OUTREG(RADEON_BUS_CNTL, tmp);
342
	} /* PCIE cards appears to not need this */
343
 
344
    tmp = INREG(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
345
    OUTREG(RADEON_BUS_CNTL, tmp);
346
 
347
    radeon_do_wait_for_idle();
348
 
349
	/* Sync everything up */
350
    OUTREG(RADEON_ISYNC_CNTL,
351
          (RADEON_ISYNC_ANY2D_IDLE3D |
352
           RADEON_ISYNC_ANY3D_IDLE2D |
353
           RADEON_ISYNC_WAIT_IDLEGUI |
354
           RADEON_ISYNC_CPSCRATCH_IDLEGUI));
355
}
356
 
357
 
358
void radeon_engine_reset(RHDPtr info)
359
{
360
     u32_t  clock_cntl_index;
361
     u32_t  mclk_cntl;
362
     u32_t  rbbm_soft_reset;
363
     u32_t  host_path_cntl;
364
 
365
    if (info->ChipFamily <= CHIP_FAMILY_RV410)
366
    {
367
	        /* may need something similar for newer chips */
368
        clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX);
369
        mclk_cntl = INPLL( RADEON_MCLK_CNTL);
370
 
371
        OUTPLL(RADEON_MCLK_CNTL, (mclk_cntl |
372
						    RADEON_FORCEON_MCLKA |
373
						    RADEON_FORCEON_MCLKB |
374
						    RADEON_FORCEON_YCLKA |
375
						    RADEON_FORCEON_YCLKB |
376
						    RADEON_FORCEON_MC |
377
						    RADEON_FORCEON_AIC));
378
	}
379
 
380
    rbbm_soft_reset = INREG(RADEON_RBBM_SOFT_RESET);
381
 
382
    OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
383
					      RADEON_SOFT_RESET_CP |
384
					      RADEON_SOFT_RESET_HI |
385
					      RADEON_SOFT_RESET_SE |
386
					      RADEON_SOFT_RESET_RE |
387
					      RADEON_SOFT_RESET_PP |
388
					      RADEON_SOFT_RESET_E2 |
389
					      RADEON_SOFT_RESET_RB));
390
    INREG(RADEON_RBBM_SOFT_RESET);
391
    OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
392
					      ~(RADEON_SOFT_RESET_CP |
393
						RADEON_SOFT_RESET_HI |
394
						RADEON_SOFT_RESET_SE |
395
						RADEON_SOFT_RESET_RE |
396
						RADEON_SOFT_RESET_PP |
397
						RADEON_SOFT_RESET_E2 |
398
						RADEON_SOFT_RESET_RB)));
399
    INREG(RADEON_RBBM_SOFT_RESET);
400
 
401
    if (info->ChipFamily <= CHIP_FAMILY_RV410) {
402
        OUTPLL(RADEON_MCLK_CNTL, mclk_cntl);
403
        OUTREG(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index);
404
        OUTREG(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
405
	}
406
 };
407
 
408
#define RADEON_WAIT_UNTIL_IDLE() do {                   \
409
    OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 1 ) );         \
410
	OUT_RING( (RADEON_WAIT_2D_IDLECLEAN |				\
411
		   RADEON_WAIT_3D_IDLECLEAN |				\
412
		   RADEON_WAIT_HOST_IDLECLEAN) );			\
413
} while (0)
414
 
415
#define R300_ZB_ZCACHE_CTLSTAT                  0x4f18
416
#   define RADEON_RB3D_ZC_FLUSH     (1 << 0)
417
#	define RADEON_RB3D_ZC_FREE		(1 << 2)
418
#	define RADEON_RB3D_ZC_FLUSH_ALL		0x5
419
#   define RADEON_RB3D_ZC_BUSY      (1 << 31)
420
#   define R300_ZC_FLUSH                (1 << 0)
421
#	define R300_ZC_FREE		        (1 << 1)
422
#   define R300_ZC_BUSY             (1 << 31)
423
#   define RADEON_RB3D_DC_FLUSH     (3 << 0)
424
#	define RADEON_RB3D_DC_FREE		(3 << 2)
425
#	define RADEON_RB3D_DC_FLUSH_ALL		0xf
426
#   define RADEON_RB3D_DC_BUSY      (1 << 31)
427
#   define R300_RB3D_DC_FLUSH       (2 << 0)
428
#	define R300_RB3D_DC_FREE		(2 << 2)
429
#
430
#define RADEON_PURGE_CACHE() do {                                    \
431
    if ( rhd.ChipFamily <= CHIP_FAMILY_RV280) {                      \
432
            OUT_RING(CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 1));  \
433
            OUT_RING(RADEON_RB3D_DC_FLUSH | RADEON_RB3D_DC_FREE);    \
434
    } else {                                                         \
435
            OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 1));     \
436
            OUT_RING(R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE );       \
437
        }                                                            \
438
} while (0)
439
 
440
#define RADEON_FLUSH_ZCACHE() do {                                   \
441
    if ( rhd.ChipFamily <= CHIP_FAMILY_RV280) {     \
442
            OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 1 ) ); \
443
            OUT_RING( RADEON_RB3D_ZC_FLUSH );                        \
444
    } else {                                                         \
445
            OUT_RING( CP_PACKET0( R300_ZB_ZCACHE_CTLSTAT, 1 ) );     \
446
            OUT_RING( R300_ZC_FLUSH );                               \
447
        }                                                            \
448
} while (0)
449
#define RADEON_PURGE_ZCACHE() do {                  \
450
    if (rhd.ChipFamily <= CHIP_FAMILY_RV280) { \
451
            OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 1));    \
452
	        OUT_RING(RADEON_RB3D_ZC_FLUSH | RADEON_RB3D_ZC_FREE);	\
453
	} else {                                                        \
454
            OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 1));    \
455
	        OUT_RING(R300_ZC_FLUSH | R300_ZC_FREE);			\
456
        }                                                               \
457
} while (0)
458
 
459
static int radeon_cp_start(RHDPtr info)
460
{
461
     u32_t *ring, write;
462
     u32_t ifl;
463
     radeon_do_wait_for_idle(64);
464
 
465
     OUTREG(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM);
466
 
467
     ifl = safe_cli();
468
 
469
     BEGIN_RING(8);
470
	/* isync can only be written through cp on r5xx write it here */
471
       OUT_RING(CP_PACKET0(RADEON_ISYNC_CNTL, 1));
472
       OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D |
473
                RADEON_ISYNC_ANY3D_IDLE2D |
474
                RADEON_ISYNC_WAIT_IDLEGUI |
475
                RADEON_ISYNC_CPSCRATCH_IDLEGUI);
476
       RADEON_PURGE_CACHE();
477
       RADEON_PURGE_ZCACHE();
478
       RADEON_WAIT_UNTIL_IDLE();
479
       ADVANCE_RING();
480
    COMMIT_RING();
481
 
482
    safe_sti(ifl);
483
 
484
    radeon_do_wait_for_idle();
485
};
486
 
487
 
488
Bool init_cp(RHDPtr info)
489
{
490
     load_microcode(&rhd);
491
 
492
     init_ring_buffer(&rhd);
493
 
494
     radeon_engine_reset(&rhd);
495
 
496
    /* setup the raster pipes */
497
     init_pipes(&rhd);
498
 
499
     rhd.ring_rp = rhd.ring_wp = INREG(RADEON_CP_RB_RPTR);
500
     OUTREG(RADEON_CP_RB_WPTR, rhd.ring_rp);
501
 
502
     radeon_cp_start(&rhd);
503
 
504
};
505
 
506