Амд gpio драйвер что это
990x.top
Простой компьютерный блог для души)
AMD GPIO Driver — что это за драйвер? (AMD GPIO Controller)
Драйвер интерфейса ввода/вывода (чипсет).
Простыми словами — нужен для корректной работы чипсета (набор логики) на материнской плате.
Без драйвера скорее всего тоже все будет работать, но функции будут только базовые, дополнительные — работать не будут. Всякие технологии, заложенные в чипсет, в том числе которые теоретически могут ускорить работу Windows — будут работать только после установки этого драйвера. Например регулировка частоты в Windows (в настройках Электропитания), автоматическое ее снижение в простое — не будет работать без этого драйвера. Также могут не работать порты USB 3.0/3.1 (точнее работать будут, но как версия 2.0) или некоторые технологии ускорения передачи данных по USB.
Также вы можете встретить драйвер с названием AMD GPIO Driver Promontory — это просто версия для чипсетов серии 300, 400 и X570.
Сам драйвер входит в состав пакета AMD Chipset Drivers. Поэтому можно сделать вывод, что он точно нужен для чипсета. Также в пакет входят и другие — AMD PCI driver, PSP driver, AMD SMbus, Promonotory GPIO Driver. И еще — после установки пакета можно перейти в эту папку (в нее распаковываются дрова):
И установить оттуда схему электропитания Ryzen balanced PowerPlan, которая тоже оптимизирует работу ПК.
После корректной установки драйверов у вас в диспетчере появится устройство AMD GPIO Controller:
Кстати, выше еще видим AMD PSP Device — это специальное устройство, которое участвует в защите софта AMD, а также используется в работе антивирусов, защищает некоторые компоненты Windows от вирусов. Аналог Intel Management Engine. PS: быстрый способ открыть диспетчер устройств: зажмите Win + R > введите команду devmgmt.msc > нажмите ОК.
Надеюсь информация оказалась полезной. Удачи и добра, до новых встреч друзья!
Драйвер виртуальных GPIO с контроллером прерываний на базе QEMU ivshmem для Linux
Трудно недооценить роль GPIO, особенно в мире встраиваемых систем ARM. Помимо того, что это крайне популярный материал для всех руководств для начинающих, GPIO обеспечивают способ для управления многими периферийными устройствами, выступают в качестве источника ценных прерываний, или даже могут быть единственным доступным способом общения с миром для SOC.
Основываясь на собственном скромном опыте, могу сказать, что прерывания далеко не самая освященная тема в сообществе Linux. Из-за своих особенностей, а так же сильной привязки к аппаратной части, все обучающие материалы посвященные прерываниям лишены реального и легко воспроизводимого примера. Данный факт мешает пониманию того, что очень часто прерывания и GPIO неразделимы, особенно в области встраиваемого Linux. Многие начинают верить, что GPIO это очень простая и скучная вещь (которая кстати и стала таковой благодаря подсистеме sysfs).
Даже в примере приведенном в LDD3 (драйвер snull) прерывания эмитируются явным вызовом функции парного устройства. Так же имеются примеры в курсах USFCA (http://cs.usfca.edu/
cruse/cs686s08/), но они используют чужое прерывание, тесно связаны с архитектурой x86 и сильно устарели.
Предлагаемое решение способно решить данные проблемы. С точки зрения пространства пользователя и, во многом, во внутренней реализации драйвер неотличим от большинства «реальных», предоставляющих прерывания портов входов/выходов общего назначения. На данный момент драйвер поддерживает прерывания по переднему или заднему фронту и может быть использован как источник прерываний для других устройств.
ivshmem — разделяемая память Inter-VM
Разработано для совместного использования разделяемой памяти (выделенной на хост-платформе через механизм POSIX shared memory API) множественными процессами QEMU с различными гостевыми платформами. Для того чтобы все гостевые платформы имели доступ к области разделяемой памяти, ivshmem моделирует PCI устройство предоставляя доступ к памяти как PCI BAR.
и проанализировал быстродействие в целом.
В настоящей момент, официально, сопровождение ivshmem никто не осуществляет, тем не менее большой вклад в развитие ivshmem вносят сотрудники Red Hat.
ivshmem может послужить основой для симуляции и отладки многих классов устройств.
В данной статье мы рассматриваем виртуальную pci плату ввода/вывода общего назначения (general-purpose input/output, GPIO), которая так же является источником прерываний, и соответствующий драйвер с предоставлением доступа и управления посредством механизма sysfs.
Для разработки и тестирования использовалась виртуальная плата qemu versatilepb (system ARM).
g>> — команды или вывод выполняемые на гостевой системе.
h>> — на основной.
Пример и оригинальный код
Для начала продемонстрируем оригинальный код, основанный на оригинальном коде ( https://github.com/henning-schild/ivshmem-guest-code ), и модифицированном, в последствии, Siro Mugabi.
В принципе этого вполне достаточно для эмуляции GPIO уже в таком виде. И во многих случаях так и поступали, когда достаточно простого состояния входа или записи в выход, использование sysfs и прерываний предполагают небольшую надстройку на I/O mem.
Реализация
Заметим, что /dev/ivshmem0 и ne_ivshmem_shm_guest_usr.c нам более не нужны, вся работа с устройством со стороны гостевой машины из пространства пользователя (user-space) будет осуществляться средствами интерфейса sysfs.
Прежде чем разметить наше устройство в памяти, хотелось бы отметить, что мы просто дублируем схему применяемую в большинстве gpio драйверов.
Во-первых все входа/выхода gpio разделены на порты, как правило по 8, 16, 32 входа. Каждый порт имеет, как минимум, регистр состояния входов (GPIO_DATA), регистр направления, если переключение in/out поддерживается (GPIO_OUTPUT). Далее (если есть поддержка в самом устройстве), регистр состояния прерываний, регистры прерывания по переднему фронту (rising) и заднему фронту (falling) и по уровню (high и low). Аппаратное прерывание, поставляемое главным контроллером прерываний, как правило, одно на весь порт и делится между всеми входами порта.
Примеры существующих реализаций с комментариями
Sitara am335x
более известна в составе платы beaglebone
Разработчик: Texas Instruments
Документация: AM335x Sitara Processors Technical Reference Manual (page 4865)
Соответствующий ему драйвер gpio: linux/drivers/gpio/gpio-omap.c
Соответствующий заголовок: linux/include/linux/platform_data/gpio-omap.h
Количество входов/выходов: 128 (4 gpio порта — по 32 контакта каждый)
Имя регистра | Смещение | Имя в драйвере | Комментарий |
---|---|---|---|
GPIO_IRQSTATUS_0 | 0x02С | OMAP4_GPIO_IRQSTATUS_0 | Состояние прерывания для заданного входа |
GPIO_IRQSTATUS_1 | 0x030 | OMAP4_GPIO_IRQSTATUS_1 | Состояние прерывания для заданного входа |
GPIO_IRQSTATUS_SET_0 | 0x034 | OMAP4_GPIO_IRQSTATUS_SET_0 | Включает прерывания по заданному входу |
GPIO_IRQSTATUS_SET_1 | 0x038 | OMAP4_GPIO_IRQSTATUS_SET_1 | Включает прерывания по заданному входу |
GPIO_IRQSTATUS_CLR_0 | 0x03С | OMAP4_GPIO_IRQSTATUS_CLR_0 | Выключает прерывания по заданному входу |
GPIO_IRQSTATUS_CLR_1 | 0x040 | OMAP4_GPIO_IRQSTATUS_CLR_1 | Выключает прерывания по заданному входу |
GPIO_OE | 0x134 | OMAP4_GPIO_OE | Контролирует состояние вход/выход (in/out) |
GPIO_DATAIN | 0x138 | OMAP4_GPIO_DATAIN | Состояние входа/выхода |
GPIO_DATAOUT | 0x13C | OMAP4_GPIO_DATAOUT | Задание состояния для выходов (low/high) |
GPIO_LEVELDETECT0 | 0x140 | OMAP4_GPIO_LEVELDETECT0 | Включение/выключения прерывания для входа по низкому уровню сигнала |
GPIO_LEVELDETECT1 | 0x144 | OMAP4_GPIO_LEVELDETECT1 | Включение/выключения прерывания для входа по высокому уровню сигнала |
GPIO_RISINGDETECT | 0x148 | OMAP4_GPIO_RISINGDETECT | Включение/выключения прерывания для входа по переднему фронту |
GPIO_FALLINGDETECT | 0x14С | OMAP4_GPIO_FALLINGDETECT | Включение/выключения прерывания для входа по заднему фронту |
GPIO_CLEARDATAOUT | 0x190 | OMAP4_GPIO_CLEARDATAOUT | Переключает соответствующий вход в состояние low |
GPIO_SETDATAOUT | 0x194 | OMAP4_GPIO_SETDATAOUT | Переключает соответствующий вход в состояние high |
Примечание: GPIO_IRQSTATUS_N также используется для IRQ ACK. Управление дребезгом, а так же питанием выходит за рамки данной статьи.
ep9301
Разработчик: Cirrus Logic
Документация: EP9301 User’s Guide (page 523)
Соответствующий ему драйвер gpio: linux/drivers/gpio/gpio-ep93xx.c
Соответствующий заголовок: linux/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h
Количество входов/выходов: 56 (7 портов gpio — по 8 контактов каждый)
Имя регистра | Смещение | Имя в драйвере | Описание |
---|---|---|---|
PADR | 0x00 | EP93XX_GPIO_REG(0x0) | Регистр состояние входов/выходов доступен для чтения записи |
PADDR | 0x10 | EP93XX_GPIO_REG(0x10) | Контролирует состояние вход/выход (in/out) |
GPIOAIntEn | 0x9C | int_en_register_offset[0] | Включает прерывания по заданному входу |
GPIOAIntType1 | 0x90 | int_type1_register_offset[0] | Задает тип прерывания level/edge |
GPIOAIntType2 | 0x94 | int_type2_register_offset[0] | Задает high/rising или low/fallingв зависимости от выбранного типа прерываний |
GPIOAEOI | 0x98 | eoi_register_offset[0] | Регистр для оповещения об обработанном прерывании |
IntStsA | 0xA0 | EP93XX_GPIO_A_INT_STATUS | Регистр состояние прерывания |
Примечание:
Из них для доступны 7 портов по 8, 8, 1, 2, 3, 2, 4 входов/выходов причем регистрами прерываний обладают только первый, второй и пятый порты.
В таблице рассмотрен только порт A.
Одной из особенностей ep9301, является то что тип прерываний both на аппаратном уровне не поддерживается, в драйвере происходит переключение в момент срабатывания прерывания. Другая интересная особенность — на порту F каждый контакт имеет свое собственное прерывание.
Bt848
Последний пример: pci плата Bt848, с gpio.
Разработчик: Intel
Документация: Bt848/848A/849A (page 68)
Соответствующий драйвер gpio: linux/drivers/gpio/gpio-bt8xx.c
Соответствующий заголовок: linux/drivers/media/pci/bt8xx/bt848.h
Количество входов/выходов: 24
Bt848 является платой видеозахвата.
Имя регистра | Смещение | Имя в драйвере | Описание |
---|---|---|---|
BT848_GPIO_OUT_EN | 0x118 | BT848_GPIO_OUT_EN | Регистр состояние входов/выходов доступен для чтения и записи |
BT848_GPIO_DATA | 0x200 | BT848_GPIO_DATA | Контролирует состояние вход/выход (in/out) |
Поддержки прерываний нет. Всего два регистра — состояние и настройка in/out.
Размечаем в памяти наше устройство
Для начала выделим место под данные и управление состоянием.
Пусть устройство обладает 8 входами/выходами общего назначения, тогда:
Имя регистра | Смещение | Имя в драйвере | Описание |
---|---|---|---|
DATA | 0x00 | VIRTUAL_GPIO_DATA | Регистр состояние входов/выходов доступен для чтения и записи |
OUTPUTEN | 0x01 | VIRTUAL_GPIO_OUT_EN | Контролирует состояние вход/выход (in/out) |
Краткая справка по интерфейсу gpio
Состояние выхода при переключении
Необходимо отметить параметр int value в функции direction_output, которая обслуживает файл /sys/class/gpio/gpioN/direction, принимающий значение не только “in”/”out”, но так же и “high”/“low”, значения которых передаются как параметр value (этот простой факт, по какой-то причине, редко упоминается в руководствах для начинающих).
Динамическое присвоение int base и наследие ARCH_NR_GPIOS
Исторически, количество GPIO в ядре было ограничено параметром ARCH_NR_GPIOS, по умолчанию равном 256 и, впоследствии увеличенном до 512 (версия 3.18).
Его смысл достаточно прост, в ядре не может быть больше GPIO чем значение параметра, если планируемое количество было больше чем значение по умолчанию, он переопределялся в соответствующем заголовочном файле платформы.
Причиной такого поведения было определение таблицы описаний GPIO как статической и максимальная величина смещения для каждого порта была ограничена:
Порты GPIO и их смещения были жестко определены в файлах описывающих аппаратную часть конкретного SOC, например:
Начиная с версии 3.19 статический массив был заменен на динамические для каждого порта GPIO, выделяемого в фукнции gpiochip_add().
Тем не менее ARCH_NR_GPIOS все еще здесь (на момент версии 4.7) и используется для поиска смещения при динамическом присваивании base.
Определим следующие функции нашего драйвера
Задать соответствующий контакт как вход:
Чтение текущего состояния контакта:
Задать соответствующий контакт как выход:
Задать состояние выхода:
Функция регистрации нашего драйвера как устройства gpio_chip:
vgread и vgwrite это просто обертки для функций iowrite8 и ioread8:
Передача значения gpiobase в качестве параметра при динамической загрузки модуля
Загрузка и тестирования модуля
DATA выставлен, OUTPUTEN выставлен.
Добавляем прерывания
Разметка регистров прерываний и базовая обработка прерывания
Примечание: В виртуальном драйвере рассматриваются только EDGEDETECT_RISE и EDGEDETECT_FALL.
Добавляем следующие регистры:
Имя регистра | Смещение | Имя в драйвере | Описание |
---|---|---|---|
INTERRUPT_EN | 0x01 | VIRTUAL_GPIO_INT_EN | Включает прерывания по заданному входу |
INTERRUPT_ST | 0x02 | VIRTUAL_GPIO_INT_ST | Регистр состояния прерывания |
INTERRUPT_EOI | 0x03 | VIRTUAL_GPIO_INT_EOI | Регистр для оповещения об обработанном прерывании |
EDGEDETECT_RISE | 0x04 | VIRTUAL_GPIO_RISING | Включение/выключения прерывания для входа по переднему фронту |
EDGEDETECT_FALL | 0x05 | VIRTUAL_GPIO_FALLING | Включение/выключения прерывания для входа по заднему фронту |
LEVELDETECT_HIGH | NC | NOT CONNECTED | |
LEVELDETECT_LOW | NC | NOT CONNECTED |
За обработку прерывания от pci шины отвечает следующая функция, на данный момент её роль заключается всего лишь в уведомлении об обработанном прерывании:
irq_chip и концепция chained_interrupt
На данный момент для нас является главным тот факт, что порты GPIO предоставляющие прерывания каскадируемые от родительского контроллера прерываний обычная практика в дни современного линукса.
Вот почему часть драйвера GPIO отвечающего за прерывания использует irq_chip. Другими словами такой драйвер использует две подсистемы одновременно: gpio_chip и irq_chip.
Беглый взгляд на подсистему irq дает нам следующую картину:
High-Level Interrupt Service Routines (ISRs) — Выполняет всю необходимую работу по обслуживанию прерывания на драйвере устройства. Например, если прерывание используется для индикации доступных для чтения новых данных, работа ISR будет заключаться в копировании данных в соответствующее место.
Interrupt Flow Handling — Данная подсистема отвечает за особенности в реализации обработок прерываний, таких как срабатывание по уровню сигнала (level) или по фронту (edge).
Срабатывание по фронту (Edge-triggering) происходит при определении, что на линии произошло изменение потенциала. Срабатывание по уровню (Level-triggering), определяется как определенное значение потенциала, при этом изменение потенциала не играет роли.
С точки зрения ядра, срабатывание по уровню более сложный случай, так как, после в начале каждого прерывания его необходимо маскировать.
Chip-Level Hardware Encapsulation — Используется для инкапсуляции особенностей реализации работы с аппаратной частью. Данную подсистему можно рассматривать как разновидность “драйвера устройства” для контроллеров прерываний.
Как мы видим ядро берет на себя управление обработкой цепочки прерывания и разницу в реализации типов (по фронту и по уровню), если предоставить соответствующую инфраструктуру.
IRQ Domains
Подсистема IRQ Domain появившееся в патче irq: add irq_domain translation infrastructure позволила отделить локальные для контроллера номера прерываний от номеров прерываний в ядре, предоставив общий массив номеров прерываний. Цитируя официальную документацию: «Сегодня номер IRQ, это просто номер».
До данного обновления аппаратные номера отображались на номерами ядра как 1:1, а каскадирование не поддерживалось. Под аппаратными номерами, понимается локальные для контроллера номера прерывания, которые в нашем случае совпадают с локальными номерами GPIO.
Поскольку наш вектор прерываний достаточно мал, и у нас точно нет интереса в «No map» отображении, наше отображение линейно, фактически номера сопоставляются 1:1 со смещением, разница со старым подходом состоит в том что за присвоение номеров irq и за вычисление смещения отвечает ядро, при этом гарантируется непрерывность выделяемого диапазона.
В каждую функцию интерфейса irq_chip передается указатель на структуру struct irq_data, где irq_data->irq это номер прерывания в ядре linux, a irq_data->hwirq это наш локальный номер прерывания в рамках драйвера. Так же в struct irq_data передается указатель на нашу структуру struct virtual_gpio, что неудивительно.
Связывание irq_chip и gpio_chip
Если бы мы ориентировались на более младшие версии ядра, нам пришлось бы воспользоваться функцией irq_domain_add_simple для отображения наших номер, но с версии 3.15 в патче gpio: add IRQ chip helpers in gpiolib patch нет необходимости напрямую использовать интерфейс IRQ Domain.
Поэтому вместо прямого использования интерфейса IRQ Domain и предоставления инфраструктуры для отображения локальных номеров на глобальные (.map() ops), мы воспользуемся функциями gpiochip_irqchip_add и gpiochip_set_chained_irqchip (зависят от параметра GPIOLIB_IRQCHIP Kconfig).
Прекрасным примером использования и простоты в применении, является драйвер gpio-pl061.
Привязываем наш irq_chip к уже существующему gpio_chip:
handle_edge_irq — это один из встроенных обработчиков потока, который берет на себя управление цепочкой прерывания по фронтам.
Примечание: прерывания по фронтам является наиболее распространенным. Главное отличие от прерываний по уровню заключается как раз в управлении цепочкой, прерывание по уровню маскируется в ядре сразу после получения.
Вызовом функции gpiochip_set_chained_irqchip мы сообщаем ядру, что наш irq_chip использует прерывание от PCI шины и наши прерывания каскадируются от pdev->irq.
Доработаем наш обработчик, чтобы он генерировал прерывания в зависимости от состояния VIRTUAL_GPIO_INT_ST:
irq_find_mapping — вспомогательная функция для трансляции локального номера входа в глобальный номер прерывания.
Собираем все вместе
Прежде всего, отметим, что интерфейс irq_chip нашего драйвера, выглядит следующим образом:
Функция ack() всегда тесна связана с аппаратной спецификой контроллера. Некоторым устройствам, например требуется подтверждение обработки запроса прерывания, прежде чем могут быть обслужены последующие запросы.
В нашем случае в программе vg_get_set – используется достаточно грубая эмуляция регистра eoi. После выставления флага статуса прерывания, в цикле постоянно опрашивается eoi регистр. Когда бит входа уведомления о прерывании выставляется драйвером, происходит обнуление регистра eoi и снятие бита статуса прерывания на входе.
Маскирование и демаскирование производится записью соответствующего значения в регистр INTERRUPT_EN.
irq_type позволяет задать тип триггера — на текущий момент в ядре определены следующие типы:
IRQ_TYPE_NONE — тип не задан
IRQ_TYPE_EDGE_RISING — по переднему фронту
IRQ_TYPE_EDGE_FALLING — по заднему фронту
IRQ_TYPE_EDGE_BOTH — по переднему и заднему фронту
IRQ_TYPE_LEVEL_HIGH — по высокому уровню
IRQ_TYPE_LEVEL_LOW — по низкому уровню
Тестирование и результаты
Для тестирования передачи информации о прерываниях в user space, воспользуемся специально написанной утилитой vg_guest_client. Согласно документации по gpio_sysfs, “Если вы используете select для отслеживания событий, задайте файловый дескриптор (входа) в exceptfds”.
Подготавливаем входы к работе при помощи sysfs:
Примечание: gpio на подавляющем большинстве устройств по умолчанию инициализируются как входы.
Цепочка вызовов от нашего обработчика прерывания к уведомлению pselect:
Заключение
Данная статья подразумевалась мной, как базовая для материала, который сложно, или даже невозможно, представить без какого-либо общего вступления. Qemu в паре с ivshmem послужили отличным и понятным базисом для этой цели. Причиной выбора этой конкретной связки является наличие вменяемой документации и прозрачности использования.
Сама работа с gpio sysfs ничем не отличается для любых устройств с реализованной поддержкой sysfs, любая инструкция по использованию GPIO может быть успешно применена к другому подобному устройству, как и задумывалось при разработке данного интерфейса. Все различия заканчиваются на уровне конкретного драйвера устройства.
Сам драйвер, несмотря на безусловную образовательную ценность, далек от идеала в контексте современного ядра. Для подобного простого драйвера стоит использовать generic-gpio драйвер, созданный, чтобы избежать похожего, повторяющегося кода для mmio gpio драйверов, использование которого, правда, не так очевидно. Обработку прерываний можно было бы сделать более элегантной, а значения смещений регистров лучше хранить в структуре драйвера.
Так же нельзя упускать из виду последние изменения в gpiolib — sysfs gpio теперь является устаревшей. Новый основанный на ioctl интерфейс для gpiolib на пути становления как новый стандарт для общения с GPIO. Но младшие версии еще долго будут использоваться, к тому же никто не собирается на данный момент убирать из ядра старый интерфейс. У меня например до сих пор есть устройства успешно работающие на версии ядра 2.6.34.