\documentclass[obeyspaces,spaces,hyphens]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{setspace}

\mode<presentation>
\usetheme{Bootlin}

\title{Linux kernel: consolidation in ARM architecture support}
\authors{Thomas Petazzoni}
\institute{Bootlin}

%% TODO
%%
%% Talk about the concept of device tree bindings

\usepackage{hyperref}

\begin{document}

\begin{frame}{Libre Software Meeting 2012}
  \begin{columns}[c]
   \column{0.6\textwidth}
     \huge
     Linux kernel: consolidation in the ARM architecture support\\
     \vspace{1cm}
     \normalsize
     Thomas Petazzoni\\
     {\bf Bootlin}\\
     {\em thomas.petazzoni@bootlin.com}
     \column{0.4\textwidth}
     \includegraphics[width=\textwidth]{ARM-Cortex-A15-chip.jpg}
   \end{columns}
\end{frame}

\begin{frame}{Thomas Petazzoni}
  \begin{itemize}
  \item {\bf Embedded Linux engineer and trainer at Bootlin}
    since 2008
    \begin{itemize}
    \item {\bf Embedded Linux development}: kernel and driver
      development, system integration, boot time and power consumption
      optimization, consulting, etc.
    \item {\bf Embedded Linux training}, Linux driver development
      training and Android system development training, with materials
      freely available under a Creative Commons license.
    \item \url{https://www.bootlin.com}
    \end{itemize}
  \item {\bf Major contributor to Buildroot}, an open-source, simple
    and fast embedded Linux build system
  \item Working on {\bf mainlining support for the Marvell Armada
      370 and Armada XP ARM SoCs}
  \item {\bf Speaker} at Embedded Linux Conference, Embedded Linux
    Conference Europe, FOSDEM, Libre Software Meeting, etc.
  \item Living in Toulouse, south west of France
  \end{itemize}
\end{frame}

\begin{frame}{Agenda}
  \Large
  \begin{itemize}
  \item The initial complaint
  \item The ARM ``\emph{problem(s)}''
  \item The solutions
    \begin{itemize}
    \large
    \item Maintainer
    \item Device Tree
    \item Clock framework
    \item Pinctrl subsystem
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Someone complains...}
  \begin{spacing}{2.0}
    \begin{center}
      \emph{\Huge{Gaah. Guys, this whole ARM thing is a f*cking pain in the ass.}}\\
      \pause
      \vspace{1.5cm}
      \Large{Linus Torvalds -- 17 March 2011}
    \end{center}
  \end{spacing}
\end{frame}

\begin{frame}{...and suggests to do something}
  \begin{spacing}{2.0}
    \begin{center}
      \emph{\Huge{ Somebody in the ARM community really needs to step up
          and tell people to stop dicking around.}}\\
    \end{center}
  \end{spacing}
\end{frame}

\begin{frame}{ARM Holdings}

  {\em ARM Holdings} is a British company that designs processor
  cores.
  \begin{itemize}
  \item They define instruction sets, and design cores implementing
    those instruction sets, memory management units, caches, etc.
  \item Examples of cores: ARM926EJ-S, Cortex-A8, Cortex-A9,
    Cortex-M3, etc.
  \item {\em ARM} does not produce processors that people can buy
  \end{itemize}
\end{frame}

\begin{frame}{Silicon vendors}
  A number of {\em silicon-vendors} buy those designs, and
  create {\em System-on-chip} combining a ARM core and a number of
  peripherals
  \begin{itemize}
  \item Peripherals are typically UARTs, bus controllers (USB, SPI,
    I2C, PCI, etc.), Ethernet controllers, ADCs, CAN controllers,
    video/audio encoding/decoding, graphics (2D, 3D), etc.
  \item Silicon vendors combine different sets of peripherals to
    address different markets (industrial, automotive, consumer,
    etc.)
  \item Examples: Texas Instruments OMAP4 (dual Cortex-A9), Atmel
    AT91SAM9M10 (926EJ-S), Freescale i.MX 6 (from 1 to 4 Cortex-A9),
    etc.
  \end{itemize}
\end{frame}

\begin{frame}{High level overview of an ARM board}
  \begin{center}
    \includegraphics[height=0.8\textheight]{arm-soc.pdf}
  \end{center}
\end{frame}

\begin{frame}{Wide variety of ARM platforms}
  \begin{center}
    \includegraphics[width=\textwidth]{arm-soc-families.pdf}\\
    and this is only a very, very partial list. ARM has more than 150
    licensees.
  \end{center}
\end{frame}

\begin{frame}{Maintenance problem}
  \begin{itemize}
  \item This {\bf huge variety of SoCs}, each getting more and more
    complicated, leads to a {\bf large quantity of code} to support
    them
  \item The historical ARM maintainer, Russell King, through which all
    ARM code was initially going, got {\bf overflowed by the amount of
      code}
  \item Code from sub-architectures (SoC families) started to go
    directly to Linus
  \item Focus of sub-architecture maintainers on their
    sub-architecture, {\bf no vision of the other sub-architectures}
  \item Consequence: a lot of {\bf code duplication}, {\bf no common
      infrastructures} designed for common problems, similar problems
    solved differently, etc.
  \end{itemize}
\end{frame}

\begin{frame}{Single kernel image}
  \begin{itemize}
  \item Until now, ARM platforms mainly used in the industrial
    embedded space, or un-modifiable consumer products
    \begin{itemize}
    \item A given binary kernel image was configured and built
      {\bf specifically for each platform}
    \item All the existing code makes the assumption that the kernel
      is built for one single platform
    \end{itemize}
  \item ARM now used in modifiable consumer products (tablets, phones,
    etc.)
    \begin{itemize}
    \item Desire for distributions to provide a system for such
      platforms
    \item On x86, easy because one kernel image supports all
      platforms. On ARM, each platform currently needs one specific
      kernel image.
    \item In the future, {\bf wish to support multiple platforms
        inside a single kernel image}.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Solutions}
  \begin{itemize}
  \item Sub-architecture maintainer
  \item Device Tree
  \item Clock framework
  \item Pinctrl subsystem
  \end{itemize}
\end{frame}

\begin{frame}
  \begin{center}
    \Huge{Sub-architecture maintainer}
  \end{center}
\end{frame}

\begin{frame}{ARM sub-architecture maintainer}
  \begin{itemize}
  \item The lack of a cross sub-architecture vision was filled by
    creating a {\bf team of ARM sub-architecture maintainers}, in May
    2011
  \item Initially with Arnd Bergmann (Linaro/IBM), Nicolas Pitre (Linaro),
    Marc Zyngier (ARM), later joined by Olof Johansson (Tegra
    maintainer)
  \item This team takes care of {\bf reviewing and consolidating the
      code} of the different sub-architectures, and {\bf sending it to
      Linus Torvalds}
  \item Russell King continues to be the maintainer for the ARM core
    part (memory management, CPU support code, etc.)
  \item {\bf Important role of {\em Linaro}} in this new maintainer team
    \begin{itemize}
    \item Linaro is a not-for-profit engineering organization
      consolidating and optimizing open source Linux software and
      tools for the ARM architecture.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Flow of code}
  \begin{center}
    \includegraphics[height=0.8\textheight]{arm-maintainers.pdf}
  \end{center}
\end{frame}

\begin{frame}
  \begin{center}
    \Huge{Device tree}
  \end{center}
\end{frame}

\begin{frame}{Definition of platform details}
  \begin{itemize}
  \item All the board-specific details and SoC-specific details
    require specific C code to support new platforms
  \item A lot of very similar C code to support each and every board,
    to list all the peripherals, their configuration, etc.
  \item Code organized in a hierarchy
    \begin{center}
      \includegraphics[width=0.7\textwidth]{arm-hierarchy.pdf}
    \end{center}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{List of files in {\tt arch/arm/mach-at91}}
  \tiny
\begin{verbatim}
at91rm9200.c           at91x40_time.c       board-neocore926.c    clock.h
at91rm9200_devices.c   board-1arm.c         board-pcontrol-g20.c  cpuidle.c
at91rm9200_time.c      board-afeb-9260v1.c  board-picotux200.c    generic.h
at91sam9260.c          board-cam60.c        board-qil-a9260.c     gpio.c
at91sam9260_devices.c  board-carmeva.c      board-rm9200dk.c      include
at91sam9261.c          board-cpu9krea.c     board-rm9200ek.c      irq.c
at91sam9261_devices.c  board-cpuat91.c      board-rsi-ews.c       Kconfig
at91sam9263.c          board-csb337.c       board-sam9260ek.c     leds.c
at91sam9263_devices.c  board-csb637.c       board-sam9261ek.c     Makefile
at91sam926x_time.c     board-dt.c           board-sam9263ek.c     Makefile.boot
at91sam9_alt_reset.S   board-eb01.c         board-sam9g20ek.c     pm.c
at91sam9g45.c          board-eb9200.c       board-sam9-l9260.c    pm.h
at91sam9g45_devices.c  board-ecbat91.c      board-sam9m10g45ek.c  pm_slowclock.S
at91sam9g45_reset.S    board-eco920.c       board-sam9rlek.c      sam9_smc.c
at91sam9n12.c          board-flexibity.c    board-snapper9260.c   sam9_smc.h
at91sam9rl.c           board-foxg20.c       board-stamp9g20.c     setup.c
at91sam9rl_devices.c   board-gsia18s.c      board-usb-a926x.c     soc.h
at91sam9x5.c           board-kafa.c         board-yl-9200.c
at91x40.c              board-kb9202.c       clock.c
\end{verbatim}
\end{frame}

\begin{frame}{Old probing mechanism: overview}
  \begin{center}
    \includegraphics[width=\textwidth]{old-style.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]{The board file}
\tiny
  \begin{minted}{c}
static struct macb_platform_data snapper9260_macb_data = {
        .phy_irq_pin    = -EINVAL,
        .is_rmii        = 1,
};

static struct i2c_board_info __initdata snapper9260_i2c_devices[] = {
        {        I2C_BOARD_INFO("max7312", 0x28),
                .platform_data = &snapper9260_io_expander_data, },
        {       I2C_BOARD_INFO("tlv320aic23", 0x1a),            },
};

static void __init snapper9260_board_init(void)
{
        at91_add_device_i2c(snapper9260_i2c_devices,
                            ARRAY_SIZE(snapper9260_i2c_devices));
        at91_register_uart(0, 0, 0);
        at91_register_uart(AT91SAM9260_ID_US0, 1,
                           ATMEL_UART_CTS | ATMEL_UART_RTS);
        at91_add_device_eth(&snapper9260_macb_data);
        [...]
}

MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
        [...]
        .init_machine   = snapper9260_board_init,
MACHINE_END
\end{minted}

\small
\begin{center}
  The board file registers devices (from
  \path{arch/arm/mach-at91/board-snapper9260.c})
\end{center}
\end{frame}

\begin{frame}[fragile]{The SoC file: device definition}

\tiny
  \begin{minted}{c}
static struct macb_platform_data eth_data;

static struct resource eth_resources[] = {
        [0] = {
                .start  = AT91SAM9260_BASE_EMAC,
                .end    = AT91SAM9260_BASE_EMAC + SZ_16K - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
                .start  = AT91SAM9260_ID_EMAC,
                .end    = AT91SAM9260_ID_EMAC,
                .flags  = IORESOURCE_IRQ,
        },
};

static struct platform_device at91sam9260_eth_device = {
        .name           = "macb",
        .id             = -1,
        .dev            = {
                                .dma_mask               = &eth_dmamask,
                                .coherent_dma_mask      = DMA_BIT_MASK(32),
                                .platform_data          = &eth_data,
        },
        .resource       = eth_resources,
        .num_resources  = ARRAY_SIZE(eth_resources),
};
  \end{minted}
\end{frame}

\begin{frame}[fragile]{The SoC file: device registration}

\tiny
\begin{minted}{c}
void __init at91_add_device_eth(struct macb_platform_data *data)
{
        [...]
        if (gpio_is_valid(data->phy_irq_pin)) {
                at91_set_gpio_input(data->phy_irq_pin, 0);
                at91_set_deglitch(data->phy_irq_pin, 1);
        }

        /* Pins used for MII and RMII */
        at91_set_A_periph(AT91_PIN_PA19, 0);    /* ETXCK_EREFCK */
        at91_set_A_periph(AT91_PIN_PA17, 0);    /* ERXDV */
        at91_set_A_periph(AT91_PIN_PA14, 0);    /* ERX0 */
        at91_set_A_periph(AT91_PIN_PA15, 0);    /* ERX1 */
        at91_set_A_periph(AT91_PIN_PA18, 0);    /* ERXER */
        at91_set_A_periph(AT91_PIN_PA16, 0);    /* ETXEN */
        at91_set_A_periph(AT91_PIN_PA12, 0);    /* ETX0 */
        at91_set_A_periph(AT91_PIN_PA13, 0);    /* ETX1 */
        at91_set_A_periph(AT91_PIN_PA21, 0);    /* EMDIO */
        at91_set_A_periph(AT91_PIN_PA20, 0);    /* EMDC */

        if (!data->is_rmii) {
              [...]
        }

        eth_data = *data;
        platform_device_register(&at91sam9260_eth_device);
}
\end{minted}
\end{frame}

\begin{frame}[fragile]{The driver part}

\tiny
\begin{minted}{c}
static int __init macb_probe(struct platform_device *pdev)
{
    [...]
}

static int __exit macb_remove(struct platform_device *pdev)
{
    [...]
}

static struct platform_driver macb_driver = {
        .remove         = __exit_p(macb_remove),
        .driver         = {
                .name   = "macb",
                .owner  = THIS_MODULE,
        },
};

static int __init macb_init(void)
{
        return platform_driver_probe(&macb_driver, macb_probe);
}

static void __exit macb_exit(void)
{
        platform_driver_unregister(&macb_driver);
}

module_init(macb_init);
module_exit(macb_exit);
\end{minted}
\end{frame}

\begin{frame}{Device Tree: principle}
  \begin{itemize}
  \item The general idea of the {\em Device Tree} is to {\bf separate
      a large part of the hardware description from the kernel
      sources}
  \item The Device Tree is a {\bf tree of nodes}, describing the
    different hardware components of a system and their
    characteristics
  \item Written in a {\bf specialized language}, the {\em Device Tree
      Source} is compiled into a {\em Device Tree Blob} by the {\em
      Device Tree Compiler}
  \item This mechanism takes its roots from {\em OpenFirmware}
    used on some PowerPC platforms, and has been used on all PowerPC
    platforms for a long time.
  \item It is now also being used in other architectures in the Linux
    kernel such as Microblaze, OpenRISC and C6X.
  \item Inheritance mechanism: \path{.dts} files for boards,
    \path{.dtsi} for include files
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Device Tree: {\tt tegra20.dtsi}}
  \tiny
  \begin{columns}
    \column{0.5\textwidth}
    \begin{minted}{perl}
/include/ "skeleton.dtsi"

/ {
    compatible = "nvidia,tegra20";
    interrupt-parent = <&intc>;

    intc: interrupt-controller {
        compatible = "arm,cortex-a9-gic";
        reg = <0x50041000 0x1000
               0x50040100 0x0100>;
        interrupt-controller;
        #interrupt-cells = <3>;
    };

    serial@70006000 {
        compatible = "nvidia,tegra20-uart";
        reg = <0x70006000 0x40>;
        reg-shift = <2>;
        interrupts = <0 36 0x04>;
        status = "disable";
    };

    serial@70006040 {
        compatible = "nvidia,tegra20-uart";
        reg = <0x70006040 0x40>;
        reg-shift = <2>;
        interrupts = <0 37 0x04>;
        status = "disable";
    };

  \end{minted}
  \column{0.5\textwidth}
  \begin{minted}{perl}
    i2c@7000c000 {
        compatible = "nvidia,tegra20-i2c";
        reg = <0x7000c000 0x100>;
        interrupts = <0 38 0x04>;
        #address-cells = <1>;
        #size-cells = <0>;
        status = "disable";
    };

    i2c@7000c400 {
        compatible = "nvidia,tegra20-i2c";
        reg = <0x7000c400 0x100>;
        interrupts = <0 84 0x04>;
        #address-cells = <1>;
        #size-cells = <0>;
        status = "disable";
    };

    usb@c5004000 {
        compatible = "nvidia,tegra20-ehci","usb-ehci";
        reg = <0xc5004000 0x4000>;
        interrupts = <0 21 0x04>;
        phy_type = "ulpi";
        status = "disable";
    };

    [...]
};
\end{minted}
\end{columns}
\end{frame}

\begin{frame}[fragile]{Device Tree: {\tt tegra-harmony.dts}}
  \tiny
  \begin{columns}
    \column{0.5\textwidth}
  \begin{minted}{perl}
/dts-v1/;

/include/ "tegra20.dtsi"

/ {
    model = "NVIDIA Tegra2 Harmony evaluation board";
    compatible = "nvidia,harmony", "nvidia,tegra20";

    memory {
        reg = <0x00000000 0x40000000>;
    };

    serial@70006300 {
        status = "okay";
        clock-frequency = <216000000>;
    };

    i2c@7000c400 {
        status = "okay";
        clock-frequency = <400000>;
    };

  \end{minted}
  \column{0.5\textwidth}
  \begin{minted}{perl}
    i2c@7000c000 {
        status = "okay";
        clock-frequency = <400000>;

        wm8903: wm8903@1a {
            compatible = "wlf,wm8903";
            reg = <0x1a>;
            interrupt-parent = <&gpio>;
            interrupts = <187 0x04>;

            gpio-controller;
            #gpio-cells = <2>;
            [...]
        };
    };

    usb@c5004000 {
        status = "okay";
        nvidia,phy-reset-gpio = <&gpio 169 0>;
    };

    [...]
};
  \end{minted}
  \end{columns}
\end{frame}

\begin{frame}{Device Tree usage}
  \begin{itemize}
  \item When the \path{.dts} file is in \path{arch/arm/boot/dts}, as
    simple as:\\
    \path{make ARCH=arm foobar.dtb}
  \item Then, on ARM, two cases:
    \begin{enumerate}
    \item {\bf Your bootloader has DT support}.\\You need to load both your
      kernel image and DT image, and start the kernel with both
      addresses. The DTB address is passed to the kernel in register
      \path{r2}, instead of the {\em ATAG} address. With U-Boot:\\
      \path{bootm kerneladdr - dtbaddr}
    \item {\bf Your bootloader does not have DT support}.\\ARM has a special
      \path{CONFIG_ARM_APPENDED_DTB} option that allows to append the
      \path{zImage} directly with the \path{dtb}. This is provided for
      debugging only, bootloaders are expected to provide DT support.
    \end{enumerate}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Device Tree in the ARM code}
  \begin{itemize}
  \item Only one ``board'' file is needed per SoC
  \item Uses \path{DT_MACHINE_START} instead of \path{MACHINE_START}
  \item Provides a \path{dt_compat} table to list the platforms
    compatible with this definition
  \item \path{of_platform_populate} will instantiate the devices
  \item From \path{arch/arm/mach-tegra/board-dt-tegra20.c}:
  \tiny
  \begin{minted}{c}
static void __init tegra_dt_init(void)
{
        [...]
        of_platform_populate(NULL, tegra_dt_match_table,
                                tegra20_auxdata_lookup, NULL);
}

static const char *tegra20_dt_board_compat[] = {
        "nvidia,tegra20",
        NULL
};

DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)")
        .init_machine   = tegra_dt_init,
        .dt_compat      = tegra20_dt_board_compat,
        [...]
MACHINE_END
  \end{minted}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Device tree in drivers: \path{i2c-tegra.c}}
  \tiny
  \begin{minted}{c}
static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
        { .compatible = "nvidia,tegra20-i2c", },
        { .compatible = "nvidia,tegra20-i2c-dvc", },
        {},
};
MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);

static struct platform_driver tegra_i2c_driver = {
        .probe   = tegra_i2c_probe,
        .remove  = __devexit_p(tegra_i2c_remove),
        .driver  = {
                .name  = "tegra-i2c",
                .owner = THIS_MODULE,
                .of_match_table = tegra_i2c_of_match,
        },
};

static int __init tegra_i2c_init_driver(void)
{
        return platform_driver_register(&tegra_i2c_driver);
}

static void __exit tegra_i2c_exit_driver(void)
{
        platform_driver_unregister(&tegra_i2c_driver);
}

subsys_initcall(tegra_i2c_init_driver);
module_exit(tegra_i2c_exit_driver);
  \end{minted}
\end{frame}

\begin{frame}{Device Tree binding}
  \begin{itemize}
  \item With the Device Tree, each driver defines:
    \begin{itemize}
    \item its {\em compatible} string, which uniquely identifies the
      driver, and allows devices to be bound to the corresponding
      driver
    \item the properties of each device in the device tree
    \end{itemize}
  \item This definition is called a {\bf device tree binding}
  \item All {\em device tree bindings} are normally documented in
    \path{Documentation/devicetree/bindings}.
  \end{itemize}
\end{frame}

\begin{frame}{Device Tree: summary}
  \begin{center}
    \includegraphics[width=\textwidth]{boot-with-dt.pdf}
  \end{center}
\end{frame}

\begin{frame}{Clocks in SoCs}
  \begin{itemize}
  \item The different hardware parts of an SoC are driven by different
    clocks, operating at different frequencies
  \item Most of those clocks are part of a complex clock tree, where
    parents clocks are inputs to children clocks
  \item Many of those clocks are software configurable (on/off,
    multiple frequencies, etc.) and must be manipulated at runtime for
    power management reasons
  \item Due to the parent/child relationship, one must ensure that
    \begin{enumerate}
    \item The parent clock is enabled when a child clock needs to be
      enabled
    \item The parent clock is disabled once all children have been
      disabled
    \end{enumerate}
  \end{itemize}
\end{frame}

\begin{frame}{The old clock management infrastructure}
  \begin{itemize}
  \item Clocks need to be manipulated by {\em device drivers}: they
    know when to enable/disable the needed clocks
  \item Clocks are listed and controlled by {\em SoC code}
  \item Since some time, a common clock API has been defined in
    \path{<linux/clk.h>}, defining
    \begin{enumerate}
    \item An opaque \path{struct clk} structure, that drivers could
      manipulate
    \item A simple \path{clk_get}, \path{clk_put}, \path{clk_enable},
      \path{clk_disable}, \path{clk_get_rate} API
    \end{enumerate}
  \item Each ARM sub-architecture had to have its own definition of
    \path{struct clk} and its own implementation of the API
    \begin{itemize}
    \item A lot of code duplication
    \item No common facilities, even though most clocks are relatively
      similar between SoC
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{The new clock framework}
  \begin{itemize}
  \item A proper {\em clock framework} has been added in kernel 3.4,
    released in May 2012
  \item Initially from Jeremy Kerr (Canonical), finally implemented
    and merged by Mike Turquette (Texas Instruments)
  \item This framework:
    \begin{itemize}
    \item Implements the \path{clk_get}, \path{clk_put},
      \path{clk_prepare}, \path{clk_unprepare}, \path{clk_enable},
      \path{clk_disable}, \path{clk_get_rate}, etc. {\bf API for usage
        by device drivers}
    \item Provides data structures (\path{struct clk_hw} and
      \path{struct clk ops}) for {\bf SoC code to define its clocks},
      and a \path{clk_register}, \path{clk_unregister} API to register
      them, and \path{clk_register_clkdevs} to associate clocks to
      device names
    \item Implements {\bf some basic clock types} (fixed rate,
      gatable, divider, fixed factor, etc.)
    \item Provides a {\em debugfs} representation of the clock tree
    \item Is implemented in \path{drivers/clk}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Clock framework, the driver side}
  From \path{drivers/serial/tty/mxs-auart.c}, the UART driver for
  i.MX23/28 SoCs.
  \tiny
  \begin{minted}{c}

static int mxs_auart_startup(struct uart_port *u)
{
        [...]
        clk_prepare_enable(s->clk);
        [...]
}

static void mxs_auart_shutdown(struct uart_port *u)
{
         [...]
         clk_disable_unprepare(s->clk);
}

static int __devinit mxs_auart_probe(struct platform_device *pdev)
{
        [...]
        s->clk = clk_get(&pdev->dev, NULL);
        [...]
        s->port.uartclk = clk_get_rate(s->clk);
        [...]
}

static int __devexit mxs_auart_remove(struct platform_device *pdev)
{
        [...]
        clk_put(s->clk);
        [...]
}
  \end{minted}
\end{frame}

\begin{frame}[fragile]{Clock framework, SoC side}
  From \path{drivers/clk/mxs/clk-imx28.c}
  \tiny
  \begin{minted}{c}
static struct clk_lookup uart_lookups[] __initdata = {
        { .dev_id = "duart", },
        { .dev_id = "mxs-auart.0", },
        [...]
        { .dev_id = "8006a000.serial", },
        [...]
};

static struct clk *clks[clk_max];

int __init mx28_clocks_init(void)
{
        [...]
        clks[ref_xtal] = mxs_clk_fixed("ref_xtal", 24000000);
        clks[pll0] = mxs_clk_pll("pll0", "ref_xtal", PLL0CTRL0, 17, 480000000);
        [...]
        clks[ref_cpu] = mxs_clk_ref("ref_cpu", "pll0", FRAC0, 0);
        clks[ref_emi] = mxs_clk_ref("ref_emi", "pll0", FRAC0, 1);
        [...]
        clks[gpmi_sel] = mxs_clk_mux("gpmi_sel", CLKSEQ, 2, 1, sel_gpmi, ARRAY_SIZE(sel_gpmi));
        clks[ssp0_sel] = mxs_clk_mux("ssp0_sel", CLKSEQ, 3, 1, sel_io0, ARRAY_SIZE(sel_io0));
        clks[ssp1_sel] = mxs_clk_mux("ssp1_sel", CLKSEQ, 4, 1, sel_io0, ARRAY_SIZE(sel_io0));
        clks[ssp2_sel] = mxs_clk_mux("ssp2_sel", CLKSEQ, 5, 1, sel_io1, ARRAY_SIZE(sel_io1));
        [...]
        clks[uart] = mxs_clk_gate("uart", "ref_xtal", XTAL, 31);
        [...]
        clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups));
        [...]
}
  \end{minted}
\end{frame}

\begin{frame}{Clock framework, SoC side}
  \begin{itemize}
  \item \path{mxs_clk_fixed()}\\
    Registers a fixed-rate clock, using the \code{clk-fixed} clock
    type provided by the base clock framework in
    \path{drivers/clk/clk-fixed.c}
  \item \path{mxs_clk_ref()}\\
    Registers a reference clock, using the \code{clk-ref} clock type
    specific to i.MX, implemented in \path{drivers/clk/mxs/clk-ref.c}
  \item \path{mxs_clk_pll()}\\
    Registers a PLL clock, using the \code{clk-pll} clock type
    specific to i.MX, implemented in \path{drivers/clk/mxs/clk-pll.c}
  \item \path{mxs_clk_mux()}\\
    Registers a muxed clock, using the \code{clk-mux} clock
    type provided by the base clock framework in
    \path{drivers/clk/clk-mux.c}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Clock tree in {\em debugfs}}
  \scriptsize
\begin{verbatim}
# cd /sys/kernel/debug/clk
# find
./ref_xtal
./ref_xtal/pll0
./ref_xtal/pll0/ref_io1
./ref_xtal/pll0/ref_io1/ssp2_sel
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/ssp2
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/ssp2/clk_notifier_count
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/ssp2/clk_enable_count
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/ssp2/clk_prepare_count
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/ssp2/clk_flags
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/ssp2/clk_rate
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/clk_notifier_count
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/clk_enable_count
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/clk_prepare_count
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/clk_flags
./ref_xtal/pll0/ref_io1/ssp2_sel/ssp2_div/clk_rate
[...]
\end{verbatim}
\end{frame}

\begin{frame}{Clock framework: summary}
  \begin{center}
    \includegraphics[width=\textwidth]{clock-framework.pdf}
  \end{center}
\end{frame}

\begin{frame}{Introduction to pin muxing}
  \begin{itemize}
  \item SoCs integrate many more peripherals than the number of
    available pins allows to expose.
  \item Many of those pins are therefore {\bf multiplexed}: they can
    either be used as function A, {\em or} function B, {\em or}
    function C, {\em or} a GPIO
  \item Example of functions are:
    \begin{itemize}
      \item parallel LCD lines
      \item SDA/SCL lines for I2C busses
      \item MISO/MOSI/CLK lines for SPI
      \item RX/TX/CTS/DTS lines for UARTs
      \end{itemize}
    \item This muxing is {\bf software-configurable}, and depends on
      {\bf how the SoC is used on each particular board}
  \end{itemize}
\end{frame}

\begin{frame}{Pin muxing: principle}
  \begin{center}
    \includegraphics[height=0.7\textheight]{pin-muxing-principle.pdf}
  \end{center}
\end{frame}

\begin{frame}{Pin muxing: example}
  \begin{center}
    \includegraphics[height=0.8\textheight]{pin-muxing-example-atmel.png}
  \end{center}
\end{frame}

\begin{frame}{The old pin-muxing code}
  \begin{itemize}
  \item Each ARM sub-architecture had its own pin-muxing code
  \item The API was specific to each sub-architecture
  \item Lot of similar functionality implemented in different ways
  \item The pin-muxing had to be done at the SoC level, and couldn't
    be requested by device drivers
  \end{itemize}
\end{frame}

\begin{frame}{The new pin-muxing subsystem}
  \begin{itemize}
  \item The new {\bf pinctrl} subsystem aims at solving those problems
  \item Mainly developed and maintained by Linus Walleij, from
    Linaro/ST-Ericsson
  \item Implemented in \path{drivers/pinctrl}
  \item Provides:
    \begin{itemize}
    \item An API to register {\em pinctrl driver}, i.e entities
      knowing the list of pins, their functions, and how to configure
      them. Used by SoC-specific drivers to expose pin-muxing
      capabilities.
    \item An API for {\em device drivers} to request the muxing of a
      certain set of pins
    \item An interaction with the {\em GPIO} framework
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{The new pin-muxing subsystem: diagram}
  \begin{center}
    \includegraphics[width=\textwidth]{pinctrl-subsystem.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]{Declaring pin groups in the SoC {\tt dtsi}}
  \begin{itemize}
  \item From \path{arch/arm/boot/dts/imx28.dtsi}
  \item Declares the {\em pinctrl} device and various pin groups
  \end{itemize}
  \tiny
  \begin{columns}
    \column{0.5\textwidth}
    \begin{minted}{perl}
pinctrl@80018000 {
   #address-cells = <1>;
   #size-cells = <0>;
   compatible = "fsl,imx28-pinctrl", "simple-bus";
   reg = <0x80018000 2000>;

   duart_pins_a: duart@0 {
           reg = <0>;
           fsl,pinmux-ids = <0x3102 0x3112>;
           fsl,drive-strength = <0>;
           fsl,voltage = <1>;
           fsl,pull-up = <0>;
   };
   duart_pins_b: duart@1 {
           reg = <1>;
           fsl,pinmux-ids = <0x3022 0x3032>;
           fsl,drive-strength = <0>;
           fsl,voltage = <1>;
           fsl,pull-up = <0>;
   };
 \end{minted}
 \column{0.5\textwidth}
 \begin{minted}{perl}
   mmc0_8bit_pins_a: mmc0-8bit@0 {
           reg = <0>;
           fsl,pinmux-ids = <0x2000 0x2010 0x2020
                   0x2030 0x2040 0x2050 0x2060
                   0x2070 0x2080 0x2090 0x20a0>;
           fsl,drive-strength = <1>;
           fsl,voltage = <1>;
           fsl,pull-up = <1>;
   };
   mmc0_4bit_pins_a: mmc0-4bit@0 {
           reg = <0>;
           fsl,pinmux-ids = <0x2000 0x2010 0x2020
                   0x2030 0x2080 0x2090 0x20a0>;
           fsl,drive-strength = <1>;
           fsl,voltage = <1>;
           fsl,pull-up = <1>;
   };
   mmc0_cd_cfg: mmc0-cd-cfg {
           fsl,pinmux-ids = <0x2090>;
           fsl,pull-up = <0>;
   };
   mmc0_sck_cfg: mmc0-sck-cfg {
           fsl,pinmux-ids = <0x20a0>;
           fsl,drive-strength = <2>;
           fsl,pull-up = <0>;
   };
};
\end{minted}
\end{columns}
\end{frame}

\begin{frame}[fragile]{Associating devices with pin groups, board {\tt dts}}
  \begin{itemize}
  \item From \path{arch/arm/boot/dts/cfa10036.dts}
  \end{itemize}
  \scriptsize
  \begin{minted}{perl}
apb@80000000 {
  apbh@80000000 {
     ssp0: ssp@80010000 {
         compatible = "fsl,imx28-mmc";
         pinctrl-names = "default";
         pinctrl-0 = <&mmc0_4bit_pins_a
                      &mmc0_cd_cfg &mmc0_sck_cfg>;
         bus-width = <4>;
         status = "okay";
     };
  };

  apbx@80040000 {
     duart: serial@80074000 {
         pinctrl-names = "default";
         pinctrl-0 = <&duart_pins_b>;
         status = "okay";
     };
  };
};
  \end{minted}
\end{frame}

\begin{frame}[fragile]{Device drivers requesting pin muxing}

  \begin{itemize}
  \item From \path{drivers/mmc/host/mxs-mmc.c}
  \end{itemize}
  \small
  \begin{minted}{c}
static int mxs_mmc_probe(struct platform_device *pdev)
{
    [...]
    pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
    if (IS_ERR(pinctrl)) {
        ret = PTR_ERR(pinctrl);
        goto out_mmc_free;
    }
    [...]
}
  \end{minted}
\end{frame}

\begin{frame}{References}
  \begin{itemize}
  \item About ARM maintenance
    \begin{itemize}
      \scriptsize
    \item {\em ARM Subarchitecture Status}, Arnd Bergmann, ELC 2012
    \end{itemize}
  \item About the Device Tree
    \begin{itemize}
      \scriptsize
    \item Official Wiki, \url{http://devicetree.org}
    \item {\em Experiences With Device Tree Support Development For
        ARM-Based SOC’s}, Thomas P. Abraham, ELC 2012
    \item {\em Device Tree Status Report}, Grant Likely, ELCE 2011.
    \end{itemize}
  \item About the clock framework
    \begin{itemize}
      \scriptsize
    \item \path{Documentation/clk.txt} in the kernel sources
    \item \url{http://lwn.net/Articles/472998/}
    \item {\em Common Clock Framework}, Mike Turquette, ELC2012
    \end{itemize}
  \item About the pinctrl subsystem
    \begin{itemize}
      \scriptsize
    \item \path{Documentation/pinctrl.txt} in the kernel sources
    \item \url{http://lwn.net/Articles/468759/}
    \item {\em Pin Control Subsystem Overview}, Linus Walleij, ELC2012
    \end{itemize}
  \item Slides and video at
    \begin{itemize}
      \scriptsize
      \item \url{https://bootlin.com/blog/elc-2012-videos/} for Embedded Linux Conference 2012
      \item \url{https://bootlin.com/blog/elce-2011-videos/} for Embedded Linux Conference Europe 2011
      \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Conclusion}
  \begin{itemize}
  \item The {\em pinctrl} and {\em clk} subsystems now provide {\bf
      generic abstractions} to manage pin muxing and the clocks of
    an SoC
  \item The {\em device tree} provides a {\bf better way of
      representing the hardware}, requiring less code to describe new
    platforms
  \item The usage of these new infrastructures is {\bf mandatory for
      new platforms}
  \item {\bf Conversion of existing platforms} that are widely used is
    in process
  \item The ARM community has gained better code infrastructures, a
    better organization, and has become {\bf even more dynamic than it
      was}.
  \end{itemize}
\end{frame}

\begin{frame}
  \begin{center}
  \Large
  Questions?\\
  \vspace{0.5cm}
  \includegraphics[width=0.7\textwidth]{lolcat.jpg}\\
  \vspace{0.2cm}
  Thomas Petazzoni\\
  \code{thomas.petazzoni@bootlin.com}\\
  \scriptsize
  Slides under CC-BY-SA 3.0.\\
  \tiny
  PDF and sources will be available on
  \url{https://bootlin.com/pub/conferences/2012/lsm/}
  \end{center}
\end{frame}

\end{document}
