Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:52

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2011, 2013 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #define NDEBUG
0029 
0030 #include <bsp/ata.h>
0031 
0032 #include <libcpu/powerpc-utility.h>
0033 
0034 #include <bsp.h>
0035 #include <bsp/fatal.h>
0036 #include <bsp/irq.h>
0037 
0038 typedef enum {
0039   DATA_CURRENT = 0,
0040   DATA_END,
0041   DATA_REG
0042 } variables;
0043 
0044 typedef enum {
0045   INC_0_NE = 0,
0046   INC_2_NE
0047 } increments;
0048 
0049 /*
0050  * for
0051  *   idx0 = DATA_CURRENT, idx1 = DATA_REG
0052  *   idx0 != DATA_END
0053  *   idx0 += 2, idx1 += 0
0054  * do
0055  *   *idx0 = *idx1 [INT, 16 bit] OR *idx1 = *idx0 [INT, 16 bit]
0056  */
0057 static const uint32_t ops[] = {
0058   LCD(0, VAR(DATA_CURRENT), 0, VAR(DATA_REG), TERM_FIRST, VAR(DATA_END), INC_2_NE, INC_0_NE),
0059     0, /* Transfer opcode, see transfer() */
0060 };
0061 
0062 static bool is_last_transfer(const ata_driver_dma_pio_single *self)
0063 {
0064   return self->transfer_current + 1 == self->transfer_end;
0065 }
0066 
0067 static void start_sector_transfer(ata_driver_dma_pio_single *self)
0068 {
0069   uint16_t *current = ata_sg_get_sector_data_begin(&self->sg_context, self->transfer_current);
0070   bestcomm_task_set_variable(&self->task, DATA_CURRENT, (uint32_t) current);
0071   bestcomm_task_set_variable(&self->task, DATA_END, (uint32_t) ata_sg_get_sector_data_end(&self->sg_context, current));
0072   bestcomm_task_start(&self->task);
0073 
0074   bool last = is_last_transfer(self);
0075   ++self->transfer_current;
0076 
0077   if (!last) {
0078     ata_flush_sector(ata_sg_get_sector_data_begin(&self->sg_context, self->transfer_current));
0079   }
0080 }
0081 
0082 static void dma_pio_single_interrupt_handler(void *arg)
0083 {
0084   ata_driver_dma_pio_single *self = arg;
0085   bool ok = ata_check_status();
0086   bool send_event = false;
0087   if (ok && self->transfer_current != self->transfer_end) {
0088     bool enable_dma_interrupt = self->read && is_last_transfer(self);
0089     if (enable_dma_interrupt) {
0090       bestcomm_task_irq_clear(&self->task);
0091       bestcomm_task_irq_enable(&self->task);
0092     }
0093 
0094     start_sector_transfer(self);
0095   } else {
0096     send_event = true;
0097   }
0098 
0099   if (send_event) {
0100     bestcomm_task_wakeup_event_task(&self->task);
0101   }
0102 }
0103 
0104 static bool transfer_dma_pio_single(ata_driver *super, bool read, rtems_blkdev_sg_buffer *sg, size_t sg_count)
0105 {
0106   bool ok = true;
0107   ata_driver_dma_pio_single *self = (ata_driver_dma_pio_single *) super;
0108 
0109   self->read = read;
0110   ata_sg_reset(&self->sg_context, sg, sg_count);
0111   rtems_blkdev_bnum start_sector = ata_sg_get_start_sector(&self->sg_context);
0112   rtems_blkdev_bnum sector_count = ata_sg_get_sector_count(&self->sg_context);
0113   rtems_blkdev_bnum relative_sector = 0;
0114 
0115   ata_flush_sector(ata_sg_get_sector_data_begin(&self->sg_context, relative_sector));
0116 
0117   uint8_t command = ata_read_or_write_sectors_command(read);
0118 
0119   uint32_t opcode;
0120   if (read) {
0121     opcode = DRD1A(INT, INIT_ALWAYS, DEST_DEREF_IDX(0), SZ_16, SRC_DEREF_IDX(1), SZ_16);
0122   } else {
0123     opcode = DRD1A(INT, INIT_ALWAYS, DEST_DEREF_IDX(1), SZ_16, SRC_DEREF_IDX(0), SZ_16);
0124   }
0125 
0126   bestcomm_task_irq_disable(&self->task);
0127   bestcomm_task_associate_with_current_task(&self->task);
0128 
0129   size_t transfer_opcode_index = 1; /* See ops */
0130   bestcomm_task_set_opcode(&self->task, transfer_opcode_index, opcode);
0131 
0132   while (ok && relative_sector < sector_count) {
0133     rtems_blkdev_bnum remaining_sectors = sector_count - relative_sector;
0134     rtems_blkdev_bnum transfer_count = ata_max_transfer_count(remaining_sectors);
0135 
0136     self->transfer_current = relative_sector;
0137     self->transfer_end = relative_sector + transfer_count;
0138 
0139     ok = ata_execute_io_command(command, start_sector + relative_sector, transfer_count);
0140     if (ok) {
0141       if (!read) {
0142         ok = ata_wait_for_data_request();
0143         assert(ok);
0144 
0145         rtems_interrupt_level level;
0146         rtems_interrupt_disable(level);
0147         start_sector_transfer(self);
0148         rtems_interrupt_enable(level);
0149       }
0150 
0151       bestcomm_task_wait(&self->task);
0152 
0153       ok = ata_check_status();
0154 
0155       relative_sector += ATA_PER_TRANSFER_SECTOR_COUNT_MAX;
0156     }
0157   }
0158 
0159   return ok;
0160 }
0161 
0162 static int io_control_dma_pio_single(
0163   rtems_disk_device *dd,
0164   uint32_t cmd,
0165   void *arg
0166 )
0167 {
0168   return ata_driver_io_control(dd, cmd, arg, transfer_dma_pio_single);
0169 }
0170 
0171 void ata_driver_dma_pio_single_create(ata_driver_dma_pio_single *self, const char *device_file_path, TaskId task_index)
0172 {
0173   ata_driver_create(&self->super, device_file_path, io_control_dma_pio_single);
0174 
0175   self->read = false;
0176 
0177   if (ata_driver_is_card_present(&self->super)) {
0178     bestcomm_task_create_and_load(&self->task, task_index, ops, sizeof(ops));
0179 
0180     bestcomm_task_set_variable(&self->task, DATA_REG, (uint32_t) &ATA->write.data);
0181 
0182     bestcomm_task_set_increment_and_condition(&self->task, INC_0_NE, 0, COND_NE);
0183     bestcomm_task_set_increment_and_condition(&self->task, INC_2_NE, 2, COND_NE);
0184 
0185     bestcomm_task_enable_combined_write(&self->task, true);
0186     bestcomm_task_enable_read_buffer(&self->task, true);
0187     bestcomm_task_enable_speculative_read(&self->task, true);
0188 
0189     ata_clear_interrupts();
0190 
0191     rtems_status_code sc = rtems_interrupt_handler_install(
0192       BSP_SIU_IRQ_ATA,
0193       "ATA",
0194       RTEMS_INTERRUPT_UNIQUE,
0195       dma_pio_single_interrupt_handler,
0196       self
0197     );
0198     if (sc != RTEMS_SUCCESSFUL) {
0199       bsp_fatal(MPC5200_FATAL_ATA_DMA_SINGLE_IRQ_INSTALL);
0200     }
0201   }
0202 }