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

\mode<presentation>
\usetheme{Bootlin}

\newcommand{\codehack}[1]{{\usebeamercolor[fg]{code} {\tt #1}}}

\title{Your new ARM SoC Linux support check-list!}
\authors{Thomas Petazzoni}
\institute{Bootlin}

\usepackage{hyperref}

\begin{document}

\begin{frame}{Embedded Linux Conference Europe 2012}
  \begin{columns}[c]
   \column{0.6\textwidth}
     \huge
     Your new ARM SoC Linux support check-list!\\
     \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 Embedded Linux engineer and trainer at Bootlin since
    2008
    \begin{itemize}
    \item Embedded Linux {\bf development}: kernel and driver
      development, system integration, boot time and power
      consumption optimization, consulting, etc.
    \item Embedded Linux {\bf training}, Linux driver development training
      and Android system development training, with materials freely
      available under a Creative Commons license.
    \item \url{http://bootlin.com}
    \end{itemize}
  \item Contributing the {\bf kernel support for the new Armada 370
      and Armada XP} ARM SoCs from Marvell, under contract with
    Marvell.
  \item Major contributor to {\bf Buildroot}, an open-source, simple and
    fast embedded Linux build system
  \item Living in {\bf Toulouse}, south west of France
  \end{itemize}
\end{frame}

\begin{frame}{Background}

  \begin{itemize}
  \item March 2011, Linus Torvalds, {\em Gaah. Guys, this whole ARM
      thing is a f*cking pain in the ass}
  \item More and more ARM SoCs have appeared and are appearing
  \item The historical maintainer, Russell King, through which all ARM
    code was initially going got {\bf overflowed by the amount of
      code} to review
  \item Code started to flow from sub-architectures maintainers
    directly to Linus
  \item Focus of each sub-architecture teams on {\bf their own
      problems}, no vision of the other sub-architectures.
  \item Consequences: lot of {\bf code duplication}, {\bf missing
      common infrastructures}, maintainability problems, etc.
  \end{itemize}

\end{frame}

\begin{frame}{Why?}
  \begin{itemize}
  \item In order to solve these problems, the ARM Linux kernel
    community has done major changes since the last ~2 years
    \begin{itemize}
    \item In the {\bf maintenance process}
    \item In the {\bf code infrastructure and subsystems}
    \end{itemize}
  \item {\bf Not necessarily easy to follow} all those changes and
    know what are the current best practices
  \item This talk is an {\bf attempt} to {\bf summarize some of the
      most important changes}, and {\bf provide guidelines} for
    developers willing to add support for new ARM SoCs in the mainline
    Linux kernel
    \begin{itemize}
    \item but it might be useful for people porting Linux on new
      boards as well
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Know who are the maintainers}
  \begin{itemize}
  \item {\bf Russell King} is now the maintainer for the core ARM
    support (i.e anything in \code{arch/arm} except the SoC specific
    code in \code{arch/arm/mach-<foo>} and
    \code{arch/arm/plat-<bar>}).
  \item {\bf Arnd Bergmann and Olof Johansson} are the {\em arm-soc}
    maintainers. All the ARM SoC code must go through them. They
    ensure a coherence between how the various SoC families handle
    similar problems.
  \item Also need to interact with the subsystem maintainers
    \begin{itemize}
    \item \code{drivers/clocksource}, \code{drivers/irqchip}, {\bf
        Thomas Gleixner}
    \item \code{drivers/pinctrl}, {\bf Linus Walleij}, {\bf Stephen Warren}
    \item \code{drivers/gpio}, {\bf Grant Likely}, {\bf Linus Walleij}
    \item \code{drivers/clk}, {\bf Mike Turquette}
    \end{itemize}
  \item Primary mailing list:
    \code{linux-arm-kernel@lists.infradead.org}
  \end{itemize}
\end{frame}

\begin{frame}{Where is the code, when to submit?}
  \begin{itemize}
  \item The {\bf arm-soc} Git tree is at
    \url{https://git.kernel.org/?p=linux/kernel/git/arm/arm-soc.git;a=summary}
  \item Watch the {\bf for-next} branch that contains what will be
    submitted by the ARM SoC maintainers during the next merge window.
  \item Generally, the ARM SoC maintainers want to have integrated all
    the code from the different ARM sub-architectures a few (two?)
    weeks before Linus opens the merge window.
  \item If you submit your code {\em during} the Linus merge window,
    there is no way it will get integrated at this point: it will have
    to wait for the next merge window.
  \item Usual Linux contribution guidelines apply: people will make
    comments on your code, take them into account, repost. Find the
    good balance between {\bf patience} and {\bf perseverance}.
  \end{itemize}
\end{frame}

\begin{frame}{Existing code?}

  \begin{itemize}
  \item You have existing Linux kernel code to support your SoC?
  \item There are {\bf 99\% chances that you should throw it away
      completely}
    \begin{itemize}
    \item Most of the time, SoC support code written by SoC vendors do
      not comply with the Linux coding rules, the Linux
      infrastructures, has major design issues, is ugly, etc.
    \item With the recent major changes in the way to support ARM SoC,
      all existing code has become {\bf basically irrelevant}.
    \end{itemize}
  \item Of course, existing code useful as a reference to know how the
    hardware works. But the code to be submitted should most likely be
    {\bf written from scratch}.
  \end{itemize}

\end{frame}

\begin{frame}{Step 1: start minimal}
  \begin{center}
    \includegraphics[width=\textwidth]{elements-step1.pdf}
  \end{center}
\end{frame}

\begin{frame}{Device Tree}
  \begin{itemize}
  \item The purpose of the Device Tree is to move a significant part
    of the {\bf hardware description} into a data structure that is no
    longer part of the kernel binary itself.
  \item This data structure, the {\bf Device Tree Source} is compiled
    into a binary {\bf Device Tree Blob}
  \item The {\bf Device Tree Blob} is loaded into memory by the
    bootloader, and passed to the kernel.
  \item It replaces all the \code{board-*.c} files, and removes all
    the manual registration of \code{platform_device}. Also, no longer
    needed to have \code{Kconfig} options for each board.
  \item Usage of the Device Tree is {\bf mandatory} for all new ARM
    SoCs. No way around it.
  \end{itemize}
\end{frame}

\begin{frame}{Boot process with a Device Tree Blob}

  \begin{center}
    \includegraphics[width=\textwidth]{kernel-and-dtb.pdf}
  \end{center}

\end{frame}

\begin{frame}{Writing your Device Tree}
  \begin{itemize}
  \item Add one \code{<soc>.dtsi} file in \code{arch/arm/boot/dts/}
    that describes the devices in your SoC
    \begin{itemize}
    \item You can also have multiple \code{<soc>.dtsi} files including
      each other with the \code{/include/} directive, if you have a
      SoC family with multiple SoCs having common things, but also
      specific things.
    \end{itemize}
  \item Add one \code{<board>.dts} file in \code{arch/arm/boot/dts/}
    for each of the boards you support. It should \code{/include/} the
    appropriate \code{.dtsi} file.
  \item Add a \codehack{dtb-\$(CONFIG\_ARCH\_<yourarch>)} line in
    \code{arch/arm/boot/dts/Makefile} for all your board \code{.dts}
    files so that all the \code{.dtb}s are automatically built.
  \end{itemize}
\end{frame}

\begin{frame}{Example on Armada 370/XP support}
  \code{armada-370-xp.dtsi}
    \begin{itemize}
    \item \code{armada-370.dtsi}
      \begin{itemize}
      \item Board \code{armada-370-db.dts}
      \end{itemize}
    \item \code{armada-xp.dtsi}
      \begin{itemize}
      \item \code{armada-xp-mv78230.dtsi}
      \item \code{armada-xp-mv78260.dtsi}
        \begin{itemize}
        \item Board \code{openblocks-ax3-4.dts}
        \end{itemize}
      \item \code{armada-xp-mv78460.dtsi}
        \begin{itemize}
        \item Board \code{armada-xp-db.dts}
        \end{itemize}
      \end{itemize}
    \end{itemize}
\end{frame}

\begin{frame}[fragile]{{\tt bcm2835.dtsi}}
\tiny
\begin{verbatim}
/include/ "skeleton.dtsi"
/ {
        compatible = "brcm,bcm2835";
        model = "BCM2835";
        interrupt-parent = <&intc>;

        chosen {
                bootargs = "earlyprintk console=ttyAMA0";
        };

        soc {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x7e000000 0x20000000 0x02000000>;

                [...]
                intc: interrupt-controller {
                        compatible = "brcm,bcm2835-armctrl-ic";
                        reg = <0x7e00b200 0x200>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                };
                uart@20201000 {
                        compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
                        reg = <0x7e201000 0x1000>;
                        interrupts = <2 25>;
                        clock-frequency = <3000000>;
                        status = "disabled";
                };
        };
};
\end{verbatim}
\end{frame}

\begin{frame}[fragile]{{\tt bcm2835-rpi-b.dts}}
\tiny
\begin{verbatim}
/dts-v1/;
/memreserve/ 0x0c000000 0x04000000;
/include/ "bcm2835.dtsi"

/ {
        compatible = "raspberrypi,model-b", "brcm,bcm2835";
        model = "Raspberry Pi Model B";

        memory {
                reg = <0 0x10000000>;
        };
        soc {
                uart@20201000 {
                      status = "okay";
                };
        };
};
\end{verbatim}
\end{frame}

\begin{frame}{Basic things in {\tt arch/arm/mach-<yourarch>}}
  \begin{itemize}
  \item \code{Kconfig}, describing your \code{ARCH_<yourarch>}
    option, as well as sub-options for each SoC if your family has
    multiple SoC. No per-board options: your kernel image is
    independent from the board details.
  \item \code{Makefile}, compiling just one file, \code{<yoursoc>.c}
  \item \code{<yoursoc>.c}, that contains a \code{DT_MACHINE_START}
    definition, either per SoC or per family of SoC
  \item \code{<yoursoc>.h}, that contains a minimal set of constants
    used to implement a static mapping for the registers used to
    access the UARTs. No constants with addresses or IRQ numbers for
    any other devices: they will be provided through the Device Tree.
  \end{itemize}
\end{frame}

\begin{frame}{Multi-SoC, multi-platform kernel}
  \begin{itemize}
  \item Originally a given Linux kernel image could only support
    multiple boards using a given SoC, boards being ``detected''
    thanks to the machine ID.
  \item Now, a given \code{mach-foo} directory must allow
    support for all the SoCs it supports to be compiled into a single
    kernel image. No more \codehack{\#ifdef} conditionals depending on
    SoCs, it must all be runtime detected.
  \item And further than that, now all new sub-architectures must be
    compatible with the \code{CONFIG_ARCH_MULTIPLATFORM} mechanism,
    which allows support for all SoCs to be built into a single
    binary kernel image.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{{\tt arch/arm/mach-<soc>/<soc>.c} (1)}
    \footnotesize
    \begin{minted}{c}
static struct map_desc mysoc_io_desc[] __initdata = {
      {
              .virtual        = (unsigned long) MYSOC_REGS_VIRT_BASE,
              .pfn            = __phys_to_pfn(MYSOC_REGS_PHYS_BASE),
              .length         = MYSOC_XP_REGS_SIZE,
              .type           = MT_DEVICE,
      },
};

void __init mysoc_map_io(void)
{
        iotable_init(mysoc_io_desc, ARRAY_SIZE(mysoc_io_desc));
}

struct sys_timer mysoc_timer = {
        .init           = mysoc_timer_init,
};
\end{minted}
\end{frame}

\begin{frame}[fragile]{{\tt arch/arm/mach-<soc>/<soc>.c} (2)}
    \footnotesize
    \begin{minted}{c}
static void __init mysoc_dt_init(void)
{
        of_platform_populate(NULL, of_default_bus_match_table,
                             NULL, NULL);
}

static const char * const mysoc_dt_compat[] = {
        "vendor,soc-model1",
        "vendor,soc-model2",
        NULL,
};

DT_MACHINE_START(MYSOC_DT, "Company Wonderful SoC (Device Tree)")
        .init_machine   = mysoc_dt_init,
        .map_io         = mysoc_map_io,
        .init_irq       = irqchip_init,
        .timer          = &mysoc_timer,
        .restart        = mysoc_restart,
        .dt_compat      = mysoc_dt_compat,
MACHINE_END
\end{minted}
\end{frame}

\begin{frame}[fragile]{{\tt arch/arm/mach-<soc>/<soc>.h}}
    \footnotesize
    \begin{minted}{c}
#ifndef __MYSOC_H
#define __MYSOC_H

#define MYSOC_REGS_PHYS_BASE    0xd0000000
#define MYSOC_REGS_VIRT_BASE    IOMEM(0xfeb00000)
#define MYSOC_REGS_SIZE         SZ_1M

#endif /* __MYSOC_H */
    \end{minted}
\end{frame}

\begin{frame}[fragile]{{\tt arch/arm/mach-<soc>/Kconfig}}
    \footnotesize
    \begin{minted}{c}
config ARCH_MYSOC
        bool "Wonderful SoC" if ARCH_MULTI_V7
        select CLKSRC_MMIO
        select COMMON_CLK
        select GENERIC_CLOCKEVENTS
        select GENERIC_IRQ_CHIP
        select IRQ_DOMAIN
        select MULTI_IRQ_HANDLER
        select PINCTRL
        select SPARSE_IRQ
    \end{minted}
\end{frame}

\begin{frame}{Earlyprintk support}
  \begin{itemize}
  \item The first thing to have is obviously {\em earlyprintk}
    support, to get early messages from the kernel.
  \item In \code{arch/arm/Kconfig.debug}, in the choice of
    \code{DEBUG_LL} UARTs, add an entry for your platform, and add an
    entry to \code{CONFIG_DEBUG_LL_INCLUDE} that references
    \code{arch/arm/include/debug/<yoursoc>.S}
  \item In \code{arch/arm/include/debug/}, implement the
    \code{addruart}, \code{senduart}, \code{waituart} and
    \code{busyuart} assembly macros. On many platforms (using 8250
    compatible or the PL011 serial IP), existing code can be re-used
    and only \code{addruart} needs to be implemented.
  \end{itemize}
\end{frame}

\begin{frame}{IRQ controller support}
  \begin{itemize}
  \item If your platform uses the GIC or VIC interrupt controllers,
    there are already drivers in \code{arch/arm/common}
  \item Otherwise, implement a new one in \code{drivers/irqchip/}
    (rather new rule, most of them still live in the
    \code{arch/arm/mach-<foo>} directory).
  \item It must support the \code{SPARSE_IRQ} and \code{irqdomain}
    mechanisms: no more fixed number of IRQs \code{NR_IRQS}: an {\em
      IRQ domain} is dynamically allocated for each interrupt
    controller.
  \item It must support the \code{MULTI_IRQ_HANDLER} mechanism, where
    your \code{DT_MACHINE_START} structure references the {\em IRQ
      controller handler} through its \code{->handle_irq()} field.
  \item In your \code{DT_MACHINE_START} structure, also call the
    initialization function of your IRQ controller driver using the
    \code{->init_irq()} field.
  \item Instantiated from your Device Tree \code{.dtsi} file.
  \end{itemize}
\end{frame}

\begin{frame}{Timer driver}
  \begin{itemize}
  \item Should be implemented in \code{drivers/clocksource}
  \item It must register
    \begin{itemize}
    \item A {\em clocksource} device, which using a free-running
      timer, provides a way for the kernel to keep track of time
      passing. See \code{clocksource_mmio_init()} if your timer value
      can be read from a simple memory-mapped register, or
      \code{clocksource_register_hz()} for a more generic solution.
    \item A {\em clockevents} device, which allows the kernel to
      program a timer for one-shot or periodic events notified by an
      interrupt. See \code{clockevents_config_and_register()}
    \end{itemize}
  \item Driver must have a Device Tree binding, and the device be
    instantiated from your Device Tree \code{.dtsi} file.
  \end{itemize}
\end{frame}

\begin{frame}{Serial port driver}
  \begin{itemize}
  \item These days, many ARM SoC use either a 8250-compatible UART, or
    the PL011 UART controller from ARM. In both cases, Linux already
    has a driver
    \begin{itemize}
    \item Just need to instantiate devices in your \code{.dtsi} file,
      and mark those that are available on a particular board with
      \code{status = "okay"} in the \code{.dts} file.
    \end{itemize}
  \item If you have a custom UART controller, then get ready for more
    fun. You'll have to write a complete driver in
    \code{drivers/tty/serial}
    \begin{itemize}
    \item A platform driver, with Device Tree binding, integrated with
      the {\em uart} and {\em console} subsystems
    \item Maintainer is Alan Cox, also Cc Greg Kroah-Hartmann who
      looks after the overall TTY layer.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{End of step 1}
  \begin{itemize}
  \item At this point, your system should boot all the way to a shell
  \item You don't have any storage device driver for now, but you can
    boot into a minimal root filesystem embedded inside an {\em
      initramfs}
  \item Time to submit your basic ARM SoC support. Don't wait to have
    all the drivers and all the features: submit something minimal
    {\bf as soon as possible}.
  \end{itemize}
\end{frame}

\begin{frame}{Step 2: more core infrastructure}
  \begin{center}
    \includegraphics[width=\textwidth]{elements-step2.pdf}
  \end{center}
\end{frame}

\begin{frame}{The 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 Implements {\bf some basic clock drivers} (fixed rate,
      gatable, divider, fixed factor, etc.) and allows the
      implementation of {\bf custom clock drivers} using
      \code{struct clk_hw} and \code{struct clk_ops}
    \item Allows to declare the available clocks and their association
      to devices in the Device Tree (preferred) or statically in the
      source code (old method)
    \item Provides a {\em debugfs} representation of the clock tree
    \item Is implemented in \path{drivers/clk}
    \item See \code{Documentation/clk.txt}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Clock framework, the driver side}
  From \path{drivers/serial/tty/amba-pl011.c}.
  \tiny
  \begin{minted}{c}
pl011_startup()
{
        [...]
        clk_prepare_enable(uap->clk);
        uap->port.uartclk = clk_get_rate(uap->clk);
        [...]
}

pl011_shutdown()
{
        [...]
        clk_disable_unprepare(uap->clk);
}

pl011_probe()
{
        [...]
        uap->clk = clk_get(&dev->dev, NULL);
        [...]
}

pl011_remove()
{
        [...]
        clk_put(uap->clk);
        [...]
}
  \end{minted}
\end{frame}

\begin{frame}[fragile]{Clock framework, declaration of clocks in DT}
  From \path{arch/arm/boot/dts/highbank.dts}
  \tiny
  \begin{minted}{perl}
clocks {
        #address-cells = <1>;
        #size-cells = <0>;

        osc: oscillator {
                #clock-cells = <0>;
                compatible = "fixed-clock";
                clock-frequency = <33333000>;
        };

        [...]

        emmcpll: emmcpll {
                #clock-cells = <0>;
                compatible = "calxeda,hb-pll-clock";
                clocks = <&osc>;
                reg = <0x10C>;
        };

        [...]

        pclk: pclk {
                #clock-cells = <0>;
                compatible = "fixed-clock";
                clock-frequency = <150000000>;
        };
};
  \end{minted}
\end{frame}

\begin{frame}[fragile]{Clock framework, devices referencing their clocks}
  From \path{arch/arm/boot/dts/highbank.dts}
  \small
  \begin{minted}{perl}
[...]
serial@fff36000 {
        compatible = "arm,pl011", "arm,primecell";
        reg = <0xfff36000 0x1000>;
        interrupts = <0 20 4>;
        clocks = <&pclk>;
        clock-names = "apb_pclk";
};
[...]
  \end{minted}
\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}{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 A 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}{GPIO}

  The GPIO subsystem has been around for quite some time now, only a
  few things have evolved recently:

  \begin{itemize}
  \item All GPIO drivers, including drivers for GPIO controllers
    internal to the SoC must be in \code{drivers/gpio}
  \item If the GPIO pins are muxed, the driver must interact with the
    {\em pinctrl} subsystem to get the proper muxing:
    \code{pinctrl_request_gpio()} and \code{pinctrl_free_gpio()}.
  \end{itemize}

\end{frame}

\begin{frame}{Step 3: more drivers, advanced features}
  \begin{center}
    \includegraphics[width=\textwidth]{elements-step3.pdf}
  \end{center}
\end{frame}

\begin{frame}{Device drivers}
  On the device driver side, not much has changed, except:
  \begin{itemize}
  \item Each device driver must have a {\bf device tree binding}
    \begin{itemize}
    \item A {\em binding} describes the {\em compatible} string and
      the properties that a DT node instantiating the device must
      carry.
    \item The binding must be documented in
      \code{Documentation/devicetree/bindings}
    \end{itemize}
  \item The drivers are no longer allowed to include
    \code{<mach/something.h>}, due to multi-platform kernel support.
  \end{itemize}
\end{frame}

\begin{frame}{Finding good examples}

  As things are moving quickly, not all ARM sub-architecture comply
  with the current best practices. The following recent ones are good
  starting points:

  \begin{itemize}
  \item \code{arch/arm/mach-highbank}
  \item \code{arch/arm/mach-socfpga}
  \item \code{arch/arm/mach-bcm2835}
  \item \code{arch/arm/mach-mxs}
  \item \code{arch/arm/mach-mvebu}
  \end{itemize}

\end{frame}

\begin{frame}{Conclusion}
  \begin{itemize}
  \item The code in the \code{arch/arm} tree has changed significantly over the last two years
  \item These changes allow the usage of more generic and common
    infrastructures and less SoC-specific code, which can only be a
    good thing
  \item However, the best practices are quickly evolving: requires
    to follow the Linux ARM Kernel mailing-list discussions constantly
    to stay aware of most recent changes.
  \end{itemize}
\end{frame}

\begin{frame}
  \begin{center}
  \Huge
  Questions?\\
  \vspace{1.5cm}
  \huge
  Thomas Petazzoni\\
  \large
  \vspace{0.5cm}
  \code{thomas.petazzoni@bootlin.com}
  \vspace{1.0cm}\\
  \normalsize
  Thanks to Gregory Clement (Bootlin, working with me on
  Marvell
  mainlining), Lior Amsalem and Maen Suleiman (Marvell)\\
  \vspace{0.5cm}
  Slides under CC-BY-SA 3.0\\
  \scriptsize
  \url{http://bootlin.com/pub/conferences/2012/elce/arm-soc-checklist/}
  \end{center}
\end{frame}

\end{document}
