File indexing completed on 2025-05-11 08:23:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <inttypes.h>
0020
0021 #include <rtems.h>
0022
0023 #include <bsp.h>
0024 #include <libchip/ide_ctrl.h>
0025 #include <libchip/ide_ctrl_cfg.h>
0026 #include <libchip/ide_ctrl_io.h>
0027
0028 #define ATA_SECTOR_SIZE (512)
0029
0030
0031
0032
0033 extern void Wait_X_ms(unsigned int msecs);
0034
0035 bool pc386_ide_show;
0036 uint32_t pc386_ide_timeout;
0037
0038 #define PC386_IDE_DEBUG_OUT 0
0039
0040 #if PC386_IDE_DEBUG_OUT
0041 bool pc386_ide_trace;
0042 #define pc386_ide_printk if (pc386_ide_trace) printk
0043 #endif
0044
0045 #define PC386_IDE_PROBE_TIMEOUT (500)
0046 #define PC386_IDE_PRESTART_TIMEOUT (1000)
0047 #define PC386_IDE_TASKING_TIMEOUT (2000)
0048
0049
0050
0051
0052 static void pc386_ide_prestart_sleep (void)
0053 {
0054 Wait_X_ms (10);
0055 }
0056
0057
0058
0059
0060 static void pc386_ide_tasking_sleep (void)
0061 {
0062 rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (10000) ?
0063 RTEMS_MICROSECONDS_TO_TICKS (10000) : 1);
0064 }
0065
0066 typedef void (*pc386_ide_sleeper)(void);
0067
0068 static void pc386_ide_sleep (pc386_ide_sleeper sleeper)
0069 {
0070 sleeper ();
0071 }
0072
0073 static void wait(volatile uint32_t loops)
0074 {
0075 while (loops)
0076 loops--;
0077 }
0078
0079 static bool pc386_ide_status_busy (uint32_t port,
0080 volatile uint32_t timeout,
0081 uint8_t* status_val,
0082 pc386_ide_sleeper sleeper)
0083 {
0084 volatile uint8_t status;
0085 int polls;
0086
0087 do
0088 {
0089 polls = 500;
0090 while (polls)
0091 {
0092 inport_byte (port + IDE_REGISTER_STATUS, status);
0093 if ((status & IDE_REGISTER_STATUS_BSY) == 0)
0094 {
0095 *status_val = status;
0096 return true;
0097 }
0098 polls--;
0099 }
0100
0101 if (timeout)
0102 {
0103 timeout--;
0104 pc386_ide_sleep (sleeper);
0105 }
0106 }
0107 while (timeout);
0108
0109 *status_val = status;
0110 return false;
0111 }
0112
0113 static bool pc386_ide_status_data_ready (uint32_t port,
0114 volatile uint32_t timeout,
0115 uint8_t* status_val,
0116 pc386_ide_sleeper sleeper)
0117 {
0118 volatile uint8_t status;
0119 int polls;
0120
0121 do
0122 {
0123 polls = 1000;
0124 while (polls)
0125 {
0126 inport_byte (port + IDE_REGISTER_STATUS, status);
0127
0128 if (((status & IDE_REGISTER_STATUS_BSY) == 0) &&
0129 (status & IDE_REGISTER_STATUS_DRQ))
0130 {
0131 *status_val = status;
0132 return true;
0133 }
0134
0135 polls--;
0136 }
0137
0138 if (timeout)
0139 {
0140 timeout--;
0141 pc386_ide_sleep (sleeper);
0142 }
0143 }
0144 while (timeout);
0145
0146 *status_val = status;
0147 return false;
0148 }
0149
0150
0151
0152
0153
0154
0155
0156 static bool pc386_ide_probe
0157 (
0158
0159
0160
0161
0162
0163
0164 int minor
0165 )
0166
0167
0168
0169
0170 {
0171 bool ide_card_plugged = true;
0172
0173 return ide_card_plugged;
0174 }
0175
0176
0177
0178
0179 static void pc386_ide_initialize
0180 (
0181
0182
0183
0184
0185
0186
0187 int minor
0188 )
0189
0190
0191
0192
0193 {
0194 uint32_t port = IDE_Controller_Table[minor].port1;
0195 uint8_t dev = 0;
0196
0197 if (pc386_ide_show)
0198 printk("IDE%d: port base: %04" PRIu32 "\n", minor, port);
0199
0200 outport_byte(port+IDE_REGISTER_DEVICE_HEAD,
0201 (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | 0xE0);
0202 wait(10000);
0203 outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
0204 IDE_REGISTER_DEVICE_CONTROL_SRST | IDE_REGISTER_DEVICE_CONTROL_nIEN);
0205 wait(10000);
0206 outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
0207 IDE_REGISTER_DEVICE_CONTROL_nIEN);
0208 wait(10000);
0209
0210 for (dev = 0; dev < 2; dev++)
0211 {
0212 uint16_t capabilities = 0;
0213 uint32_t byte;
0214 uint8_t status;
0215 uint8_t error;
0216 uint8_t cyllsb;
0217 uint8_t cylmsb;
0218 const char* label = dev ? " slave" : "master";
0219 int max_multiple_sectors = 0;
0220 int cur_multiple_sectors = 0;
0221 uint32_t cylinders = 0;
0222 uint32_t heads = 0;
0223 uint32_t sectors = 0;
0224 uint32_t lba_sectors = 0;
0225 char model_number[41];
0226 char* p = &model_number[0];
0227 bool data_ready;
0228
0229 (void) cur_multiple_sectors;
0230
0231 memset(model_number, 0, sizeof(model_number));
0232
0233 outport_byte(port+IDE_REGISTER_DEVICE_HEAD,
0234 (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | 0xE0);
0235
0236
0237
0238
0239
0240 outport_byte(port+IDE_REGISTER_COMMAND, 0x00);
0241
0242 if (!pc386_ide_status_busy (port, PC386_IDE_PROBE_TIMEOUT,
0243 &status, pc386_ide_prestart_sleep))
0244 continue;
0245
0246 inport_byte(port+IDE_REGISTER_STATUS, status);
0247 inport_byte(port+IDE_REGISTER_ERROR, error);
0248 inport_byte(port+IDE_REGISTER_CYLINDER_LOW, cyllsb);
0249 inport_byte(port+IDE_REGISTER_CYLINDER_HIGH, cylmsb);
0250
0251 if (pc386_ide_show)
0252 {
0253 printk("IDE%d:%s: status=%02x\n", minor, label, status);
0254 printk("IDE%d:%s: error=%02x\n", minor, label, error);
0255 printk("IDE%d:%s: cylinder-low=%02x\n", minor, label, cyllsb);
0256 printk("IDE%d:%s: cylinder-high=%02x\n", minor, label, cylmsb);
0257 }
0258
0259 outport_byte(port+IDE_REGISTER_COMMAND, 0xec);
0260
0261 if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
0262 &status, pc386_ide_prestart_sleep))
0263 {
0264 if (pc386_ide_show)
0265 printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
0266 continue;
0267 }
0268
0269 data_ready = pc386_ide_status_data_ready (port,
0270 250,
0271 &status,
0272 pc386_ide_prestart_sleep);
0273
0274 if (status & IDE_REGISTER_STATUS_ERR)
0275 {
0276 inport_byte(port+IDE_REGISTER_ERROR, error);
0277 if (error != 4)
0278 {
0279 if (pc386_ide_show)
0280 printk("IDE%d:%s: error=%04x\n", minor, label, error);
0281 continue;
0282 }
0283
0284
0285
0286 outport_byte(port+IDE_REGISTER_COMMAND, 0xa1);
0287 data_ready = pc386_ide_status_data_ready (port,
0288 250,
0289 &status,
0290 pc386_ide_prestart_sleep);
0291 }
0292
0293 if (!data_ready)
0294 continue;
0295
0296 byte = 0;
0297 while (byte < 512)
0298 {
0299 uint16_t word;
0300
0301 if (pc386_ide_show && ((byte % 16) == 0))
0302 printk("\n %04" PRIx32 " : ", byte);
0303
0304 inport_word(port+IDE_REGISTER_DATA, word);
0305
0306 if (pc386_ide_show)
0307 printk ("%04x ", word);
0308
0309 if (byte == 2)
0310 cylinders = word;
0311 if (byte == 6)
0312 heads = word;
0313 if (byte == 12)
0314 sectors = word;
0315
0316 if (byte >= 54 && byte < (54 + 40))
0317 {
0318 *p = word >> 8;
0319 p++;
0320 *p = word;
0321 p++;
0322 }
0323
0324 if (byte == (47 * 2))
0325 max_multiple_sectors = word & 0xff;
0326
0327 if (byte == (49 * 2))
0328 capabilities = word;
0329
0330 if (byte == (59 * 2))
0331 {
0332 if (word & (1 << 8))
0333 cur_multiple_sectors = word & 0xff;
0334 }
0335
0336 if (byte == (60 * 2))
0337 lba_sectors = word;
0338 if (byte == (61 * 2))
0339 lba_sectors |= word << 16;
0340
0341 byte += 2;
0342 }
0343
0344 if (pc386_ide_show)
0345 printk("\nbytes read = %" PRIu32 "\n", byte);
0346
0347 if (p != &model_number[0])
0348 {
0349 uint32_t size;
0350 uint32_t left;
0351 uint32_t right;
0352 char units;
0353
0354 if (capabilities & (1 << 9))
0355 size = lba_sectors;
0356 else
0357 size = cylinders * heads * sectors;
0358
0359 size /= 2;
0360
0361 if (size > (1024 * 1024))
0362 {
0363 size = (size * 10) / (1000 * 1000);
0364 units = 'G';
0365 }
0366 else if (size > 1024)
0367 {
0368 size = (size * 10) / 1000;
0369 units = 'M';
0370 }
0371 else
0372 {
0373 size = size * 10;
0374 units = 'K';
0375 }
0376
0377 left = size / 10;
0378 right = size % 10;
0379
0380 p--;
0381 while (*p == ' ')
0382 {
0383 *p = '\0';
0384 p--;
0385 }
0386
0387 printk("IDE%d:%s:%s, %" PRIu32 ".%" PRIu32 "%c (%" PRIu32 "/%" PRIu32 "/%" PRIu32 "), max blk size:%d\n",
0388 minor, label, model_number, left, right, units,
0389 heads, cylinders, sectors, max_multiple_sectors * 512);
0390 }
0391
0392 #if IDE_CLEAR_MULTI_SECTOR_COUNT
0393 if (max_multiple_sectors)
0394 {
0395 outport_byte(port+IDE_REGISTER_SECTOR_COUNT, 0);
0396 outport_byte(port+IDE_REGISTER_COMMAND, 0xc6);
0397
0398 if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
0399 &status, pc386_ide_prestart_sleep))
0400 {
0401 if (pc386_ide_show)
0402 printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
0403 continue;
0404 }
0405
0406 inport_byte(port+IDE_REGISTER_STATUS, status);
0407 if (status & IDE_REGISTER_STATUS_ERR)
0408 {
0409 inport_byte(port+IDE_REGISTER_ERROR, error);
0410 if (error & IDE_REGISTER_ERROR_ABRT)
0411 printk("IDE%d:%s: disable multiple failed\n", minor, label);
0412 else
0413 printk("IDE%d:%s: unknown error on disable multiple: %02x\n",
0414 minor, label, error);
0415 }
0416 }
0417 #endif
0418
0419 outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
0420 IDE_REGISTER_DEVICE_CONTROL_nIEN);
0421 wait(10000);
0422 }
0423
0424 pc386_ide_timeout = PC386_IDE_TASKING_TIMEOUT;
0425
0426
0427
0428
0429 }
0430
0431
0432
0433
0434 static void pc386_ide_read_reg
0435 (
0436
0437
0438
0439
0440
0441
0442 int minor,
0443 int reg,
0444 uint16_t *value
0445 )
0446
0447
0448
0449
0450 {
0451 uint32_t port = IDE_Controller_Table[minor].port1;
0452 uint8_t bval1,bval2;
0453
0454 if (reg == IDE_REGISTER_DATA_WORD) {
0455 inport_byte(port+reg, bval1);
0456 inport_byte(port+reg+1, bval2);
0457 *value = bval1 + (bval2 << 8);
0458 }
0459 else {
0460 inport_byte(port+reg, bval1);
0461 *value = bval1;
0462 }
0463 #if PC386_IDE_DEBUG_OUT
0464 pc386_ide_printk("pc386_ide_read_reg (0x%x)=0x%x\r\n",reg,*value & 0xff);
0465 #endif
0466 }
0467
0468
0469
0470
0471 static void pc386_ide_write_reg
0472 (
0473
0474
0475
0476
0477
0478
0479 int minor,
0480 int reg,
0481 uint16_t value
0482 )
0483
0484
0485
0486
0487 {
0488 uint32_t port = IDE_Controller_Table[minor].port1;
0489
0490 #if PC386_IDE_DEBUG_OUT
0491 pc386_ide_printk("pc386_ide_write_reg(0x%x,0x%x)\r\n",reg,value & 0xff);
0492 #endif
0493 if (reg == IDE_REGISTER_DATA_WORD) {
0494 outport_word(port+reg,value);
0495 }
0496 else {
0497 outport_byte(port+reg,value);
0498 }
0499 }
0500
0501
0502
0503
0504 static void pc386_ide_read_block
0505 (
0506
0507
0508
0509
0510
0511
0512 int minor,
0513 uint32_t block_size,
0514 rtems_blkdev_sg_buffer *bufs,
0515 uint32_t *cbuf,
0516 uint32_t *pos
0517 )
0518
0519
0520
0521
0522 {
0523 uint32_t port = IDE_Controller_Table[minor].port1;
0524 uint32_t cnt = 0;
0525 #if PC386_IDE_DEBUG_OUT
0526 int i32 = 0;
0527 pc386_ide_printk("pc386_ide_read_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
0528 block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
0529 #endif
0530
0531 while (cnt < block_size)
0532 {
0533 uint16_t *lbuf;
0534 uint8_t status_val;
0535 int b;
0536
0537 if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
0538 &status_val, pc386_ide_tasking_sleep))
0539 {
0540 printk ("pc386_ide_read_block: block=%" PRIu32 \
0541 " cbuf=%" PRIu32 " status=%02x, cnt=%" PRIu32 " bs=%" PRIu32 "\n",
0542 bufs[*cbuf].block, *cbuf, status_val, cnt, block_size);
0543
0544 return;
0545 }
0546
0547 if (status_val & IDE_REGISTER_STATUS_ERR)
0548 {
0549 inport_byte(port+IDE_REGISTER_ERROR, status_val);
0550 printk("pc386_ide_read_block: error: %02x\n", status_val);
0551 return;
0552 }
0553
0554 lbuf = (uint16_t*)((uint8_t*)(bufs[(*cbuf)].buffer) + (*pos));
0555
0556 for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
0557 {
0558 inport_word(port+IDE_REGISTER_DATA,*lbuf);
0559
0560 #if PC386_IDE_DEBUG_OUT
0561 pc386_ide_printk("%04x ",*lbuf);
0562 i32++;
0563 if (i32 >= 16)
0564 {
0565 pc386_ide_printk("\n");
0566 i32 = 0;
0567 }
0568 #endif
0569 lbuf++;
0570 }
0571 cnt += ATA_SECTOR_SIZE;
0572 (*pos) += ATA_SECTOR_SIZE;
0573 if ((*pos) == bufs[(*cbuf)].length) {
0574 (*pos) = 0;
0575 (*cbuf)++;
0576 lbuf = bufs[(*cbuf)].buffer;
0577 }
0578 }
0579 }
0580
0581
0582
0583
0584 static void pc386_ide_write_block
0585 (
0586
0587
0588
0589
0590
0591
0592 int minor,
0593 uint32_t block_size,
0594 rtems_blkdev_sg_buffer *bufs,
0595 uint32_t *cbuf,
0596 uint32_t *pos
0597 )
0598
0599
0600
0601
0602 {
0603 uint32_t port = IDE_Controller_Table[minor].port1;
0604 uint32_t cnt = 0;
0605 #if PC386_IDE_DEBUG_OUT
0606 int i32 = 0;
0607 pc386_ide_printk("pc386_ide_write_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
0608 block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
0609 #endif
0610
0611 while (cnt < block_size)
0612 {
0613 uint16_t *lbuf;
0614 uint8_t status_val;
0615 int b;
0616
0617 if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
0618 &status_val, pc386_ide_tasking_sleep))
0619 {
0620 printk ("pc386_ide_write_block: block=%" PRIu32 " status=%02x, cnt=%" PRIu32 " bs=%" PRIu32 "\n",
0621 bufs[*cbuf].block, status_val, cnt, block_size);
0622
0623 return;
0624 }
0625
0626 if (status_val & IDE_REGISTER_STATUS_ERR)
0627 {
0628 inport_byte(port+IDE_REGISTER_ERROR, status_val);
0629 printk ("pc386_ide_write_block: error: %02x\n", status_val);
0630 return;
0631 }
0632
0633 lbuf = (uint16_t*)(((uint8_t*)bufs[*cbuf].buffer) + (*pos));
0634
0635 for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
0636 {
0637 #if PC386_IDE_DEBUG_OUT
0638 pc386_ide_printk("%04x ",*lbuf);
0639 i32++;
0640 if (i32 >= 16)
0641 {
0642 pc386_ide_printk("\n");
0643 i32 = 0;
0644 }
0645 #endif
0646 outport_word(port+IDE_REGISTER_DATA,*lbuf);
0647 lbuf++;
0648 }
0649 cnt += ATA_SECTOR_SIZE;
0650 (*pos) += ATA_SECTOR_SIZE;
0651 if ((*pos) == bufs[(*cbuf)].length) {
0652 (*pos) = 0;
0653 (*cbuf)++;
0654 lbuf = bufs[(*cbuf)].buffer;
0655 }
0656 }
0657 }
0658
0659
0660
0661
0662 static int pc386_ide_control
0663 (
0664
0665
0666
0667
0668
0669
0670 int minor,
0671 uint32_t cmd,
0672 void * arg
0673 )
0674
0675
0676
0677
0678 {
0679 return 0;
0680 }
0681
0682
0683
0684
0685 static rtems_status_code pc386_ide_config_io_speed
0686 (
0687
0688
0689
0690
0691
0692
0693 int minor,
0694 uint16_t modes_avail
0695 )
0696
0697
0698
0699
0700 {
0701 return RTEMS_SUCCESSFUL;
0702 }
0703
0704
0705
0706
0707
0708
0709 ide_ctrl_fns_t pc386_ide_ctrl_fns = {
0710 pc386_ide_probe,
0711 pc386_ide_initialize,
0712 pc386_ide_control,
0713 pc386_ide_read_reg,
0714 pc386_ide_write_reg,
0715 pc386_ide_read_block,
0716 pc386_ide_write_block,
0717 pc386_ide_config_io_speed
0718 };