RK33999 использует IP-адрес контроллера USB3.0 Synopsys dwc3. Раннюю инициализацию необходимо выполнить в двух модулях. Один из них инициализируется в официально предоставленном Rockchip драйвере, расположенном в файле driver/usb/dwc3/dwc3-rockchip.c. Он в основном инициализирует контент, тесно связанный с ЦП, например. часы, сброс, питание, extcon( Используется для переключения режима USB), другой инициализируется в драйвере, предоставленном Synopsys и расположенном в файле driver/usb/dwc3/core.c. Эта часть тесно связана с контроллером USB3.0, например USB3.0. Адрес внутреннего регистра контроллера, USB3.0 PHY, прерывания и т. д. Только когда оба модуля инициализированы, контроллер USB3.0 может работать нормально. В этом разделе анализируется только часть ранней инициализации драйвера USB.
Ниже представлен узел дерева устройств контроллера USB3.0. Самый внешний совместимый атрибут — «rockchip,rk3399-dwc3», который является атрибутом, определенным Rockchip, включая часы, питание, сброс, extcon и т. д. Extcon (внешние разъемы) — это драйвер USB, используемый для уведомления о состоянии. Он в основном используется для переключения режима USB. Когда PHY получает прерывание и обрабатывает статус USB, он передает его всем драйверам, отслеживающим событие через драйвер extcon. Используйте devm_extcon_register_notifier для регистрации функции обратного вызова, которая отслеживает изменения состояния USB. Атрибутами совместимости внутреннего уровня являются «snps, dwc3», которые определяются синопсисом и в основном связаны с контроллерами USB и PHY. Конкретную информацию об атрибутах узла устройства dwc3 см. в документе Documentation/devicetree/bindings/usb/dwc3.txt.
Поскольку узел дерева устройств usbdrd3_0 является дочерним узлом корневого узла и имеет атрибут совместимости, ядро автоматически преобразует его в Platform_device и затем сопоставляет его с соответствующим драйвером. Однако его дочерний узел usbdrd_dwc3_0 не будет обрабатываться ядром. и будет обработан его родительским узлом, обрабатывающим драйвер usbdrd3_0.
usbdrd3_0: usb0 {
compatible = "rockchip,rk3399-dwc3";
clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
<&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_GRF>;
clock-names = "ref_clk", "suspend_clk", "bus_clk", "grf_clk";
power-domains = <&power RK3399_PD_USB3>; // источник питания
resets = <&cru SRST_A_USB3_OTG0>; // для сброса
reset-names = "usb3-otg";
#address-cells = <2>;
#size-cells = <2>;
ranges;
status = "disabled";
usbdrd_dwc3_0: dwc3@fe800000 {
compatible = "snps,dwc3";
reg = <0x0 0xfe800000 0x0 0x100000>;
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>; // Атрибут прерывания
dr_mode = "otg"; // режим, режим по умолчанию — OTG
phys = <&u2phy0_otg>, <&tcphy0_usb3>;
phy-names = "usb2-phy", "usb3-phy"; // USB PHY
phy_type = "utmi_wide";
/* when set clears the enblslpm in GUSB2PHYCFG,
disabling the suspend signal to the PHY */
snps,dis_enblslpm_quirk;
/* when set, clear the u2_freeclk_exists in GUSB2PHYCFG,
specify that USB2 PHY doesn't provide a free-running PHY clock */
snps,dis-u2-freeclk-exists-quirk;
/* when set core will disable USB2 suspend phy */
snps,dis_u2_susphy_quirk;
/* when set core will change PHY power from P0 to P1/P2/P3 without delay */
snps,dis-del-phy-power-chg-quirk;
/* when set, disable u2mac linestate check during HS transmit */
snps,tx-ipgap-linecheck-dis-quirk;
/* when set, need an extraordinary delay to wait for xHC enter the
Halted state (i.e. HCH in the USBSTS register is '1') */
snps,xhci-slow-suspend-quirk;
/* when set, the xHC use the Evaluate Next TRB(ENT) flag to force
the xHC to pre-fetch the next TRB of a TD */
snps,xhci-trb-ent-quirk;
/* when set, need warm reset on resume */
snps,usb3-warm-reset-on-resume-quirk;
status = "disabled";
};
};
&usbdrd3_0 {
status = "okay";
extcon = <&fusb0>;
};
&i2c4 {
status = "okay";
i2c-scl-rising-time-ns = <160>;
i2c-scl-falling-time-ns = <30>;
clock-frequency = <400000>;
fusb0: fusb30x@22 {
compatible = "fairchild,fusb302";
reg = <0x22>;
pinctrl-names = "default";
pinctrl-0 = <&fusb0_int>;
int-n-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
vbus-5v-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>;
status = "okay";
};
......
};
Драйвер инициализации разделен на две части: одна часть — это инициализация, связанная с процессором, например тактовой частотой, питанием и т. д., которая выполняется драйвером, предоставляемым Rockchip. Другая часть — это инициализация, связанная с контроллером USB, например. Адрес регистрации контроллера USB, прерывание, PHY и т. д. Дополняется официальным драйвером Synopsys. Эти две части анализируются отдельно: сначала анализируется драйвер, предоставленный Rockchip, и, наконец, анализируется официальный драйвер из Synopsys.
Драйвер инициализации USB, предоставляемый Rockchip, — это Platform_driver, атрибут соответствия дерева устройств — «rockchip,rk3399-dwc3», а функция входа — dwc3_rockchip_probe. Разберем процесс выполнения функции входа.
[drivers/usb/dwc3/dwc3-rockchip.c]
static const struct of_device_id rockchip_dwc3_match[] = {
{ .compatible = "rockchip,rk3399-dwc3" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, rockchip_dwc3_match);
static struct platform_driver dwc3_rockchip_driver = {
.probe = dwc3_rockchip_probe,
.remove = dwc3_rockchip_remove,
.driver = {
.name = "rockchip-dwc3",
.of_match_table = rockchip_dwc3_match,
.pm = DEV_PM_OPS,
},
};
module_platform_driver(dwc3_rockchip_driver);
Основная работа функции dwc3_rockchip_probe заключается в следующем:
(1) Получите часы и включите часы.
(2) Преобразуйте дочерний узел usbdrd_dwc3_0 в Platform_device и сохраните указатель структуры частных данных dwc3 драйвера устройства, соответствующего дочернему узлу. Если указатель структуры dwc3 не может быть получен, будет возвращен EPROBE_DEFER, и ядро выполнит команду. dwc3_rockchip_probe позже.
(3) Обработайте атрибут extcon и установите функцию обратного вызова для устройства — dwc3_rockchip_device_notifier. Функция обратного вызова хоста — dwc3_rockchip_host_notifier. Функция обратного вызова выполняется через рабочую очередь otg_work.
(4) Асинхронно выполнить функцию dwc3_rockchip_async_probe, в основном регистрируя обратные вызовы уведомлений, устанавливая мощность и т. д.
dwc3_rockchip_probe
devm_kzalloc // выделить структуру Структурная память dwc3_rockchip
of_clk_get_parent_count // Получите количество источников синхронизации, на которые ссылается дерево устройств.
rockchip->num_clocks = count // Количество сохраненных источников синхронизации
devm_kcalloc // Выделить структуры num_clocks клк*указатель
platform_set_drvdata // Сохранить указатель dwc3_rockchip
clk = of_clk_get(np, i) // Получить часы
clk_prepare_enable // включить часы
rockchip->clks[i] = clk // Сохранить указатель структуры часов
pm_runtime_set_active // источник связанные с управлением питанием
pm_runtime_enable
pm_runtime_get_sync
devm_reset_control_get(dev, "usb3-otg") // Получить для сбросаизreset_control
of_get_child_by_name(np, "dwc3") // Получить device_node дочернего узла dwc3.
/* Пройдите все дочерние узлы указанного узла и преобразуйте составные требования в Platform_device, то есть дочерние узлы usbdrd3_0.
usbdrd_dwc3_0 преобразован в Platform_device */
of_platform_populate
// Инициализируйте рабочую очередь. Функция входа в рабочую очередь — dwc3_rockchip_otg_extcon_evt_work, которая используется для переключения режима USB.
INIT_WORK(&rockchip->otg_work, dwc3_rockchip_otg_extcon_evt_work)
of_find_device_by_node // Получите указатель Platform_device дочернего узла, которым является узел usbdrd_dwc3_0.
/* Получите указатель личных данных драйвера дочернего узла, то есть указатель структуры dwc3. Если получение не удалось, возвращается EPROBE_DEFER.
Ядро позже снова выполнит dwc3_rockchip_probe. */
rockchip->dwc = platform_get_drvdata
// Если это режим хоста и OTG, получите структуру хост-контроллера. указатель usb_hcd
rockchip->hcd = dev_get_drvdata(&rockchip->dwc->xhci->dev)
// Обработка атрибутов extcon
dwc3_rockchip_get_extcon_dev
// Определите, есть ли атрибут extcon в узле usbdrd3_0.
device_property_read_bool(dev, "extcon")
extcon_get_edev_by_phandle // Получить структуру по указанному узлу дерева устройств extcon_dev
// Установить функцию обратного вызова уведомлений
rockchip->device_nb.notifier_call = dwc3_rockchip_device_notifier;
rockchip->host_nb.notifier_call = dwc3_rockchip_host_notifier;
rockchip->edev = edev;
// Асинхронное выполнение функции dwc3_rockchip_async_probe по существу выполняется через рабочую очередь system_unbound_wq.
async_schedule(dwc3_rockchip_async_probe, rockchip)
Функция обратного вызова extcon следующая. За исключением различных параметров, функции обратного вызова устройства и хоста одинаковы. Все они планируют рабочую очередь otg_work для обработки рабочей задачи через Schedule_work. Функция рабочей задачи — dwc3_rockchip_otg_extcon_evt_work. что в основном связано с переключением режима USB. Подробный анализ драйвера extcon будет сделан позже.
dwc3_rockchip_device_notifier
// Получите структуру dwc3_rockchip
rockchip = container_of(nb, struct dwc3_rockchip, device_nb)
// Когда USB не находится в приостановленном состоянии, запланируйте рабочую очередь otg_work
schedule_work(&rockchip->otg_work)
dwc3_rockchip_host_notifier
// Получите структуру dwc3_rockchip
rockchip = container_of(nb, struct dwc3_rockchip, host_nb)
// Когда USB не находится в приостановленном состоянии, запланируйте рабочую очередь otg_work
schedule_work(&rockchip->otg_work)
dwc3_rockchip_async_probe — это асинхронно выполняемая функция, которая по существу выполняется через рабочую очередь system_unbound_wq. Основная работа — зарегистрировать функцию обратного вызова уведомлений extcon, включить USB PHY и создать группу файлов атрибутов отладки.
dwc3_rockchip_async_probe
// Узнайте, имеет ли устройство атрибут «needs-reset-on-resume», и верните true, если да.
device_property_read_bool(dev, "needs-reset-on-resume")
devm_extcon_register_notifier(..., &rockchip->device_nb) // Зарегистрируйте функцию обратного вызова уведомлений extcon устройства.
devm_extcon_register_notifier(..., &rockchip->host_nb) // Зарегистрируйте функцию обратного вызова уведомления extcon хоста
// Если extcon существует или dr_mode равен USB_DR_MODE_OTG,Затем приступайте к поиску настройки, связанные с питанием
pm_runtime_set_autosuspend_delay // Установите время задержки автоприостановки на 500 миллисекунд.
pm_runtime_allow // Открыть ленту источников питанияуправлять
pm_runtime_suspend // Войти в состояние ожидания
// Планирование рабочей очереди otg_work, функция выполнения — dwc3_rockchip_otg_extcon_evt_work
schedule_work(&rockchip->otg_work)
// Если extcon не существует и dr_mode не USB_DR_MODE_OTG, это означает, что USB-контроллер не выполняет переключение режимов.
// Это может быть только режим хоста или режим устройства.
// Установите для подключения значение true, чтобы предотвратить USB от PM. Выполните сброс контроллера DWC3, когда состояние приостановки переходит в возобновление.
// Сброс режима хоста приводит к повторному перечислению устройства
rockchip->connected = true
// Если на устройстве не установлен атрибут «needs-reset-on-resume», а процессор — «rockchip,rk3399» и
// dr_modeдляUSB_DR_MODE_HOST // USB3.0 PHY RK3399 имеет тип C. PHY, помимо включения в dwc3_core_init(), также должен
// Включите здесь,предотвратитьUSBустройство, подключенное кDWC3Переключатель состояния пост-контроллера хостадляsuspendзакрыто, когдаPHYизисточник питания
phy_power_on(dwc->usb2_generic_phy)
phy_power_on(dwc->usb3_generic_phy)
rockchip->is_phy_on = true
// Создайте группу файлов свойств отладки.
sysfs_create_group(&dev->kobj, &dwc3_rockchip_attr_group)
Struct dwc3 — это базовая структура данных контроллера USB3.0 OTG, и вся работа вращается вокруг этой структуры данных. Значение этой структуры данных показано в коде ниже, за исключением некоторых менее важных элементов.
[drivers/usb/dwc3/core.h]
struct dwc3 {
// Запрос управления USB для конечной точки 0, То есть запрос на установку, полученный ep0out, например Get Descriptor, Set Интерфейс и другие команды
struct usb_ctrlrequest *ctrl_req;
struct dwc3_trb *ep0_trb; // Конечная точка 0 контролирует передаваемый trb
// Выделяется с помощью функции kzalloc, Не функция dma_alloc_coherent
// Get Статус и набор Стандартные запросы, такие как Sel, должны использовать предварительно выделенный буфер в качестве полезной нагрузки передачи USB.
void *ep0_bounce; // отскок конечной точки 0 buffer
void *zlp_buf; // request->zeroиспользуется при настройке
// В основном используется для функции пробуждения во время сна (гибернации), То есть сохранение информации о регистрах контроллера в памяти во время сна.
void *scratchbuf; // RK3399 контроллер dwc3 не используется
u8 *setup_buf; // Используется при обработке стандартных запросов USB.
dma_addr_t ctrl_req_addr; // dma-адрес ctrl_req
dma_addr_t ep0_trb_addr; // dma-адрес ep0_trb
dma_addr_t ep0_bounce_addr; // Адрес dma ep0_bounce
dma_addr_t scratch_addr; // dma-адрес Scratchbuf
struct dwc3_request ep0_usb_req; // dummy req used while handling STD USB requests
struct device *dev;
struct platform_device *xhci; // Структура хост-контроллера USB данных
struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; // Ресурсы хост-контроллера USB
// Буфер событий, контроллер сохранит переданную информацию о событии в этот буфер, и она будет равномерно обработана программным обеспечением.
struct dwc3_event_buffer *ev_buf;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; // конечная точкаструктура Массив указателей на данные длиной 32
struct usb_gadget gadget; // структура, используемая, когда USB-контроллер находится в режиме устройства данных
struct usb_gadget_driver *gadget_driver; // Драйвер, используемый в режиме устройства, определяется конкретным подходящим устройством.
void __iomem *regs; // Зарегистрировать базовый адрес
size_t regs_size; // Длина адреса регистрации
enum usb_dr_mode dr_mode; // Тип перечисления режима USB-контроллера
u32 fladj; // frame length adjustment
u32 irq_gadget; // Номер прерывания, когда USB находится в режиме устройства
u32 nr_scratch; // scratch Количество буферов, не используется
u32 u1u2; // only used on revisions <1.83a for workaround
u32 maximum_speed; // максимальная скорость
u32 revision; // Номер версии в реестре USB-контроллера
enum dwc3_ep0_next ep0_next_event; // hold the next expected event
enum dwc3_ep0_state ep0state; // Статус конечной точки 0
enum dwc3_link_state link_state; // статус ссылки
u16 isoch_delay; // wValue from Set Isochronous Delay request
u16 u2sel; // parameter from Set SEL request
u16 u2pel; // parameter from Set SEL request
u8 u1sel; // parameter from Set SEL request
u8 u1pel; // parameter from Set SEL request
u8 speed; // device speed (super, high, full, low)
u8 num_out_eps; // Количество конечных точек вывода
u8 num_in_eps; // Введите количество конечных точек
void *mem; // Указывает на начальный адрес памяти структуры. DWC3 имеет требования к выравниванию. Первые байты памяти не могут использоваться.
struct dwc3_hwparams hwparams; // Кэш регистров
struct dentry *root;
struct debugfs_regset32 *regset;
u8 test_mode;
u8 test_mode_nr;
u8 lpm_nyet_threshold;
u8 hird_threshold;
u32 grxthrcfg[2];
u32 gtxthrcfg[2];
};
Структура struct dwc3 очень сложна, внутри нее встроено множество важных структур данных. Взаимосвязь между ними можно кратко проиллюстрировать на следующем рисунке. xhci указывает на структуру данных, когда USB находится в режиме хоста. Он представлен драйвером в режиме хоста — Platform_driver. Эти два значения совпадают по имени устройства xhci-hcd. Это будет подробно объяснено при анализе драйвера хоста. .
Структуры данных, когда USB находится в режиме устройства, — это usb_gadget и gadget_driver; usb_gadget внутренне содержит структуры данных usb_udc и usb_gadget_ops. usb_gadget_ops — это набор функций работы оборудования контроллера USB, указывающий на dwc3_gadget_ops, который является драйвером конкретного устройства и должен быть указан; Сопоставляется в соответствии с типом устройства. Определяется, устанавливается при успешном сопоставлении устройств. eps[32] — это массив указателей, в котором сохраняются указатели всех структур конечных точек dwc3_ep в режиме устройства. Каждая конечная точка соответствует структуре данных dwc3_ep. Набор рабочих функций конечной точки 0 указывает на dwc3_gadget_ep0_ops, а набор рабочих функций других. конечные точки указывают на dwc3_gadget_ep_ops.
dwc3_rockchip_probe преобразует узел дерева устройств usbdrd_dwc3_0 в Platform_device, а затем сопоставляет его с dwc3_driver. После успешного сопоставления будет выполнена функция dwc3_probe.
[drivers/usb/dwc3/core.c]
static const struct of_device_id of_dwc3_match[] = {
{
.compatible = "snps,dwc3"
},
{
.compatible = "synopsys,dwc3"
},
{ },
};
static struct platform_driver dwc3_driver = {
.probe = dwc3_probe,
.remove = dwc3_remove,
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
.pm = &dwc3_dev_pm_ops,
},
};
module_platform_driver(dwc3_driver);
dwc3_probe завершает инициализацию контроллера dwc3 USB3.0. Основное содержание следующее:
(1) Выделите структуру данных драйвера dwc3 и выровняйте ее по 16 байтам.
(2) Получение и обработка ресурсов, таких как ресурсы регистра, параметры, максимальная скорость, dr_mode и другие атрибуты.
(3) Выделите согласованный буфер DMA dwc3_event_buffer, DMA передает события контроллера USB в dwc3_event_buffer, а затем обрабатывает ЦП.
(4) Инициализация ядра и инициализация режима USB, подробный анализ позже.
(5) Инициализируйте файл отладки, как показано на рисунке ниже. Пользователи могут получать информацию о USB-контроллере и управлять USB-контроллером в пользовательском пространстве.
dwc3_probe
mem = devm_kzalloc // Выделить структуру dwc3
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1) // Выровнено по 16 байтам
dwc->mem = mem // Сохранить выделенный адрес памяти
// Установите 64-битную маску DMA. Устройство не обязательно сможет выполнять операции DMA для всех адресов памяти. В этом случае ее следует установить.
// Маска адреса DMA, dma_mask — это диапазон, к которому может обращаться DMA устройства, а coherent_dma_mask используется для маски DMA сопоставления согласованности.
dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))
platform_get_resource // Получить ресурсы с адресом регистрации
devm_ioremap_resource // Сопоставить адреса регистров, но не включать регистры xHCI, регистры xHCI обрабатываются его драйвером.
lpm_nyet_threshold = 0xff /* default to highest possible threshold */
tx_de_emphasis = 1 /* default to -3.5dB de-emphasis */
/* default to assert utmi_sleep_n and use maximum allowed HIRD
threshold value of 0b1100 */
hird_threshold = 12
usb_get_maximum_speed // Получите максимальную скорость
usb_get_dr_mode // Получить dr_mode
...... // Чтобы получить некоторые свойства dwc3, обратитесь к узлу дерева устройств и документу dwc3.txt.
// Если максимальная_скорость равна USB_SPEED_UNKNOWN, установите значение USB_SPEED_SUPER.
dwc->maximum_speed = USB_SPEED_SUPER;
platform_set_drvdata // Установите личные данные Platform_device
dwc3_cache_hwparams // Прочитайте параметры, сохраненные во внутреннем регистре контроллера dwc3, и сохраните их в hwparams dwc3.
dwc3_core_get_phy // Получить dwc3 USB-контроллер фи
dwc3_alloc_event_buffers // Выделить буфер событий длиной DWC3_EVENT_BUFFERS_SIZE=4096.
dwc3_alloc_one_event_buffer
devm_kzalloc // Сначала выделите структуру dwc3_event_buffer, которая управляет буфером событий.
evt->dwc = dwc // Сохранить указатель структуры dwc3
evt->length = length // Сохранить длину буфера
// Выделить согласованный буфер DMA,buf сохраняет виртуальный адрес,&evt->dmaСохранить физический адрес
evt->buf = dma_alloc_coherent(dwc->dev, length, &evt->dma, GFP_KERNEL)
dwc3_alloc_scratch_buffers // Выделить рабочий буфер, не используемый
dwc->scratchbuf = kmalloc_array // Назначить номер nr_scratch * Память DWC3_SCRATCHBUF_SIZE
dwc3_core_init // Инициализация ядра
dwc3_core_init_mode // В соответствии с режимом, соответствующим инициализации dr_mode, существуют режимы устройства, хоста и otg.
dwc3_debugfs_init // Инициализация, связанная с атрибутом отладки dwc3
debugfs_create_dir // Создайте каталог отладки/sys/kernel/debug/fe800000.dwc3(fe900000.dwc3)
kzalloc // Выделить структуру debugfs_regset32
dwc->regset->regs = dwc3_regs // Сохраните регистры, которые необходимо сбросить.
debugfs_create_regset32("regdump", ...) // Создайте файл отладки, который может выгружать значения регистров.
// Чтобы создать файл отладки, способный переключать режимы, необходимо включить опцию CONFIG_USB_DWC3_DUAL_ROLE.
debugfs_create_file("mode", ...., &dwc3_mode_fops)
// Чтобы создать файл отладки в режиме отладки, необходимо включить опцию CONFIG_USB_DWC3_DUAL_ROLE или CONFIG_USB_DWC3_GADGET.
debugfs_create_file("testmode", ..., &dwc3_testmode_fops)
// Чтобы создать файл отладки link_state, вам необходимо включить опцию CONFIG_USB_DWC3_DUAL_ROLE или CONFIG_USB_DWC3_GADGET.
debugfs_create_file("link_state", ..., &dwc3_link_state_fops)
// Чтобы создать файл отладки конечной точки, вам необходимо включить опцию CONFIG_USB_DWC3_DUAL_ROLE или CONFIG_USB_DWC3_GADGET.
dwc3_debugfs_create_endpoint_dirs(dwc, root)
dwc3_debugfs_create_endpoint_dir // Цикл для создания файлов отладки входной конечной точки
debugfs_create_dir // Создать каталог
dwc3_debugfs_create_endpoint_files // Создать файл
dwc3_debugfs_create_endpoint_dir // Цикл для создания файлов отладки конечной точки вывода.
debugfs_create_dir // Создать каталог
dwc3_debugfs_create_endpoint_files // Создать файл
Основная задача dwc3_core_init — инициализация оборудования USB-контроллера. Основной процесс выглядит следующим образом:
(1) Получите версию IP-адреса USB-контроллера для облегчения последующей настройки. Между различными IP-версиями USB-контроллера существуют различия. Запишите номер версии ядра Linux в реестр USB-контроллера, чтобы обнаружить ошибки в определенных версиях.
(2) В соответствии с dr_mode выберите, нужно ли сбрасывать USB-контроллер.
(3) Получите количество конечных точек USB-контроллера из кэша регистров USB-контроллера. Конечные точки здесь представляют собой набор ресурсов.
(4) Создайте Scratch_buffers и используйте потоковое сопоставление DMA. USB-контроллер RK3399 не использует эту функцию.
dwc3_core_init dwc3_readl(dwc->regs, DWC3_GSNPSID) // GetGlobal SNPS ID Содержание в реестре /* Write Linux Version Code to our GUID register so it's easy to figure out which kernel version a bug was found. */ dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE) dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE) dwc3_soft_reset // Программный сброс USB-контроллера // Контроллер USB будет сброшен только в том случае, если он находится в режиме устройства, режиме хоста или dr_mode — это режим OTG. // И реестр не сбрасывается при настройке в режиме хоста и будет сброшен последующими драйверами. dwc3_readl(dwc->regs, DWC3_GCTL) // Чтение глобального управляющего регистра USB timeout = jiffies + msecs_to_jiffies(500) // Установите тайм-аут ожидания сброса на 500 миллисекунд. dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST) // Программный сброс, бит очищается аппаратно, если сброс успешен. // Прочитайте в цикле регистр DWC3_DCTL, чтобы определить, успешен ли сброс. dwc3_readl(dwc->regs, DWC3_DCTL) time_after(jiffies, timeout) // Определить, истек ли период тайм-аута cpu_relax() // барьер памяти asm volatile("yield" ::: "memory") // yield:Указывает текущее выполнениеиз Темы не имеют значения,можно отключить,memory:барьер памяти asm volatile("yield" ::: "memory") // aarch64 dwc3_core_soft_reset // ИнициализироватьPHY dwc3_phy_setup // Configure USB PHY Interface of DWC3 Core dwc3_core_num_eps // Получить количество конечных точек dwc->num_in_eps = DWC3_NUM_IN_EPS(parms) // Введите количество конечных точек dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps // Количество конечных точек вывода dwc3_setup_scratch_buffers // не используется // При потоковом сопоставлении DMA данные могут перемещаться в обоих направлениях, то есть могут передаваться на устройство и обратно, при этом возвращается физический адрес. scratch_addr = dma_map_single(..., DMA_BIDIRECTIONAL); dwc->scratch_addr = scratch_addr // Сохранить физический адрес param = lower_32_bits(scratch_addr) // Получите младшие 32 бита физического адреса. dwc3_send_gadget_generic_command(..., DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, ...) // Запишите младший 32-битный адрес в регистр в качестве параметра команды, который будет использоваться при выполнении команды. dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param) // Команда записи, DWC3_DGCMD_CMDACT: активировать команду, начать выполнение команды после установки // DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:Set Scratchpad Buffer Array Address Lo dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT)
Драйвер режима хоста USB-контроллера и драйвер режима устройства представляют собой два набора платформ драйверов и не могут использоваться универсально. Таким образом, при инициализации драйвера dwc3 соответствующий драйвер режима USB будет инициализирован в соответствии с параметром dr_mode, который указан в дереве устройств. Функция dwc3_core_init_mode используется для установки драйвера режима контроллера USB. Основная работа этой функции заключается в следующем:
dwc3_core_init_mode // Инициализируйте соответствующий драйвер в соответствии с dr_mode. // dwc->dr_mode == USB_DR_MODE_PERIPHERAL dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE) // Переведите USB-контроллер в режим устройства dwc3_gadget_init // Инициализировать драйвер устройства // dwc->dr_mode == USB_DR_MODE_HOST dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST) // Установите USB-контроллер в режим хоста dwc3_host_init // Инициализировать драйвер хоста // dwc->dr_mode == USB_DR_MODE_OTG // Установите USB-контроллер в режим OTG. USB-контроллер в режиме OTG может быть хостом или устройством, а за переключение отвечает extcon. dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG) dwc3_host_init // Инициализировать драйвер хоста dwc3_gadget_init // Инициализировать драйвер устройства
Конкретный процесс инициализации драйвера хоста и драйвера устройства будет подробно проанализирован позже, когда мы будем говорить о хосте и устройстве.