LINUX.ORG.RU

AT91 + device tree + kernel driver

 , ,


2

2

Наконец дошли руки доковырять борду от стартеркита c at91sam9m10g45ek и портануть на нее распоследнее ядро.
Проблема возникла с фпга, которая сидит на smc шине: по неведомым причинам в моей ревизии платы вместо внешнего тактового генератора используется сигнал с at91 с pck0.
С помощью записи регистров AT91 напрямую удалось запустить клок на фпга и поморгать диодом, поэтому сейчас хочется причесать все это дело.
В ядре 3.19+ АТ91 был неплохо переработан, а вся система клоков заново расписана в device tree, поэтому решил использовать ее. Ок, создаем ноду:

fpga0: fpga@0x10000000 {
    compatible = "sk,at91-xc6slx";
    status = "okay";
    clocks = <&pck0>;
    clock-names = "mclk";
};
Затем в драйвере делаем следующее:
mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(mclk)) {
	dev_err(&pdev->dev, "Failed to get MCLK\n");
	return ret;
}
	
unsigned int mclk_rate = clk_get_rate(mclk);
if (!mclk_rate) {
	dev_err(&pdev->dev, "Invalid slow clock rate\n");
	return -EINVAL;
}

ret = clk_prepare_enable(mclk);
if (ret) {
	dev_err(&pdev->dev, "Could not enable mclk clock\n");
	return ret;
}
И тут возникает 2 вопроса:
1) pck0 может иметь несколько клок соурсов или делителей, хз как они правильно называются. Определены в родительской ноде:
prog: progck {
    compatible = "atmel,at91sam9g45-clk-programmable";
    #address-cells = <1>;
    #size-cells = <0>;
    interrupt-parent = <&pmc>;
    clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>;

    prog0: prog0 {
        #clock-cells = <0>;
        reg = <0>;
        interrupts = <AT91_PMC_PCKRDY(0)>;
    };

    prog1: prog1 {
        #clock-cells = <0>;
        reg = <1>;
        interrupts = <AT91_PMC_PCKRDY(1)>;
    };
};
Собственно вопрос, как мне переключить или выбрать нужную частоту: хочется получить 133мгц, это mck. В приведенном коде выше я получаю частоту 32кгц, что не устраивает.
2) Кроме того для того, чтобы клок доходил до фпга, необходимо выставить ножку в аутпут режим и periph b. Я так понимаю, это можно сделать с помощью
fpga0 {
    pinctrl_fpga_clock: fpga-clk {
        atmel,pins = <AT91_PIOE 0  AT91_PERIPH_B AT91_PINCTRL_PULL_UP>;
    };
};
...
fpga0: fpga@0x10000000 {
    compatible = "sk,at91-xc6slx";
    status = "okay";
    clocks = <&pck0>;
    clock-names = "mclk";
    pinctrl-0 = <&pinctrl_fpga_clock>;
};
Что я еще упускаю? И накидайте, пожалуйста, линков на документацию по dts и примерам работы с ним. Ничего толкового и консистентного найти не удалось, увы. ncrmnt в отпуске, поэтому прошу всех неравнодушных помочь.

Deleted

Привет тебе из отпусков. DeviceTree документирован на букву Х, причем Х не значит «хорошо». Сколько я с ним уже копался, экспертом себя тоже назвать не могу. Клоки, как и прерывания в каждой борде задаются по разному, в некоторых особенно запущенных случаях (versatile express) уровень наркомании просто зашкаливает.

По твоему вопросу: Можешь показать ноду, которая описывает pck0 ? В теории там должен выбираться пэрент, из которого pck0 берет клок. Могу ошибаться.

ncrmnt ★★★★★
()
Ответ на: комментарий от ncrmnt

Вот из-за того, что нет какого-то общего стандарта, я путаюсь и пугаюсь.

prog: progck {
					compatible = "atmel,at91sam9g45-clk-programmable";
					#address-cells = <1>;
					#size-cells = <0>;
					interrupt-parent = <&pmc>;
					clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>;

					prog0: prog0 {
						#clock-cells = <0>;
						reg = <0>;
						interrupts = <AT91_PMC_PCKRDY(0)>;
					};

					prog1: prog1 {
						#clock-cells = <0>;
						reg = <1>;
						interrupts = <AT91_PMC_PCKRDY(1)>;
					};
				};

				systemck {
					compatible = "atmel,at91rm9200-clk-system";
					#address-cells = <1>;
					#size-cells = <0>;

					ddrck: ddrck {
						#clock-cells = <0>;
						reg = <2>;
						clocks = <&mck>;
					};

					uhpck: uhpck {
						#clock-cells = <0>;
						reg = <6>;
						clocks = <&usb>;
					};

					pck0: pck0 {
						#clock-cells = <0>;
						reg = <8>;
						clocks = <&prog0>;
					};

					pck1: pck1 {
						#clock-cells = <0>;
						reg = <9>;
						clocks = <&prog1>;
					};
				};
То есть pck0 наследуется от prog, который может принимать значения clk32k, main и тд. И вот хотелось бы выставиться на mck.
На канале ат91 подсказали, что на это можно забить и сделать так:
	mclk = devm_clk_get(&pdev->dev, "mclk");
	if (IS_ERR(mclk)) {
		dev_err(&pdev->dev, "Failed to get MCLK\n");
		return ret;
	}
		
	unsigned int mclk_rate = clk_get_rate(mclk);
	if (!mclk_rate) {
		dev_err(&pdev->dev, "Invalid slow clock rate\n");
		return -EINVAL;
	}
	ret = clk_set_rate(mclk, 133000000L);
В этом случае подсистема сама выставит и настроит клок на ближайшее возможное значение. Проверить пока не удалось.
Алсо, раз уж ты тут: что насчет pinctl для атмела? Если я определю пин как periph b и привяжу его к ноде фпга, применится ли это автоматически драйвером pinctl или нужно инициализировать его вручную в драйвере?

Deleted
()
Ответ на: комментарий от imb

Спасибо, это видел, но к сожалению в пдфке нет ответа на мой вопрос. Ответы частично разбросаны по ./Documentation, но именно что частично разбросаны.

Deleted
()
Ответ на: комментарий от ncrmnt

Вроде получилось сделать так, как хотелось в приведенных кусках: частота и клок включаются в драйвере через clk_* функции, а пин выставляется в девайстри.

Deleted
()
Ответ на: комментарий от Deleted

По клокам иногда полезно смотреть что у нас получилось тут

cat /sys/kernel/debug/clk/clk_summary
и остальной контент /sys/kernel/debug/clk

Кое-что по device tree документировано тут http://lxr.free-electrons.com/source/Documentation/devicetree/

Неплохой туториал по dts для чайников тут http://xillybus.com/tutorials/device-tree-zynq-1

alx777 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.