Официальный форум СВД Встраиваемые Системы
19 Апрель, 2024, 18:13:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.

Войти
 
 
 Сайт СВД ВС  Начало   Помощь Поиск Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: etfs драйвер для параллельной NAND i.mx6  (Прочитано 1440 раз)
yanvasilij
Пользователь

Сообщений: 16


« : 14 Июнь, 2018, 10:32:25 »

Добрый день!

 - QNX6.5.
 - Вывод утилит pidin ar дать не могу, у меня из терминалов пока доступен только последовательный порт (драйвер ethernet еще не поднял), а консоль ставноится недоступна, как только стартует драйвер etfs.
 - Команда запуска драйвера fs-etfs-imx-micron -e.

Пытаюсь поднять файловую систему ETFS для микросхемы MT29F8G08 на нашем устройстве на базе i.MX6S. В качестве BSP у нас портированная версия BSP для Freescale i.MX6Q Sabre Lite Board. Но поскольку в составе этой BSP не было ни одного драйвера для параллельных NAND, драйвер взяли из BSP для NXP MCIMX7 Sabre Board, там он как раз для этой микросхемы. По составу регистров полное совпадение, единственное, что нужно было сделать, насколько я понял, это задать правильное начальное смещение регистров для модулей GPMI, BCH и APBH и назначить нужные номера аппаратных прерываний. Это можно было сделать передав параметр драйверу или просто поправив в исходниках, как я и поступил. Драйвер собрался без ошибок, запуск этого драйвера я прописал в секции .script в build-файле:

Код:
[+script] .script = {
...
    display_msg Starting fs-etfs-imx-micron -e
    fs-etfs-imx-micron -e
...
}

После запуска драйвера, процесс останавливается в бесконечном ожидании прерывания от модуля gpmi IMX_APBH_IRQ (45 - Logical OR of APBH DMA channels 0-3 completion and error interrupts). Система при этом не зависает "насмерть" (watchdog не срабатывает), но загрузка так и останавливается на ожидании, когда поднимется драйвер.

Клоки вроде как поданы - я их все включил в DCD секции еще в IPL:

Код:

DCD_ENTRY(1, 0x020c4068, 0xffffffff)
DCD_ENTRY(2, 0x020c406c, 0xffffffff)
DCD_ENTRY(3, 0x020c4070, 0xffffffff)
DCD_ENTRY(4, 0x020c4074, 0xffffffff)
DCD_ENTRY(5, 0x020c4078, 0xffffffff)
DCD_ENTRY(6, 0x020c407c, 0xffffffff)
DCD_ENTRY(7, 0x020c4080, 0xffffffff)


Мультиплексирование пинов я сделал в startup:

Код:
            out32(MX6X_CCM_BASE + MX6X_CCM_CCGR4, 0xFFFFF300 );
 
            pinmux_set_swmux(SWMUX_NANDF_CLE, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_CLE, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_ALE, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_ALE, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_WP_B, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_WP_B, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_RB0, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_RB0, PAD_CFG_1);
 
            pinmux_set_swmux(SWMUX_NANDF_CS0, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_CS0, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_CS1, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_CS1, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_CS2, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_CS2, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_CS3, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_CS3, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_SD4_CMD, MUX_CTL_MUX_MODE_ALT1);
            pinmux_set_padcfg(SWPAD_SD4_CMD, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_SD4_CLK, MUX_CTL_MUX_MODE_ALT1);
            pinmux_set_padcfg(SWPAD_SD4_CLK, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_D0, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_D0, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_D1, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_D1, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_D2, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_D2, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_D3, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_D3, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_D4, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_D4, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_D5, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_D5, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_D6, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_D6, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_NANDF_D7, MUX_CTL_MUX_MODE_ALT0);
            pinmux_set_padcfg(SWPAD_NANDF_D7, PAD_CFG_0);
 
            pinmux_set_swmux(SWMUX_SD4_DAT0, MUX_CTL_MUX_MODE_ALT2);
            pinmux_set_padcfg(SWPAD_SD4_DAT0, PAD_CFG_2);

Вот фрагмент кода, в котором все стопорится:

Код:
// APBH, BCH and GPMI init
if (nand_init(cio) != 0) {
        dev->log(_SLOG_CRITICAL, "nand_init failed : %s", strerror(errno));
        // We will not return
    }
 
    cio->apbhirq = IMX_APBH_IRQ;
    cio->bchirq = IMX_BCH_IRQ;
 
    // Start-up a thread that is dedicated to interrupt processing
    cio->apbhirq_expected = 0;
    pthread_mutex_init(&cio->apbhmutex, NULL);
    pthread_cond_init(&cio->apbhcond, NULL);
    pthread_create(NULL, NULL, apbhint_thread, cio);
    // Start-up a thread that is dedicated to interrupt processing
    cio->bchirq_expected = 0;
    pthread_mutex_init(&cio->bchmutex, NULL);
    pthread_cond_init(&cio->bchcond, NULL);
    pthread_create(NULL, NULL, bchint_thread, cio);
 
...
    if (nand_wait_busy(cio, MAX_RESET_USEC, 0) != 0) {
        dev->log(_SLOG_CRITICAL, "Timeout on RESET");
    }
 
    // Create reset device and reset the part - for some devices it must be first command
    create_reset_descriptor(reset_ptr);
    status = run_dma((apbh_dma_t*)reset_ptr, cio, NAND_DMA_GPMI_TRANS, (uint32_t)virtual_to_physical_addr(reset_ptr));
    if (status != NAND_EOK) {
        dev->log(_SLOG_CRITICAL, "DMA operation fail");
    }
    if (nand_wait_busy(cio, MAX_RESET_USEC, 0) != 0) {
        dev->log(_SLOG_CRITICAL, "Timeout on RESET");
    }
    delay(2);
    // Create read status chain and read status register from device
    create_readStatus2_descriptor(read_status_ptr, mem_stat_ptr, 1);
                status = run_dma((apbh_dma_t*)read_status_ptr, cio, NAND_DMA_GPMI_TRANS, (uint32_t)virtual_to_physical_addr(read_status_ptr));     //<<<<<<<<<<<<<<<<< Оставливается на ожидании прерывания здесь <<<<<<<<<<<<<<<<<<<
...

Если у кого-нибудь есть идеи, подскажите в чем может быть дело?
Записан
Владимир Махилёв
Сотрудник СВД ВС
Старожил

Сообщений: 704



WWW
« Ответ #1 : 18 Июнь, 2018, 17:00:47 »

Боюсь, что могу сказать только очевидную фразу про то, что необходимо погружаться в отладку драйвера.
Начать лучше с самого начала. Ещё раз проверьте и убедитесь, что правильно настроены мультиплексинг, клоки, указаны базовые адреса регистров и их содержимое совпадает с документацией/кодом.
Драйвер немногословен, поэтому вероятно придётся в ручном режиме пройтись по ключевым моментам и, например, выводить дамп регистров и проверять, что всё похоже на правду. Не очень ясно приходит-ли прерывание. Если нет, то нужно разбираться почему - возможно неверно указан номер или оно не включено/не настроено.
В отладке может помочь U-Boot. Если он работает с флэшкой, то стоит свериться и с настройкой мультиплексинга, и с логикой работы.

Записан

yanvasilij
Пользователь

Сообщений: 16


« Ответ #2 : 21 Июнь, 2018, 15:40:46 »

... Не очень ясно приходит-ли прерывание. Если нет, то нужно разбираться почему - возможно неверно указан номер или оно не включено/не настроено.
...

По-поводу прерываний это интересное замечание. Драйвер стопорится на функции apbh_intr_wait(), которая ждет флаг и мьютекс:

Код:
/**
 * Conditional wait for interrupt occurrence.
 */
int apbh_intr_wait(chipio *chipio)
{

    pthread_mutex_lock(&chipio->apbhmutex);

    while (chipio->apbhirq_expected == 0) {
        pthread_cond_wait(&chipio->apbhcond, &chipio->apbhmutex);
    }
...
}

А флаг apbhirq_expected и мьютекс apbhmutex выставляются в потоке apbhint_thread, который подписан на прерывание IMX_APBH_IRQ. IMX_APBH_IRQ я переопределил, когда портировал драйвер на значение 45 (APBH DMA - Logical OR of APBH DMA channels 0-3 completion and error interrupts), которое я взял из документации на imx6s.

Код:

void *apbhint_thread(void *arg)
{
...
    SIGEV_INTR_INIT(&chipio->apbhevent);
    chipio->apbhiid = InterruptAttachEvent(chipio->apbhirq, &chipio->apbhevent, _NTO_INTR_FLAGS_TRK_MSK); // Значение chipio->apbhirq = IMX_APBH_IRQ (45)
...

    while (1) {
        InterruptWait (NULL, NULL);
...
        chipio->apbhirq_expected = 1;
        pthread_cond_signal(&chipio->apbhcond);
        //
        pthread_mutex_unlock(&chipio->apbhmutex);
        InterruptUnmask(chipio->apbhirq, chipio->apbhiid);
    }
    return NULL;
}

Так вот собсвтенно поток apbhint_thread() никогда не выходит из ожидания прерывания, из чего я сделал вывод, что прерывание не происходит.

Мне пока не совсем понятно, каким образом происходит привязка аппаратного прерывания к ядру, не исключаю, что дальше будет путаница. Буду очень признателен, если прокомментируете. Правильно ли я понимаю, связь ядра и "железа" происходит в startup путем "наполнения" syspage_entry, в частности прерывания можно добавить к ней при помощи add_interrupt()? Нужно ли все необходимые для работы прерывания явным образом так описывать? В BSP на Freescale i.MX6Q Sabre Lite Board и NXP MCIMX7 Sabre Board я нашел только привязки к GPIO x low interrupts:

Код:
...
/* GPIO 1 low interrupts (160 -175) */
{ 160, // vector base
16, // number of vectors
98, // cascade vector
0, // CPU vector base
0, // CPU vector stride
0, // flags

{ 0, 0, &interrupt_id_mx6x_gpio_low },
{ INTR_GENFLAG_LOAD_INTRMASK, 0, &interrupt_eoi_mx6x_gpio_low },
&interrupt_mask_mx6x_gpio_low, // mask   callout
&interrupt_unmask_mx6x_gpio_low, // unmask callout
0, // config callout
&mx6x_gpio1_base,
},
...

Глядя на эту структуру, могу предложить, что на самом деле мне нужно подписывать поток не значение вектора прерывания из документации на процессор (reference manual), а на значение "vector base" из соответствующего экземпляра структуры startup_intrinfo? Если так, то почему я не нашел никаких других прерываний в startup в BSP, кроме GPIO 1 low interrupts? Или это делается как-то иначе?
Записан
Владимир Махилёв
Сотрудник СВД ВС
Старожил

Сообщений: 704



WWW
« Ответ #3 : 22 Июнь, 2018, 18:41:37 »

Прерывания и обработчики по умолчанию привязаны к нулевому процессорному ядру и настройка действительно осуществляется в startup в коде init_intrinfo(), но прерывания от базовых устройств уже должны быть уже настроены.
Прерывания GPIO настраиваются т.н. каскадом, т.е. система сначала получает прерывание CPU 98 (cascade vector) и в дальнейшем определяет и возвращает логический номер конкретного прерывания GPIO. При этом используются логические номера прерываний, т.е. если у вас, например, приходит 5ое прерывание на GPIO 1, то нужно прибавить его к логическому номеру 160 (vector base) + 5.
GPIO наверняка мультиплексируются, поэтому убедитесь ещё раз, что нужные пины настроены на правильный режим.

Однако, насколько понимаю, у вас прерывание не от GPIO, а от одного из каналов DMA. Возможно канал неверно указан?
Записан

yanvasilij
Пользователь

Сообщений: 16


« Ответ #4 : 27 Июнь, 2018, 08:51:41 »

Возможно канал неверно указан?

Хорошая догадка, я почему то не догадался сразу проверить, но увы. Канал тот:



Код:
/**
 * DMA channel initialization.
 *
 * @param chipio Low level driver handle.
 */
void apbh_init_dma_channel(chipio *chipio)
{
    uint32_t apbh_virt_base = chipio->apbh_dma_reg_base;
    uint32_t apbh_channel_mask = 0x10001;
    uint8_t cnt = 0;

    /* Reset dma channel 0 */
    out32((apbh_virt_base + IMX_APBH_CHANNEL_CTRL_SET_OFFSET), IMX_APBH_CHANNEL_CTRL_RESET_CHANNEL(apbh_channel_mask));

    /* Wait for the reset to complete */
    while((*(volatile imx_apbh_channel_ctrl_t *) (apbh_virt_base + IMX_APBH_CHANNEL_CTRL_OFFSET)).B.RESET_CHANNEL & apbh_channel_mask) {
        delay(1);
        cnt++;
        if (cnt > 10) {
            break;
        }
    };

    /* Clear corresponding IRQ and enable interrupt */
    out32((apbh_virt_base + IMX_APBH_CTRL1_OFFSET), apbh_channel_mask);
}
« Последнее редактирование: 27 Июнь, 2018, 09:01:39 от yanvasilij » Записан
semevgen
Интересующийся

Сообщений: 3


« Ответ #5 : 01 Ноябрь, 2018, 19:11:29 »

Здравствуйте,  yanvasilij.
Мне понадобилось работать с NAND на модуле phyflex imx6q под QNX, тоже пытался запустить драйвер от BSP для NXP MCIMX7 Sabre Board, и столкнулся с той же проблемой: остановка драйвера на ожидании прерывания в функции apbh_intr_wait. Получилось ли у вас продвинуться решении этой проблемы ?
Записан
yanvasilij
Пользователь

Сообщений: 16


« Ответ #6 : 06 Ноябрь, 2018, 09:41:57 »

Здравствуйте, semevgen.

К сожалению нет. Дальше продвинуться так и не удалось, я переключился на другие задачи. В схеме ошибок нет, так под linux все прекрасно работает. Если у Вас будут успехи, дайте знать, если не затруднит.
Записан
semevgen
Интересующийся

Сообщений: 3


« Ответ #7 : 09 Ноябрь, 2018, 16:57:52 »

Здравствуйте. Проблема с DMA решилась банально - правильной настройкой GPIO. Две ножки были настроены не правильно:
SD4_CMD
SD4_CLK
Но у меня imx6q
Записан
yanvasilij
Пользователь

Сообщений: 16


« Ответ #8 : 12 Ноябрь, 2018, 08:29:21 »

То есть у Вас драйвер работает практически без изменений? Только GPIO подправили?
Записан
semevgen
Интересующийся

Сообщений: 3


« Ответ #9 : 12 Ноябрь, 2018, 10:00:30 »

Здравствуйте.
Он запускается, то что он работает еще не проверял т.к. микросхема другая, драйвер требует доп. настройки. Я еще не разбирался дальше, пока нет времени.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP © 2002-2024 СВД Встраиваемые Системы.
При использовании материалов сайта ссылка на forum.kpda.ru обязательна.

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines | © Aiwan. Kolobok smiles | Sitemap
Valid XHTML 1.0! Valid CSS!
Сайт СВД ВС

В последний раз google посещал эту страницу 28 Март, 2024, 23:01:46