Armadilloフォーラム

UART2制御デバイスドライバ開発について

morimayu

2018年2月6日 18時30分

UART2制御デバイスドライバ制御用アドレス(0x30890000~)のレジスタ値の書込みを行いたいのですが、
値が書込みできない状態になっております。読込みはできるが、書込み値が変化しない状態です。
確認したのは、以下の2通りで、UCR1(0x30890080)のUARTENに1をセット
・devmem2コマンド
・関数ioremap_nocache後のioread32

書込み権限がないように思えるのですが、書込み許可を得るための方法をご教授いただけますでしょうか。
それとも、何か別の方法で実現できるのでしょうか?

大変初歩的な質問で申し訳ありません。
よろしくお願いいたします。

コメント

溝渕です。

> UART2制御デバイスドライバ制御用アドレス(0x30890000~)のレジスタ値の書込みを行いたいのですが、
> 値が書込みできない状態になっております。読込みはできるが、書込み値が変化しない状態です。
> 確認したのは、以下の2通りで、UCR1(0x30890080)のUARTENに1をセット
> ・devmem2コマンド
> ・関数ioremap_nocache後のioread32

上記、具体的に何を行ったか教えていただけますか。

Linuxカーネルに変更を加えた場合はパッチ等をもらえるとアドバイスしやすいです。

> 書込み権限がないように思えるのですが、書込み許可を得るための方法をご教授いただけますでしょうか。

特に権限等はありません。標準のUARTドライバでは、次のようにUARTENに1を
セットすることができています。

drivers/tty/serial/imx.c:
441: temp = readl(sport->port.membase + UCR1);
442: temp |= UCR1_UARTEN;
443: writel(temp, sport->port.membase + UCR1);

返信ありがとうございます。
以下について、説明いたします。

> > ・devmem2コマンド
> > ・関数ioremap_nocache後のioread32
>
> 上記、具体的に何を行ったか教えていただけますか。

【devmem2コマンドについて】
https://armadillo.atmark-techno.com/howto/accessing-any-address
こちらを参照してダウンロードしたdevmem2を使用して、
アドレス0x30890080のリードとライト確認をしております。
以下がそのコマンド実行結果です。
=====
root@armadillo:~# /root/devmem2/devmem2 0x30890080 w
/dev/mem opened.
Memory mapped at address 0x76f68000.
Value at address 0x30890080 (0x76f68080): 0x1

root@armadillo:~# /root/devmem2/devmem2 0x30890080 w 0x00
/dev/mem opened.
Memory mapped at address 0x76fd1000.
Value at address 0x30890080 (0x76fd1080): 0x1
Written 0x0; readback 0x1
=====
後半の書込み処理(0)後の読み戻し値が1のままです。
ちなみに、ブートローダ機能(Linux起動前)のmwコマンドでは、書込みできました。

【関数ioremap_nocache後のioread32について】
直接カーネルに組み込まず、ローダブルモジュールとして作成しております。
以下のコードで、iowrite32とwritelを試しております。
=====
#define IOMEM_BASE 0x30890000
#define IOMEM_LEN 0xBC
#define UART_IMX7_REG_UCR1 0x80
#define UCR1_UARTEN (0x1 << 0)

void __iomem *uart;
unsigned int temp;
uart= ioremap_nocache(IOMEM_BASE, IOMEM_LEN);
if (uart == NULL) {
printk(KERN_ERR "%s: I/O ioremap_nocache.\n", DEVICE_NAME);
return -ENODEV;
}
temp = ioread32(uart + UART_IMX7_REG_UCR1);
printk("111 testtest[%x]\n",temp);
iowrite32(temp | UCR1_UARTEN, uart + UART_IMX7_REG_UCR1);
temp = ioread32(uart + UART_IMX7_REG_UCR1);
printk("222 testtest[%x]\n",temp);

unsigned int readvalue = 0;
writel(0x0001, uart + UART_IMX7_REG_UCR1);
readvalue = readl(uart + UART_IMX7_REG_UCR1);
printk("CCC writew readw after[%x]\n",readvalue);
=====
出力結果↓

111 testtest[0]
222 testtest[0]
CCC writew readw after[0]

→どちらも0のまま変化しません。
ローダブルモジュールとして実現したい場合は、何か対応が必要なのでしょうか?

よろしくお願いいたします。

溝渕です。

> 後半の書込み処理(0)後の読み戻し値が1のままです。

恐らくUART2にclockが入っていないためです。

i.MX 7DのUARTドライバでは、デバイスのopen時にclockを入れるため、

root@armadillo:~# cat /dev/ttymxc1 &

のようにopenした状態だとレジスタアクセスが可能になると思います。

UARTドライバでclockを入れているのは以下の場所です。

drivers/tty/serial/imx.c
static int imx_startup(struct uart_port *port)
{
: (省略)
retval = clk_prepare_enable(sport->clk_per);
if (retval)
return retval;
retval = clk_prepare_enable(sport->clk_ipg);
if (retval) {
clk_disable_unprepare(sport->clk_per);
return retval;
}

溝渕様
ありがとうございました。

以下コマンドにて、オープンした後は、レジスタ値への書込みが可能となりました。
>
> root@armadillo:~# cat /dev/ttymxc1 &
>

ちなみに、これらを実行した後は、
再起動後も、そのままレジスタ値への書込みが可能となっております。
電源OFF/ON後も、オープン設定情報を維持したままになるという事でしょうか?

また、元の状態に戻して確認してみようと思ったのですが、
単純に、コンソールで、そのような状態に戻すことは可能でしょうか?

引続き申し訳ございませんが、ご教授いただけますでしょうか。

> ちなみに、これらを実行した後は、
> 再起動後も、そのままレジスタ値への書込みが可能となっております。

再起動を行ったのは、Armadillo-IoT G3Lでしょうか。

再起動の手順を教えていただけますか。

> 電源OFF/ON後も、オープン設定情報を維持したままになるという事でしょうか?

ファイルのオープン/クローズはソフトウェアで(RAM上に)保持しているため、
電源OFFで消えます。

また、UARTのレジスタにアクセスできるかどうかは、本質的にはオープン/ク
ローズではなくclockの状態である点に注意してください。

> また、元の状態に戻して確認してみようと思ったのですが、
> 単純に、コンソールで、そのような状態に戻すことは可能でしょうか?

以下のコマンドの終了方法のことでしょうか。

root@armadillo:~# cat /dev/ttymxc1 &

psコマンドでPIDを調べてkillコマンドを実行したり、fgコマンドでcatをフォ
アグラウンドにしてCtrl-cを押下する等で終了させることができます。

早々と返信ありがとうございます。

> 再起動を行ったのは、Armadillo-IoT G3Lでしょうか。
> 再起動の手順を教えていただけますか。

はい。Armadillo-IoT G3Lの電源をOFF/ONしております。

> また、UARTのレジスタにアクセスできるかどうかは、本質的にはオープン/ク
> ローズではなくclockの状態である点に注意してください。

承知いたしました。
clockが有効な状態が保持されているという事と判断いたしました。

> > また、元の状態に戻して確認してみようと思ったのですが、
> > 単純に、コンソールで、そのような状態に戻すことは可能でしょうか?
>
> 以下のコマンドの終了方法のことでしょうか。
>
>
> root@armadillo:~# cat /dev/ttymxc1 &
>
>
> psコマンドでPIDを調べてkillコマンドを実行したり、fgコマンドでcatをフォ
> アグラウンドにしてCtrl-cを押下する等で終了させることができます。

ttymxc1の終了方法というより、クロックを無効(レジスタに書込み不可)な
状態に戻すことは可能なのでしょうか?
デバイスドライバ内で、クロックを正しく有効にできたか確認したいと思ったために、
このような質問をさせていただきました。

何度も申し訳ありませんが、よろしくお願いいたします。

> clockが有効な状態が保持されているという事と判断いたしました。

Armadillo-IoT G3Lの電源をOFF/ONした場合は、i.MX 7Dがリセットされるので、
clockの状態もリセットされます。

そのため、電源をOFF/ON後もclockが有効な状態が保持されるとは考え難いの
ですが、どのような手順で確認されたかを教えていただけますか。

> ttymxc1の終了方法というより、クロックを無効(レジスタに書込み不可)な
> 状態に戻すことは可能なのでしょうか?

ttymxc1をcloseすることにより、クロックが無効となります。UARTドライバの
該当箇所は次の通りです。

drivers/tty/serial/imx.c:
static void imx_shutdown(struct uart_port *port)
{
:(省略)
clk_disable_unprepare(sport->clk_per);
clk_disable_unprepare(sport->clk_ipg);
}

> デバイスドライバ内で、クロックを正しく有効にできたか確認したいと思ったために、
> このような質問をさせていただきました。

上記「デバイスドライバ」は、自作されたローダブルモジュールでしょうか。

そうであれば、クロックが有効化されているかを確認するより、利用前にクロッ
クを有効化する方がスマートと思います。

すでにLinuxカーネルに組み込まれているドライバは、openしてからcloseする
までの間はクロックが入っているので、クロックを意識せずに利用できると思
います。

> Armadillo-IoT G3Lの電源をOFF/ONした場合は、i.MX 7Dがリセットされるので、
> clockの状態もリセットされます。
> そのため、電源をOFF/ON後もclockが有効な状態が保持されるとは考え難いの
> ですが、どのような手順で確認されたかを教えていただけますか。

電源OFF後、1分程度経過で電源ON
devmem2コマンドを使用してレジスタ値書換実行
以下の通り書換えができている。
=====
root@armadillo:/home/atmark# /root/devmem2/devmem2 0x30390080 w
/dev/mem opened.
Memory mapped at address 0x76f91000.
Value at address 0x30390080 (0x76f91080): 0x0
root@armadillo:/home/atmark# /root/devmem2/devmem2 0x30390080 w 0x01
/dev/mem opened.
Memory mapped at address 0x76f46000.
Value at address 0x30390080 (0x76f46080): 0x0
Written 0x1; readback 0x1
=====
現在は、ローダブルモジュールではなく、コマンドベースで確認しております。
その他設定変更は実施しておりません。
また、UART2インタフェースにも何も接続しておりません。
何か、わかりますでしょうか?

> そうであれば、クロックが有効化されているかを確認するより、利用前にクロッ
> クを有効化する方がスマートと思います。
> すでにLinuxカーネルに組み込まれているドライバは、openしてからcloseする
> までの間はクロックが入っているので、クロックを意識せずに利用できると思
> います。

承知いたしました。
そのように対応したいと思います。

溝渕です。

> 電源OFF後、1分程度経過で電源ON
> devmem2コマンドを使用してレジスタ値書換実行
> 以下の通り書換えができている。
> =====
> root@armadillo:/home/atmark# /root/devmem2/devmem2 0x30390080 w
> /dev/mem opened.
> Memory mapped at address 0x76f91000.
> Value at address 0x30390080 (0x76f91080): 0x0
> root@armadillo:/home/atmark# /root/devmem2/devmem2 0x30390080 w 0x01
> /dev/mem opened.
> Memory mapped at address 0x76f46000.
> Value at address 0x30390080 (0x76f46080): 0x0
> Written 0x1; readback 0x1

"0x30390080"は、SRC(System Reset Controller)のレジスタです。UARTではありません。

各UARTのベースアドレスは次の通りです。
UART2: 0x30890000
UART3: 0x30880000
UART4: 0x30a60000
UART5: 0x30a70000
UART7: 0x30a90000

大変申し訳ありません。
単純に、アドレス指定を間違っておりました。
正しいUARTアドレスで再確認したところ、書込みできませんでした。
電源OFF/ON後は、リセットされているようです。

溝渕様、ありがとうございました。