Использование writel для записи 4-битного адреса памяти в ioremap

Я новичок в программировании ядра, и теперь пытаюсь записать некоторые значения в 32-битный регистр GPIO в драйвере устройства. Ввод / вывод ioremap()-ед по адресу памяти. Проблема в том, что я не знаю как writel()/writeb()/writew() пишет биты по адресам.

Документы продавца говорят, что реестр включен 0xE5200000, Биты, которые я должен написать, - это [0:3] бит и оставить оставшиеся 28 бит ([4:31] биты) как нули.

Это часть кода в драйвере устройства, который я написал до сих пор:

#define TCON_ADDR 0xE250000 // The address as provided by the vendor
static void *TIMER_CON_ADDR;
// I have to map and write to the address when the device is opened
static int on_dev_open(struct inode *inode, struct file *file) {
    unsigned int data;
    TIMER_CON_ADDR = ioremap(TCON_ADDR, 4); // Map the [0:4] bits to TIMER_CON_ADDR
    data = 4; // 0100 in binary
    writel(data, TIMER_CON_ADDR); // Write 0100 to TIMER_CON_ADDR
    return 0;
}

Приведенный выше код может быть просто бредом для всех вас, но я не знаком с write(l|w|b) а также ioremap(),

Итак, мои вопросы:

  1. Я карту [0:4] биты в TIMER_CON_ADDR правильно?
  2. Если нет, то как мне правильно их сопоставить?
  3. После того, как я правильно сопоставил 4 бита, как я могу использовать любой из write(1|w|b) функции для записи битов (0100) в TIMER_CON_ADDR в правильном порядке?
  4. Что значит write(l|w|b) делать под капотом писать биты?
  5. Есть ли какая-либо информация, которую я пропустил / ошибся?

Спасибо за вашу помощь заранее.

1 ответ

Решение
  1. Я карту [0:4] биты в TIMER_CON_ADDR правильно?

нет, ты пишешь 32 бита, writel запись 4 байта, 4 * 8 = 32 бита

  1. Если нет, то как мне правильно их сопоставить?

Нет способа отобразить 4 бита, минимум 8 бит = 1 байт, но если вы работаете с 32-битным регистром, вам нужно отобразить 32 бита = 4 байта. Также не забывайте проверять и обрабатывать ошибки.

  1. После того, как я правильно сопоставил 4 бита, как я могу использовать любой из write(1|w|b) функции для записи битов (0100) в TIMER_CON_ADDR в правильном порядке?

вам нужно использовать readl, ядро ​​полно примеров, просто запустите grep внутри drivers подкаталог дерева исходных текстов ядра Linux. Общая идея чтения / записи:

u32 reg = readl(TIMER_CON_ADDR);
reg &= ~0xfu;
reg |= 4;
writel(reg, TIMER_CON_ADDR);
  1. Что значит write(l|w|b) делать под капотом писать биты?

посмотрите на исходный код, это просто простые функции C, например:

static inline void __raw_writel(u32 value, volatile void __iomem *addr)
{
    *(volatile u32 __force *)addr = value;
}

основная идея - сказать компилятору, что он не должен удалять вашу память для чтения / записи

  1. Есть ли какая-либо информация, которую я пропустил / ошибся?

Прочитайте исходный код подобных драйверов, он уже содержит практически все решения для таких простых драйверов.

Другие вопросы по тегам