add m_class
authorLuke Leighton <lkcl@lkcl.net>
Sun, 25 Feb 2018 09:48:05 +0000 (09:48 +0000)
committerLuke Leighton <lkcl@lkcl.net>
Sun, 25 Feb 2018 09:48:05 +0000 (09:48 +0000)
23 files changed:
shakti/m_class.mdwn [new file with mode: 0644]
shakti/m_class/ACT8846.jpg [new file with mode: 0644]
shakti/m_class/AP6335.jpg [new file with mode: 0644]
shakti/m_class/AXP209.jpg [new file with mode: 0644]
shakti/m_class/AXP803.jpg [new file with mode: 0644]
shakti/m_class/DM9000.jpg [new file with mode: 0644]
shakti/m_class/ES8323.jpg [new file with mode: 0644]
shakti/m_class/I2CSensors.jpg [new file with mode: 0644]
shakti/m_class/LevelShiftedMicroSD.jpg [new file with mode: 0644]
shakti/m_class/MU509.jpg [new file with mode: 0644]
shakti/m_class/PowerDomainMicroSD.jpg [new file with mode: 0644]
shakti/m_class/RT9502.jpg [new file with mode: 0644]
shakti/m_class/RT9711.jpg [new file with mode: 0644]
shakti/m_class/SIM7600.jpg [new file with mode: 0644]
shakti/m_class/SYR827.828.jpg [new file with mode: 0644]
shakti/m_class/TDA2822.jpg [new file with mode: 0644]
shakti/m_class/USBports.jpg [new file with mode: 0644]
shakti/m_class/Vregs.jpg [new file with mode: 0644]
shakti/m_class/gsoc2018.mdwn [new file with mode: 0644]
shakti/m_class/peripheralschematics.mdwn [new file with mode: 0644]
shakti/m_class/pinouts.mdwn [new file with mode: 0644]
shakti/m_class/pinouts.py [new file with mode: 0644]
shakti/m_class/ramanalysis.mdwn [new file with mode: 0644]

diff --git a/shakti/m_class.mdwn b/shakti/m_class.mdwn
new file mode 100644 (file)
index 0000000..8b71b72
--- /dev/null
@@ -0,0 +1,417 @@
+# Shakti M-Class Libre SoC
+
+This SoC is a propsed libre design that draws in expertise from mass-volume
+SoCs of the past six years and beyond, and is being designed to cover just
+as wide a range of target embedded / low-power / industrial markets as those
+SoCs.  Pincount is to be kept low in order to reduce cost as well as increase
+yields.
+
+* See <http://rise.cse.iitm.ac.in/shakti.html> M-Class for top-level
+* See [[pinouts]] for auto-generated table of pinouts (including mux)
+* See [[peripheralschematics]] for example Reference Layouts
+* See [[ramanalysis]] for a comprehensive analysis of why DDR3 is to be used.
+
+## Rough specification.
+
+Quad-core 28nm RISC-V 64-bit (RISCV64GC core with Vector SIMD Media / 3D
+extensions), 300-pin 15x15mm BGA 0.8mm pitch, 32-bit DDR3/DDR3L/LPDDR3
+memory interface and libre / open interfaces and accelerated hardware
+functions suitable for the higher-end, low-power, embedded, industrial
+and mobile space.
+
+A 0.8mm pitch BGA allows relatively large (low-cost) VIA drill sizes
+to be used (8-10mil) and 4-5mil tracks with 4mil clearance.  For
+details see
+<http://processors.wiki.ti.com/index.php/General_hardware_design/BGA_PCB_design>
+
+## Targetting full Libre Licensing to the bedrock.
+
+The only barrier to being able to replicate the masks from scratch
+is the proprietary cells (e.g. memory cells) designed by the Foundries:
+there is a potential long-term strategy in place to deal with that issue.
+
+The only proprietary interface utilised in the entire SoC is the DDR3
+PHY plus Controller, which will be replaced in a future revision, making
+the entire SoC exclusively designed and made from fully libre-licensed
+BSD and LGPL openly and freely accessible VLSI and VHDL source.
+
+In addition, no proprietary firmware whatsoever will be required to
+operate or boot the device right from the bedrock: the entire software
+stack will also be libre-licensed (even for programming the initial
+proprietary DDR3 PHY+Controller)
+
+# Inspiration from several sources
+
+The design of this SoC is drawn from at least the following SoCs, which
+have significant multiplexing for pinouts, reducing pincount whilst at
+the same time permitting the SoC to be utilised across a very wide range
+of markets:
+
+* A10/A20 EVB <http://hands.com/~lkcl/eoma/A10-EVB-V1-2-20110726.pdf>
+* RK3288 T-Firefly <http://www.t-firefly.com/download/firefly-rk3288/hardware/FR_RK3288_0930.pdf>
+* Ingenic JZ4760B <ftp://ftp.ingenic.cn/SOC/JZ4760B/JZ4760B_DS_REVISION.PDF>
+  LEPUS Board <ftp://ftp.ingenic.cn/DevSupport/Hardware/RD4760B_LEPUS/RD4760B_LEPUS_V1.3.2.PDF>
+* GPL-violating CT-PC89e <http://hands.com/~lkcl/seatron/>, 
+  and <http://lkcl.net/arm_systems/CT-PC89E/> this was an 8.9in netbook
+  weighing only 0.72kg and having a 3 HOUR battery life on a single 2100mAh 
+  cell, its casework alone inspired a decade of copycat china clone
+  netbooks as it was slowly morphed from its original 8.9in up to (currently)
+  an 11in form-factor almost a decade later in 2017.
+* A64 Reference Designs for example this: <http://linux-sunxi.org/images/3/32/Banana_pi_BPI-M64-V1_1-Release_201609.pdf>
+
+TI Boards such as the BeagleXXXX Series, or the Freescale iMX6
+WandBoard etc., are, whilst interesting, have a different kind of focus
+and "feel" about them, as they are typically designed by Western firms
+with less access or knowledge of the kinds of low-cost tricks deployed
+to ingenious and successful effect by Chinese Design Houses.  Not only
+that but they typically know the best components to buy.  Western-designed
+PCBs typically source exclusively from Digikey, AVNet, Mouser etc. and
+the prices are often two to **TEN** times more costly as a result.
+
+The TI and Freescale (now NXP) series SoCs themselves are also just as
+interesting to study, but again have a subtly different focus: cost of
+manufacture of PCBs utilising them not being one of those primary focii.
+Freescale's iMX6 is well-known for its awesome intended lifespan and support:
+**ninteen** years.  That does however have some unintended knock-on effects
+on its pricing.
+
+Instead, the primary input is taken from Chinese-designed SoCs, where cost
+and ease of production, manufacturing and design of a PCB using the planned
+SoC, as well as support for high-volume mass-produced peripherals is
+firmly a priority focus.
+
+# Target Markets
+
+* EOMA68 Computer Card form-factor (general-purpose, eco-conscious)
+* Smartphone / Tablet (basically the same thing, different LCD/CTP size)
+* Low-end (ChromeOS style) laptop
+* Industrial uses when augmented by a suitable MCU (for ADC/DAC/CAN etc.)
+
+## Common Peripherals to majority of target markets
+
+* SPI or 8080 or RGB/TTL or LVDS LCD display.  SPI: 320x240.  LVDS: 1440x900.
+* LCD Backlight, requires GPIO power-control plus PWM for brightness control
+* USB-OTG Port (OTG-Host, OTG Client, Charging capability)
+* Baseband Modem (GSM / GPRS / 3G / LTE) requiring USB, UART, and PCM audio
+* Bluetooth, requires either full UART or SD/MMC or USB, plus control GPIO
+* WIFI, requires either USB (but with power penalties) or better SD/MMC
+* SD/MMC for external MicroSD
+* SD/MMC for on-PCB eMMC (care needed on power/boot sequence)
+* NAND Flash (not recommended), requires 8080/ATI-style Bus with dedicated CS#
+* Optional 4-wire SPI NAND/NOR for boot (XIP - Execute In-place - recommended).
+* Audio over I2S (5-pin: 4 for output, 1 for input), fall-back to USB Audio
+* Some additional SPI peripherals, e.g. connection to low-power MCU.
+* GPIO (EINT-capable, with wakeup) for buttons, power, volume etc.
+* Camera(s) either by CSI-1 (parallel CSI) or better by USB
+* I2C sensors: accelerometer, compass, etc.  Each requires EINT and RST GPIO.
+* Capacitive Touchpanel (I2C and also requiring EINT and RST GPIO)
+* Real-time Clock (usually an I2C device but may be on-board a support MCU)
+
+## Peripherals unique to laptop market
+
+* Keyboard (USB or keyboard-matrix managed by MCU)
+* USB, I2C or SPI Mouse-trackpad (plus button GPIO, EINT capable)
+
+## Peripherals common to laptop and Industrial Market
+
+* Ethernet (RGMII or better 8080-style XT/AT/ATI MCU bus)
+
+## Augmentation by an embedded MCU
+
+Some functions, particularly analog, are particularly tricky to implement
+in an early SoC.  In addition, CAN is still patented.  For unusual, patented
+or analog functionality such as CAN, RTC, ADC, DAC, SPDIF, One-wire Bus
+and so on it is easier and simpler to deploy an ultra-low-cost low-speed
+companion Micro-Controller such as the crystal-less STMS8003 ($0.24) or
+the crystal-less STM32F072 or other suitable MCU, depending on requirements.
+For high-speed interconnect it may be wired up as an SPI device, and for
+lower-speed communication UART would be the simplest and easiest means of
+two-way communication.
+
+This technique can be deployed in all scenarios (phone, tablet, laptop,
+industrial), and is an extremely low-cost way of getting RTC functionality
+for example.  The cost of, for example, dedicated I2C sensors that provide
+RTC functionality, or ADC or DAC or "Digipot", are actually incredibly
+high, relatively speaking.  Some very simple software and a general-purpose
+MCU does the exact same job.  In particularly cost-sensitive applications,
+DAC may be substituted by a PWM, an RC circuit, and an optional feedback
+loop into an ADC pin to monitor situations where changing load on the RC
+circuit alters the output voltage.  All done entirely in the MCU's software.
+
+An MCU may even be used to emulate SPI "XIP" (Execute in-place) NAND
+memory, such that there is no longer a need to deploy a dedicated SPI
+NOR bootloader IC (which are really quite expensive).  By emulating
+an SPI XIP device the SoC may boot from the NAND Flash storage built-in
+to the embedded MCU, or may even feed the SoC data from a USB-OTG
+or other interface.  This makes for an extremely flexible bootloader
+capability, without the need for totally redoing the SoC masks just to
+add extra BOOTROM functions.
+
+## Common Internal (on-board) acceleration and hardware functions
+
+* 2D accelerated display
+* 3D accelerated graphics
+* Video encode / decode
+* Image encode / decode
+* Crypto functions (SHA, Rijndael, DES, etc., Diffie-Hellman, RSA)
+* Cryptographically-secure PRNG (hard to get right)
+
+### 2D acceleration
+
+The ORSOC GPU contains basic primitives for 2D: rectangles, sprites,
+image acceleration, scalable fonts, and Z-buffering and much more.
+
+<https://opencores.org/project,orsoc_graphics_accelerator>
+
+### 3D acceleration
+
+* MIAOW: ATI-compatible shader engine <http://miaowgpu.org/>
+* ORSOC GPU contains some primitives that can be used
+* SIMD RISC-V extensions can obviate the need for a "full" separate GPU
+
+### Video encode / decode
+
+* video primitives <https://opencores.org/project,video_systems>
+* MPEG decoder <https://opencores.org/project,mpeg2fpga>
+* Google make free VP8 and VP9 hard macros available for production use only
+
+### Image encode / decode
+
+partially covered by the ORSOC GPU
+
+### Crypto functions
+
+TBD
+
+### Cryptographically-secure PRNG
+
+TBD
+
+# Proposed Interfaces
+
+* RGB/TTL up to 1440x900 @ 60fps, 24-bit colour
+* 2x 1-lane SPI
+* 1x 4-lane (quad) SPI
+* 4x SD/MMC (1x 1/2/4/8-bit, 3x 1/2/4-bit)
+* 2x full UART incl. CTS/RTS
+* 3x UART (TX/RX only)
+* 3x I2C (in case of address clashes between peripherals)
+* 8080-style AT/XT/ATI MCU Bus Interface, with multiple (8x CS#) lines
+* 3x PWM-capable GPIO
+* 32x EINT-cable GPIO with full edge-triggered and low/high IRQ capability
+* 1x I2S audio with 4-wire output and 1-wire input.
+* 3x USB2 (ULPI for reduced pincount) each capable of USB-OTG support
+* DDR3/DDR3L/LPDDR3 32-bit-wide memory controller
+
+Some interfaces at:
+
+* <https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/>
+  includes GPIO, SPI, UART, JTAG, I2C, PinCtrl, UART and PWM.  Also included
+  is a Watchdog Timer and others.
+* <https://github.com/sifive/freedom/blob/master/src/main/scala/everywhere/e300artydevkit/Platform.scala>
+  Pinmux ("IOF") for multiplexing several I/O functions onto a single pin
+
+## I2S
+
+<https://github.com/skristiansson/i2s>
+
+## FlexBus
+
+FlexBus is capable of emulating the 8080-style / ATI MCU Bus, as well as
+providing support for access to SRAM.  It is extremely likely that it will
+provide access to MCU-style Ethernet PHY ICs such as the DM9000, the
+AX88180 (gigabit ethernet but an enormous number of pins), the AX88796A
+(8/16-bit 80186 or MC68k).
+
+## RGB/TTL interface
+
+<https://opencores.org/project,vga_lcd> full linux kernel driver also available
+
+## SPI
+
+* APB to SPI <https://opencores.org/project,apb2spi>
+* ASIC-proven <https://opencores.org/project,spi_master_slave>
+* Wishbone-compliant <https://opencores.org/project,simple_spi>
+
+## SD/MMC (including eMMC)
+
+* <https://opencores.org/project,sd_mmc_emulator>
+* (needs work) <https://opencores.org/project,sdcard_mass_storage_controller>
+
+# Pin Multiplexing
+
+Complex!  Covered in [[pinouts]].  The general idea is to target several
+distinct applications and, by trial-and-error, create a pinmux table that
+successfully covers all the target scenarios by providing absolutely all
+required functions for each and every target.  A few general rules:
+
+* Different functions (SPI, I2C) which overlap on the same pins on one
+ bank should also be duplicated on completely different banks, both from
+ each other and also the bank on which they overlap.  With each bank having
+ separate Power Domains this strategy increases the chances of being able
+ to place low-power and high-power peripherals and sensors on separate
+ GPIO banks without needing external level-shifters.
+* Functions which have optional bus-widths (eMMC: 1/2/4/8) may have more
+ functions overlapping them than would otherwise normally be considered.
+* Then the same overlapped high-order bus pins can also be mapped onto
+ other pins.  This particularly applies to the very large buses, such
+ as FlexBus (over 50 pins).  However if the overlapped pins are on a
+ different bank it becomes necessary to have both banks run in the same
+ GPIO Power Domain.
+* All functions should really be pin-muxed at least twice, preferably
+ three times.  Four or more times on average makes it pointless to
+ even have four-way pinmuxing at all, so this should be avoided.
+ The only exceptions (functions which have not been pinmuxed multiple
+ times) are the RGB/TTL LCD channel, and both ULPI interfaces.  
+
+## GPIO Pinmux Power Domains
+
+Of particular importance is the Power Domains for the GPIO.  Realistically
+it has to be flexible (simplest option: recommended to be between
+1.8v and 3.3v) as the majority of low-cost mass-produced sensors and
+peripherals on I2C, SPI, UART and SD/MMC are at or are compatible with
+this voltage range.  Long-tail (older / stable / low-cost / mass-produced)
+peripherals in particular tend to be 3.3v, whereas newer ones with a
+particular focus on Mobile tend to be 1.2v to 1.8v.
+
+A large percentage of sensors and peripherals have separate IO voltage
+domains from their main supply voltage: a good example is the SN75LVDS83b
+which has one power domain for the RGB/TTL I/O, one for the LVDS output,
+and one for the internal logic controller (typical deployments tend not
+to notice the different power-domain capability, as they usually supply all
+three voltages at 3.3v).
+
+Relying on this capability, however, by selecting a fixed voltage for
+the entire SoC's GPIO domain, is simply not a good idea: all sensors
+and peripherals which do not have a variable (VREF) capability for the
+logic side, or coincidentally are not at the exact same fixed voltage,
+will simply not be compatible if they are high-speed CMOS-level push-push
+driven.  Open-Drain on the other hand can be handled with a MOSFET for
+two-way or even a diode for one-way depending on the levels, but this means
+significant numbers of external components if the number of lines is large.
+
+So, selecting a fixed voltage (such as 1.8v or 3.3v) results in a bit of a
+problem: external level-shifting is required on pretty much absolutely every
+single pin, particularly the high-speed (CMOS) push-push I/O.  An example: the
+DM9000 is best run at 3.3v.  A fixed 1.8v FlexBus would
+require a whopping 18 pins (possibly even 24 for a 16-bit-wide bus)
+worth of level-shifting, which is not just costly
+but also a huge amount of PCB space: bear in mind that for level-shifting, an
+IC with **double** the number of pins being level-shifted is required.
+
+Given that level-shifting is an unavoidable necessity, and external
+level-shifting has such high cost(s), the workable solution is to
+actually include GPIO-group level-shifting actually on the SoC die,
+after the pin-muxer at the front-end (on the I/O pads of the die),
+on a per-bank basis.  This is an extremely common technique that is
+deployed across a very wide range of mass-volume SoCs.
+
+One very useful side-effect for example of a variable Power Domain voltage
+on a GPIO bank containing SD/MMC functionality is to be able to change the
+bank's voltage from 3.3v to 1.8v, to match an SD Card's capabilities, as
+permitted under the SD/MMC Specification.  The alternative is to be forced to
+deploy an external level-shifter IC (if PCB space and BOM target allows) or to
+fix the voltage at 3.3v and thus lose access to the low-power and higher-speed
+capabilities of modern SD Cards.
+
+In summary: putting level shifters right at the I/O pads of the SoC, after
+the pin-mux (so that the core logic remains at the core voltage) is a
+cost-effective solution that can have additional unintended side-benefits
+and cost savings beyond simply saving on external level-shifting components
+and board space.
+
+# Items requiring clarification, or proposals TBD
+
+## Core Voltage Domains from the PMIC
+
+See [[peripheralschematics]] - what default (start-up) voltage can the
+core of the proposed 28nm SoC cope with for short durations?  The AXP209
+PMIC defaults to a 1.25v CPU core voltage, and 1.2v for the logic.  It
+can be changed by the SoC by communicating over I2C but the start-up
+voltage of the PMIC may not be changed.  What is the maximum voltage
+that the SoC can run at, for short durations at a greatly-reduced clock rate?
+
+## 3.3v tolerance
+
+Can the GPIO be made at least 3.3v tolerant?
+
+## Shakti Flexbus implementation: 32-bit word-aligned access
+
+The FlexBus implementation may only make accesses onto the back-end
+AXI bus on 32-bit word-aligned boundaries.  How this affects FlexBus
+memory accesses (read and write) on 8-bit and 16-bit boundaries is
+yet to be determined.  It is particularly relevant e.g. for 24-bit
+pixel accesses on 8080 (MCU) style LCD controllers that have their
+own on-board SRAM.
+
+## Confirmation of GPIO Power Domains
+
+The proposed plan is to stick with a fixed 1.8v GPIO level across all
+GPIO banks.  However as outlined in the section above, this has some
+distinct disadvantages, particularly for e.g. SRAM access over FlexBus:
+that would often require a 50-way bi-directional level-shifter Bus IC,
+with over 100 pins!
+
+## Proposal / Concept to include "Minion Cores" on a 7-way pinmux
+
+The lowRISC team first came up with the idea, instead of having a pinmux,
+to effectively bit-bang pretty much all GPIO using **multiple** 32-bit
+RISC-V non-SMP integer-only cores each with a tiny instruction and data
+cache (or, simpler, access to their own independent on-die SRAM).
+The reasoning behind this is: if it's a dedicated core, it's not really
+bit-banging any more.  The technique is very commonly deployed, typically
+using an 8051 MCU engine, as it means that a mass-produced peripheral may
+be firmware-updated in the field for example if a Standard has unanticipated
+flaws or otherwise requires updating.
+
+The proposal here is to add four extra pin-mux selectors (an extra bit
+to what is currently a 2-bit mux per pin), and for each GPIO bank to map to
+one of four such ultra-small "Minion Cores".  For each pin, Pin-mux 4 would
+select the first Minion core, Pin-mux 5 would select the second and so on.
+The sizes of the GPIO banks are as follows:
+
+* Bank A: 16
+* Bank B: 28
+* Bank C: 24
+* Bank D: 24
+* Bank E: 24
+* Bank F: 10
+
+Therefore, it is proposed that each Minion Core have 28 EINT-capable
+GPIOs, and that all but Bank A and F map their GPIO number (minus the
+Bank Designation letter) direct to the Minion Core GPIOs.  For Banks
+A and F, the numbering is proposed to be concatenated, so that A0 through
+A15 maps to a Minion Core's GPIO 0 to 15, and F0 to F10 map to a Minion
+Core's GPIO 16 to 25 (another alternative idea would be to split Banks
+A and F to complete B through E, taking them up to 32 I/O per Minion core).
+
+With careful selection from different banks it should be possible to map
+unused spare pins to a complete, contiguous, sequential set of any given
+Minion Core, such that the Minion Core could then bit-bang anything up to
+a 28-bit-wide Bus.  Theoretically this could make up a second RGB/TTL
+LCD interface with up to 24 bits per pixel.
+
+For low-speed interfaces, particularly those with an independent clock
+that the interface takes into account that the clock changes on a different
+time-cycle from the data, this should work perfectly fine.  Whether the
+idea is practical for higher-speed interfaces or or not will critically
+depend on whether the Minion Core can do mask-spread atomic
+reads/writes from a register to/from memory-addressed GPIO or not,
+and faster I/O streams will almost certainly require some form of
+serialiser/de-serialiser hardware-assist, and definitely each their
+own DMA Engine.
+
+If the idea proves successful it would be extremely nice to have a
+future version that has direct access to generic LVDS lines, plus
+S8/10 ECC hardware-assist engines.  If the voltage may be set externally
+and accurate PLL clock timing provided, it may become possible to bit-bang
+and software-emulate high-speed interfaces such as SATA, HDMI, PCIe and
+many more.
+
+# Research (to investigate)
+
+* <https://level42.ca/projects/ultra64/Documentation/man/pro-man/pro25/index25.1.html>
+* <http://n64devkit.square7.ch/qa/graphics/ucode.htm>
+* <https://dac.com/media-center/exhibitor-news/synopsys%E2%80%99-designware-universal-ddr-memory-controller-delivers-30-percent> 110nm DDR3 PHY
+[[!tag cpus]]
+
diff --git a/shakti/m_class/ACT8846.jpg b/shakti/m_class/ACT8846.jpg
new file mode 100644 (file)
index 0000000..06d9609
Binary files /dev/null and b/shakti/m_class/ACT8846.jpg differ
diff --git a/shakti/m_class/AP6335.jpg b/shakti/m_class/AP6335.jpg
new file mode 100644 (file)
index 0000000..c214f21
Binary files /dev/null and b/shakti/m_class/AP6335.jpg differ
diff --git a/shakti/m_class/AXP209.jpg b/shakti/m_class/AXP209.jpg
new file mode 100644 (file)
index 0000000..7ef3fdc
Binary files /dev/null and b/shakti/m_class/AXP209.jpg differ
diff --git a/shakti/m_class/AXP803.jpg b/shakti/m_class/AXP803.jpg
new file mode 100644 (file)
index 0000000..0978f95
Binary files /dev/null and b/shakti/m_class/AXP803.jpg differ
diff --git a/shakti/m_class/DM9000.jpg b/shakti/m_class/DM9000.jpg
new file mode 100644 (file)
index 0000000..fd5acee
Binary files /dev/null and b/shakti/m_class/DM9000.jpg differ
diff --git a/shakti/m_class/ES8323.jpg b/shakti/m_class/ES8323.jpg
new file mode 100644 (file)
index 0000000..4b73930
Binary files /dev/null and b/shakti/m_class/ES8323.jpg differ
diff --git a/shakti/m_class/I2CSensors.jpg b/shakti/m_class/I2CSensors.jpg
new file mode 100644 (file)
index 0000000..6e19c5b
Binary files /dev/null and b/shakti/m_class/I2CSensors.jpg differ
diff --git a/shakti/m_class/LevelShiftedMicroSD.jpg b/shakti/m_class/LevelShiftedMicroSD.jpg
new file mode 100644 (file)
index 0000000..86b6d50
Binary files /dev/null and b/shakti/m_class/LevelShiftedMicroSD.jpg differ
diff --git a/shakti/m_class/MU509.jpg b/shakti/m_class/MU509.jpg
new file mode 100644 (file)
index 0000000..c57029a
Binary files /dev/null and b/shakti/m_class/MU509.jpg differ
diff --git a/shakti/m_class/PowerDomainMicroSD.jpg b/shakti/m_class/PowerDomainMicroSD.jpg
new file mode 100644 (file)
index 0000000..b10ad8d
Binary files /dev/null and b/shakti/m_class/PowerDomainMicroSD.jpg differ
diff --git a/shakti/m_class/RT9502.jpg b/shakti/m_class/RT9502.jpg
new file mode 100644 (file)
index 0000000..a3bd778
Binary files /dev/null and b/shakti/m_class/RT9502.jpg differ
diff --git a/shakti/m_class/RT9711.jpg b/shakti/m_class/RT9711.jpg
new file mode 100644 (file)
index 0000000..d56cda9
Binary files /dev/null and b/shakti/m_class/RT9711.jpg differ
diff --git a/shakti/m_class/SIM7600.jpg b/shakti/m_class/SIM7600.jpg
new file mode 100644 (file)
index 0000000..c764bf7
Binary files /dev/null and b/shakti/m_class/SIM7600.jpg differ
diff --git a/shakti/m_class/SYR827.828.jpg b/shakti/m_class/SYR827.828.jpg
new file mode 100644 (file)
index 0000000..6ac1de9
Binary files /dev/null and b/shakti/m_class/SYR827.828.jpg differ
diff --git a/shakti/m_class/TDA2822.jpg b/shakti/m_class/TDA2822.jpg
new file mode 100644 (file)
index 0000000..f3b84df
Binary files /dev/null and b/shakti/m_class/TDA2822.jpg differ
diff --git a/shakti/m_class/USBports.jpg b/shakti/m_class/USBports.jpg
new file mode 100644 (file)
index 0000000..edf3e09
Binary files /dev/null and b/shakti/m_class/USBports.jpg differ
diff --git a/shakti/m_class/Vregs.jpg b/shakti/m_class/Vregs.jpg
new file mode 100644 (file)
index 0000000..f482dc7
Binary files /dev/null and b/shakti/m_class/Vregs.jpg differ
diff --git a/shakti/m_class/gsoc2018.mdwn b/shakti/m_class/gsoc2018.mdwn
new file mode 100644 (file)
index 0000000..5e531ce
--- /dev/null
@@ -0,0 +1,83 @@
+# Goal
+
+The goal is to create, test and document a working pinmux (switchbox),
+with extended goals, time permitting, to add actual multiplexed peripherals
+to a pre-existing working core (lowRISC, ZipCPU, OR1k) and a further goal
+to get actual linux kernel drivers up and running.  This could be part
+of an existing team, or a single-person project, or a team project.
+All communication will be carried out on a public mailing list at all
+times, as part of the goal is to allow absolutely anyone to help if they
+feel so inclined.
+
+# Details
+
+Starting from a known-good working pre-existing SoC running well on
+a standard FPGA platform and having a few pre-existing proven
+peripherals working, the idea is to add a multiplexer so that the actual I/O
+pins can switch to different functions, just like any Embedded STM32F,
+or any Texas Instruments OMAP Series processor.
+
+A pre-existing multiplexer already exists which may provide a good starting
+point: https://github.com/wallento/pmod_switchbox.  Another exists
+in the form of the SiFive "IOF":
+https://github.com/sifive/freedom/blob/master/src/main/scala/everywhere/e300artydevkit/Platform.scala
+
+Additional peripherals
+in the form of PWM, UART, I2C, SPI, SD/MMC and RGB/TTL already exist on
+http://opencores.org so there will be no need to develop those.
+
+If RISC-V is chosen (for example the lowRISC ethernet-0.5 branch
+https://github.com/lowRISC/lowrisc-chip/tree/ethernet-v0.5) then the
+first task will be to move the MicroSD and Ethernet peripherals aside
+and place the GPIO pinmux in between.  This should be a relatively
+straightforward task that on its own is a significant contribution,
+and the project could be declared to be a success even if this was the
+only task that was completed.
+
+The next phase, where it gets interesting, would be to track down a suitable
+linux kernel driver for GPIO and rewrite it (or the pmod switchbox VHDL) to
+match precisely a pre-existing memory-mapped linux kernel GPIO driver.
+This would then need to be tested, demonstrating that the pins formerly
+used for MicroSD for example can now be switched to Input or Output.
+
+The next phase after that, again if time permits, would be to incorporate
+further peripherals such as PWM, I2C, UART, SPI and others, as desired.
+Recommended priority here will be on saving time by tracking down code
+that already has pre-existing linux kernel drivers that match up with
+the associated Verilog / VHDL, so that time is not spent exclusively writing
+c code or exclusively writing Verilog / VHDL.
+
+This project is therefore primarily about cross-skill integration and
+communication, and learning to work and collaborate "in the public eye",
+which takes either quite a lot of confidence, or just a particularly
+honest and open mind-set.
+
+Skill level: varies from Beginner to Advanced.
+
+Language / Tool: varied.  VHDL/Verilog/Chisel essential, c optional,
+                 git, mailing lists, wikis, good written communication
+                 skills in English absolutely essential.
+
+Mentor: Luke Kenneth Casson Leighton, Stefan Wallentowitz.
+
+# Notes
+
+## <https://lists.librecores.org/pipermail/discussion/2018-January/000406.html>
+
+Some additional considerations:
+
+Glitchless muxing::    Pads must never glitch when switched.
+
+Request/Grant handshake::  Multiple requests can occur at the same time and control goes to the highest priority.
+A grant signal notifies the winner and losing input pads are driven to a specified value (1,0 ,other signal)
+
+Fast path for main function::  The pads main function is the most important signal but it only controls the pad when no one
+else wants it. You want it one mux level from the pad and must not have to go through a bunch of muxes.
+
+Jtag mode:: Boundary scan must test mission mode signals going to pad
+
+
+Test mode:: For any and all scan,mbist or test signals. Must not go through jtag Boundary scan.
+
+Reset mode: Forces pad into reset state during power on reset
+
diff --git a/shakti/m_class/peripheralschematics.mdwn b/shakti/m_class/peripheralschematics.mdwn
new file mode 100644 (file)
index 0000000..4e8c8c1
--- /dev/null
@@ -0,0 +1,658 @@
+# Example Reference Schematics for Peripherals
+
+# Selection of a suitable PMIC
+
+Selecting a PMIC is tricky.  Corporations such as Intel have gotten themselves
+into a lot of trouble by supplying an SoC under NDA, then forgetting that
+it's ultra-important to supply an easily-accessible PMIC that doesn't
+additionally require a totally separate NDA just to gain access to it!
+Total madness: cartelling by accident or by design (literally).
+
+Allwinner's solution was to actually buy a PMIC company (X-Powers), and
+for every new SoC they actually designed a corresponding companion PMIC,
+often selling it along-side the SoC at a combined price.  Ingenic, as
+a smaller company, picks off-the-shelf PMICs from Actions Semi (typically
+the ACT8600 or similar).  Rockchip also picked Actions Semi PMICs for
+the RK3288 designs but unlike the majority of X-Powers (AXP) offerings,
+none of these cover battery charging or OTG Power-switching.
+
+DCin, battery and OTG "Charging" is a **three-way** power-routing problem
+that, due to the amounts of current involved, and the possibility of
+blowing up lithium cells and causing people's houses to catch fire, is
+somthing that has to be taken very very seriously.
+Not blowing up devices by getting into a current bun-fight over who is
+going to supply 5.0v (battery, main power, DCin or the USB charger) is
+really quite complicated, and the AXP209 in conjunction with SY6280
+current-limiter ICs per USB port can take care of that, easily enough.
+
+Without this integrated capacity to route power it actually becomes
+extremely hair-raising and requires something like 60 discrete components
+and ICs to replicate (see jz4760 reference schematics "LEPUS Board"
+for an example).  Alternatives for higher power (up to 4.5A) but not
+the same level of integration as the AXP209, include the bq2419x series
+from TI.  Using anything from the bq24193 series still requires external
+components for 3-way power protection, as well as an external high-current
+efficient power-regulator to drop the input DC down to a stable 5V supply.
+
+Alternatives which do not have the same OTG Power provision
+but are lower cost and around the same current include the ACT8600 (2A),
+and the ACT8846 which can handle around 3A but requires companion
+ICs (SYR627 and SYR628) for the SoC core domain supply (see below).
+Another option would be something like the AXP803, however this PMIC
+requires a rather large companion MOSFET to handle / switch the battery
+and charging current, where the AXP209, by being less power-hungry,
+has that same MOSFET integrated.
+
+A critical aspect of PMIC selection is that the default output voltages
+at power-up are compatible with the SoC.  Supply voltages **need** to be set
+so that during low clock rate operation the amount of power consumed is
+greatly reduced, however at higher clockrates the current draw of flipping
+1s to 0s and vice-versa causes a voltage drop that takes 1s and 0s outside
+of their "definitions".  The solution: increase the voltage supply.
+
+The AXP209's main "core voltage" DCDC converter
+defaults to 1.2v for example, and the
+DCDC converter that is used for supplying the
+DRAM typically defaults to 1.5v.  **These voltages are typically hard-wired
+into the PMIC's firmware**.
+Some PMICs may be re-programmed manually (at the factory) i.e have
+an on-board EEPROM, but this adds considerable complexity to manufacturing,
+as the PMIC must be pre-programmed **before** it can be safely connected
+to the SoC.
+
+So to avoid cartel scenarios and also to avoid custom-ordering of (minimum
+10k-50k PMICs), and to avoid the manufacturing and design complexity of
+re-programming the PMIC before it can be connected to the SoC, the best
+course of action is to analyse some available and extremely common PMICs,
+find out what their default outputs are, and then **arrange the SoC and
+the DRAM to be compatible with them** rather than the other way round.
+Primarily it is the core CPU voltage that, if exceeded, could damage the
+processor: the PMICs below default to between 1.0 and 1.25v; the DRAM
+voltage also typically defaults to 1.5v, meaning that DRAM ICs selected
+for the application will need to be rated for that.  During the first
+second or so of startup, the boot firmware will need to get the SoC to
+communicate with the PMIC and set more suitable voltages before carrying
+on with the boot process.  This is a Standard Operational Procedure
+which is encoded into either the BIOS or into u-boot.
+
+## AXP209
+
+An extremely well-supported, very simple-to-deploy and very comprehensive
+PMIC that includes support for USB OTG power flipping as well as battery
+charging.  It copes with up to around a 2A power provision.
+
+Control Signals for the AXP209 are as follows:
+
+* NMI# - Non-maskable Interrupt.  connect to main SoC.  absolutely critical.
+* PWRON - Power On.  Press-and-hold style, generates IRQ for SoC to shut down.
+* I2C SDA/SCL - for being able to manage the PMIC, change voltage output levels
+* GPIO1-3 - spare GPIO accessible over the I2C Bus
+* VBUSEN# - for controlling (enabling) the VBUS power.
+
+This latter signal - VBUSEN# - is absolutely critical.  The AXP209 can cut
+the power when needed (when an OTG charger is plugged in), or it can do so as
+directed by the SoC, which detects incoming power or there is the required
+OTG "ID" negotiated.
+
+Power outputs are roughly as follows:
+
+* IPSOUT - basically either the battery or the 5V DC mains input.  Needs
+  to be boosted (e.g. SY7208) to provide a stable 5.0v
+* DCDC outputs - the exact voltages are under I2C control.  They're high
+  current, usually used for the DDR3 main supply, core SoC supply and so on.
+* LDO outputs - again controlled through I2C.  Typically used for Camera,
+  Analog 3.3v and so on (around 200-300mA).  One of them is suitable for a
+  RTC supply, when the rest of the board (and the PMIC) are in shut-down mode.
+
+Note that for the CPU and DDR3, the SoC has to either be designed to cope
+with the default pre-set voltages (1.2v for the CPU core for example and
+1.5v for DDR3) and to run for a very short while on those whilst the CPU gets
+a chance to change them by communicating over the I2C Bus to the PMIC, or it
+is necessary to **custom-order** a very special PMIC with preset voltages
+from a PMIC Manufacturer, which means a MOQ of 10k to 50k units.
+
+Honestly it is simpler to just design the SoC to cope with the higher voltage.
+
+[[!img  AXP209.jpg]]
+
+# ACT8846 with SYR827 and SYR828 companion ICs
+
+This PMIC is used typically in conjunction with the 28nm Rockchip RK3288,
+and full schematics may be found by searching for "T-Firefly" and also
+"EOMA68-RK3288".  Like the AXP209 it is an integrated PMIC but it does **not**
+handle battery charging or VBUS detection and OTG triple-way power switching.
+
+It does however, in combination with the SYR827 and SYR828, handle a lot
+more power than the AXP209 (2.8A for two of its DC-DC converters).  The SYR827
+and SYR828 are used on the RK3288 to provide the SoC core domain power and
+the GPU core power, respectively.  The default voltage is 1.0 volts and may
+be reduced or increased under I2C control as needed.
+
+[[!img  ACT8846.jpg]]
+
+[[!img  SYR827.828.jpg]]
+
+# AXP803 and companion MOSFET for Battery
+
+The AXP803 handles a lot more current and has a lot more options than the
+AXP209: it's a bit larger, a bit more expensive, but is specifically designed
+for modern quad-core SoCs.  It can also handle a lot more current for charging
+because the battery MOSFET is an external IC.
+
+The A64 for which this PMIC was first deployed is a 40nm quad-core SoC, so
+the default power domains are designed specifically for that SoC.
+
+Control Signals include:
+
+* I2C for control, access to GPIO and selection of voltages on all outputs
+* 2 GPIOs which may be switched to an additional pair of LDOs
+* NMI# - Non-Maskable Interrupt.  Critical to be connected to the SoC.
+* RESET# - a reset signal
+* PWR-ON - press or press-and-hold, used for hard power-cycling of the device
+* USB-DM/DP - this is to detect the presence of an OTG device in a clean way
+* USBVBUSEN - just as with the AXP209 this controls power to the OTG port.
+
+The AXP803 has additional capability to detect whether a USB 3.0 OTG Charger
+has been connected (so that additional current may be negotiated).  This is
+most likely the reason why the USB+/- lines have to be connected to the PMIC.
+
+Outputs include:
+
+* 6 DC-DC converters
+* 3 ELDOs (extremely low-dropout outputs, for high-stability)
+* 4 DLDOs (digital LDOs)
+* 3 ALDOs (separate LDOs for Analog supply)
+* 2 FLDOs (no idea what these are: refer to the datasheet)
+* Dedicated RTC VCC supply
+
+Overall it is an extremely sophisticated PMIC which has the advantage of being
+mass-produced, proven (just like the AXP209 before it), and significant
+linux kernel driver support that is well-understood.
+
+[[!img  AXP803.jpg]]
+
+# Ingenic JZ4760 PMIC Approach: Discrete ICs
+
+The team that did the Ingenic JZ4760 LEPUS Reference Design decided to take
+a different approach to Power Management: multiple discrete ICs for each
+power domain.  They selected multiple RT8008 ICs and used different resistors
+to set the required current (which is then not adjustable, but the jz4760 is
+so low power anyway that this doesn't really matter), and used RT9169 and other
+3-pin LDOs for the RTC and low-power 1.2v supply.
+
+Of particular interest is how they did battery charging and the USB OTG
+power-switching.  For the battery charging including being able to charge
+from either a 5V DCin or the OTG VBUS, they selected the RT9502.  A MOSFET
+protects against power input from VBUS fighting with DCIN, and a Schottky
+Diode protects against current fights.  A **second** MOSFET and Schottky
+Diode allows power-selection of either battery or DCin to the RT9502.
+All in all it's quite a sophisticated and clever circuit.
+
+[[!img  RT9502.jpg]]
+
+USB Power Switching - selecting between either 5V or VBUS to go in (or out)
+of the OTG Port without blowing anything up - is done with a matched pair
+of RT9711A and RT9711B ICs.  A SY6280 has not been deployed, so it is not
+precisely clear which IC does the current-provision / over-current protection
+on the OTG port.
+
+In addition to these discrete ICs for power provision, there is the usual
+step-up converter (an RT9266) which converts the 3.8-4.2v battery directly
+into a stable +5V supply.  This is fairly normal, and can be seen in
+pretty much every design (whether using the AXP209, AXP803, ACT8600, ACT8846
+and so on).  It is very interesting in this case however to note that
+the DCin is wired (via the two MOSFETs and Schottky Diodes) directly to
+BAT-V (and thus supplies the +5V rail) but that, thanks to those MOSFETs
+and Schottkys, if either VBUS powers up or the battery powers up, they
+**replace** the power stream to BAT-V in a priority-cascade.
+
+This example is included to show that power-provision **can** be done without
+a dedicated PMIC (but also demonstrating quite how many components it
+actually needs, to do so).  Perhaps it might even still be a viable solution,
+by replacing some of the discrete (fixed) SY8008 LDOs with SYR828 and SYR829
+I2C-controllable high-current voltage regulators.
+
+[[!img  RT9711.jpg]]
+
+[[!img  Vregs.jpg]]
+
+# USB-OTG and USB-Host Ports
+
+This section covers how to set up an OTG port and a plain USB2 Host port.
+The USB Host is quite straightforward: protect the power with a SY6280 which
+performs current-limiting and also stops over-voltage from the USB port
+bleeding back down into the 5V supply (if someone does something silly like
+connect a 5.5v or 6v PSU to the USB port), and that's basically it, apart
+from one note-worthy fact that the SY6280 may be enabled/disabled under the
+control of the SoC in order to save power or to carry out a hard-reset on USB
+devices.
+
+The OTG port is slightly different.  Note that there are 2 power lines and
+3 I/O signals involved:
+
+* VCC-5V input - for when power is **supplied** to the USB port (OTG Host)
+* USBVBUS - for when power is supplied **by** the USB port
+ (OTG Client aka usually "OTG Charging")
+* USB-ID - for OTG negotiation of which end is to be Client and which Host
+* VBUSDET - a resistor-divider bridge allowing the SoC to detect USBVBUS on/off
+* USB-DRV - enables or disables the VCC-5V power **supply** (but does not
+ affect, involve, or otherwise stop VBUS - outgoing or incoming)
+
+It is a good idea to place the USB-DRV under the control of the PMIC, so that
+it may detect when a charger is plugged in, even if the main SoC is powered
+down.  Bear in mind that this all is a cooperative arrangement where the SoC
+and the PMIC must collaborate to prevent power-loss and current bun-fights.
+VBUSDET must be arranged so that the resistor-divider bridge creates just
+enough of a voltage to trigger an EINT-capable GPIO on the SoC with a "HIGH"
+or "LOW" digital level (not an ADC in other words).
+
+[[!img  USBports.jpg]]
+
+# Level-shifted MicroSD
+
+For instances where the GPIO voltage of the SoC's I/O is not 3.3v, the
+deployment of a level-shifter is needed.  Note the inclusion of ESD protection
+(which needs to be very close to the SD card slot) and the 47k pull-up
+resistors.  Strictly speaking the Card Detect line (which is an Open Drain)
+need not be routed through the level-shifter, whereas the SDcard signals,
+which are push-push high-speed, definitely do.  Many "Arduino-style" 
+amateur-deployed level shifting techniques are in fact Open-Drain style and
+really do not work properly as they rely on the internal capacitance of
+pins and tracks to drop towards Ground levels: this simply doesn't happen
+quickly enough, corrupting the signal integrity and is why push-push was
+invented in the first place.
+
+This schematic could actually be dynamically converted to adjustable 3.3v/1.8v
+by replacing the level-shifter VCC-3V3 input power (U2, VCCB) with a power
+source that is under the control of the SoC.  When the SoC detects
+that the inserted card has 1.8v capability, the SoC could then drop the
+level-shifter's B side down from 3.3v signal levels to 1.8v levels... all
+without having to adjust the actual SoC GPIO levels.  The down-side:
+level-shifter ICs are around USD $1, take up a lot of board space relatively
+speaking, and require double the number of pins as I/O signals.
+
+[[!img  LevelShiftedMicroSD.jpg]]
+
+# Power-domain-controlled MicroSD
+
+This second circuit is much simpler in principle yet may still adjust the
+SD/MMC power levels from 3.3v to 1.8v as required.  Also note that the
+SD Card itself may be powered down under the control of a GPIO signal 
+(named SDMMC-PWR) from the SoC.
+
+The level-shifting trick however in this case relies on the capability of the
+SoC and requires the cooperation of the PMIC.  A specific LDO output from the
+PMIC is dedicated to this **one** SD card, and the **entire** power domain
+for this particular GPIO-bank (which happens only to have SD/MMC on it)
+is flipped from 3.3v down to 1.8v if needed.
+
+Note that whilst this GPIO voltage domain power-drop occurs the actual SD
+card itself is still supplied by 3.3v.  Also note that in this circuit
+the SD-Det is still powered from SDIO (3.3v) so the SoC GPIO will need
+to be 3.3v tolerant even when it is dropped to 1.8v signalling levels.
+
+The alternative scheme would be to have an on-board level-shifter where the
+SD/MMC signal levels (only) are shifted between 3.3v and 1.8v levels, whilst
+leaving the rest of the entire GPIO bank's voltage levels alone.  This seems
+inordinately overcomplex.
+
+[[!img  PowerDomainMicroSD.jpg]]
+
+# AC97-compliant (I2S) Audio
+
+Under certain circumstances, USB Audio may be preferred over I2S (the
+CM108AH is a very good low-cost choice that is still mass-produced and
+has full schematics and no NDAs required).  However USB bulk audio
+framing introduces latency that may prove intolerable under certain
+high-end circumstances (Media Centre for example).  I2S was designed
+for low-latency and high-quality Digital Audio, send and receive.
+
+An example AC97-compliant Audio IC is the ES8323.  In this instance it
+is a very low-cost one (around $0.50 for single quanties from multiple
+vendors on taobao.com), that only has a single stereo earphone output and
+a single mono microphone input.  For ultra-low-cost applications this
+is perfectly fine, considering the price and high availability.  Also,
+using the right type of stereo headphone jack (a PJ-0345 6-pin) it
+becomes possible to hard-switch (and detect - using another of the
+precious EINT lines to the SoC) stereo headphone jack insertion and to
+route both outputs, via the headphone jack, back to a pair of low-cost
+audio amplifier ICS (TDA2822), the important thing being that this
+requires **no** additional signals or involvement or wires to/from the
+AC97 Audio IC.  It's crude but effective: the only thing needed to watch
+out for is to make sure that the jack insertion (or removal) is properly
+detected and that the audio volume level adjusted in sufficient time
+(if needed).  Careful inclusion of the right resistor-divider bridges
+etc. can mitigate even against needing to do that.
+
+Control signals to the ES8323 are:
+
+* 5-pin I2S: this includes, in this example, only one DO and only one DI.
+* I2C: used to control the ES8323 (volume, configuration)
+
+Audio signals are:
+
+* Mono Microphone input
+* Stereo Headphone
+
+Many more sophisticated examples exist, which include 5-lane I2S (4 output,
+1 input) for Dolby 5.1 and 7 Surround Sound, multiple audio paths including
+Line-out, Line-in, Car Stereo, etc. etc. - one obsolete one that was extremely
+good was the Akai AK4641 used in the HTC Universal clamshell / micro-laptop
+smartphone.  All in all it just depends on the application but the actual
+signals / buses involved remains pretty much the same in all cases: I2S for
+Audio data, I2C for control of the IC (AC97 volumes and routing etc.) and
+optional GPIO for detection e.g. of physical insertion of headphone and
+other jacks.  That's about it.
+
+[[!img  ES8323.jpg]]
+
+[[!img  TDA2822.jpg]]
+
+# 802.11 WIFI and BT
+
+**WARNING: there are *NO* low-power embedded WIFI ICs that are RYF-Endorseable.
+*ALL* firmware for *ALL* embedded (SD/MMC) WIFI SIP modules and ICs are
+proprietary and cannot in any way be trusted not to compromise a machine
+through *built-in* factory-installed spying, or hardware level malicious
+hacking (this is not a theoretical concept: it has been successfully
+demonstrated by Security Researchers, numerous times on numerous chipsets
+and numerous architectures and OSes).  If you include a hard-wired
+SD/MMC embedded WIFI SIP module hard-soldered to a PCB it is a sure-fire
+*GUARANTEED* way to 100 percent *FAIL* RYF Endorsement and Certification.
+If RYF Endorsement and the safety and privacy of end-users is important,
+ensure that the WIFI module may be *REMOVED* (physically by the user
+or simply not installed at the factory) and USB-based WIFI such as the
+ThinkPenguin TP150N, a small 802.11abgn WIFI dongle, inserted into the
+device instead (either internally or externally) with the end-user having
+the right to remove it.**
+
+With that huge warning out of the way, we can move on to describe the signals
+required for an example 802.11a/b/g/n/ac WIFI and BT 4.0 SIP Module.  These
+are:
+
+* 4-lane SD/MMC for the WIFI data.  This is standard for low-power SIP WIFI
+* 4-wire UART for Bluetooth, including TX/RX as well as CTS/RTS.
+* Quite a lot of IRQ and communication lines: up to five EINTs and GPIO in
+ the case of this particular SoC.
+
+The GPIO lines particularly EINTs are critical for WIFI and Bluetooth,
+particularly as applications may be adversely affected by clashes of these
+two protocols sharing the same 2.4ghz frequency bands.  So the OS needs to
+know when a clash is detected, immediately: that requires an EINT-capable
+GPIO, on its own.  Also, BT or WIFI (separately) may be used to wake up a
+host that has been placed into low-power sleep mode: again, that requires
+two separate and distinct EINT-capable GPIO lines.
+
+This particular WIFI SIP module also takes a 32.768kHz RTC input signal
+(which may be generated by the SoC or by a companion MCU), and it is also
+recommended to dedicate an additional GPIO to a MOSFET or other means to
+hard-kill the entire WIFI module.
+
+So on the face of it, it seems very straightforward, just route SD/MMC
+and UART, but it's actually quite involved.  It would seem, then, that
+deploying a USB WIFI module would be a much simpler idea, especially
+given that USB2 is only 2 wires (plus power) and things like "wakeup"
+and "signalling" etc.  are typically handled (with the common exception
+of protocol-clashing) via the provision of features built-in to the
+USB Bus Protocol.  The down-side: most USB2 WIFI dongles, modules and
+chipsets are simply not designed for low-power scenarios, not at the
+hardware level and certainly not at the firmware level.
+
+Only one (modern) USB chipset - which only supports 802.11abgn and not ac - 
+has full firmware source code available under Libre Licensing, thanks to
+ThinkPenguin's tireless efforts: the Atheros AR9271 USB Chipset.  ThinkPenguin
+spent two years walking Atheros through the process of releasing the full
+firmware source code, and it is the only chipset where peer-to-peer mesh
+networking has been added by the Free Software Community, and it is the
+only chipset that could be considered for adjusting the firmware to reduce
+power consumption.  Time however is running out for this chip because
+Qualcomm subequently bought Atheros, and Qualcomm replaced the entire
+management with people who completely fail to comprehend what made the
+AR9271 so very successful.
+
+Bottom line: WIFI and Bluetooth are an ethical minefield as far as
+user privacy, rights, and hardware-level remote hacking are concerend,
+and it starts right at the early design phase: component selection.
+A good way to ensure that users have control over their own devices is
+to add hardware (physical) kill-switches to the power lines, and/or
+to allow them to actually physically and completely remove the WIFI /
+BT module without invalidating the warranty.
+
+Datasheet: <http://www.t-firefly.com/download/firefly-rk3288/hardware/AP6335%20datasheet_V1.3_02102014.pdf>
+
+[[!img  AP6335.jpg]]
+
+# I2C Sensors
+
+I2C sensors appear on the face of it to be quite straightforward: wire them
+up to the 2-line I2C bus and it's done, right?  It's not that simple: I2C
+is a **master** bus only, meaning that if the peripheral has important data,
+it has to have some way of letting the SoC know that something's happened.
+This requires an EINT-capable IRQ line on the SoC in order to wake up the
+SoC from tasks or low-power mode(s).  In addition, it's often the case
+that the sensor may need an occasional (or a definitive, on start-up)
+RESET.  In particular it's a good idea to reset sensors after power-on due
+to potential problems caused by in-rush current instability: often this is
+covered in the datasheet as being **required**.
+
+So typically for each sensor, two extra GPIO lines are required: one EINT
+and one not.  If the amount of GPIO begins to run out (EINTs are usually a
+finite resource) then it is technically possible to share SoC EINT lines
+using logic gates (one for a group of sensors), board-space permitting.
+The other technique is to use a companion MCU for EINT aggregation, and
+even, if pins are particularly sparse, to use the fact that the USB Bus
+has built-in wake-up capability to the SoC.  A signal (or the actual data
+if the sensor is directly connected to the MCU instead) can be sent over
+USB.  Typically in this instance it's a good idea to use the MCU to convert
+to a more standard format such as presenting one or more USB-HID endpoints
+(for CTP, Trackpad and mouse-like sensors), otherwise a special linux kernel
+driver needs to be written.
+
+Other than that, sensors are pretty straightforward.  Most already have a
+linux kernel driver already available.  If they don't, they're best avoided:
+pick another one that does, as it's a sure-fire sign that the sensor has not
+seen mass-volume production deployment, or if it has, there's been zero
+opportunity to do a security review of the source code and/or it'll be
+GPL-violating.
+
+[[!img  I2CSensors.jpg]]
+
+# Ethernet PHY IC
+
+The normal standard for Ethernet PHYs is MII (10/100) and its variants, GMII
+(10/100/1000 Ethernet), RGMII and so on.  There is however a different
+approach: MCU-based interfaces.  In this particular instance, the Shakti
+team have already created a FlexBus implementation, which can be used
+to emulate the required SRAM / 8080-style micro-controller interface needed.
+A number of MCU-based Ethernet PHY ICs exist, including the AX88180
+(which is a Gigabit MCU-to-RGMII converter), the AX88796A (a 10/100
+PHY which supports 8080 as well as MC68k-style interfaces), and the
+low-cost and well-established 10/100 DM9000 PHY.  It requires the
+following signals:
+
+* 16-bit Data/Address Bus
+* CMD select (Changes bus from Data to Address lines)
+* PWRST# (Power-on Reset)
+* IRQ (Interrupt indicator from DM9000 to SoC)
+* IOR# (Read Ready)
+* IOW# (Write Ready)
+* CS# (Chip Select)
+
+This comes to a total of 22 GPIO lines, which is a significant amount.
+However it is also possible to run the DM9000 bus at a reduced 8-bit
+width (with a slightly different pin arrangement for the top 8 bit pins:
+see datasheet for details), for a total 14 pincount.  In addition,
+as a general-purpose shared memory bus it's possible to connect other
+peripherals simultaneously, mitigating the high pincount issue, requiring
+only one Chip Select line per peripheral.  For example, if two Ethernet
+PHY ICs are required they may be placed on the exact same Bus: only one
+extra CS# line is required, and the pincount is now 15 pins for two
+Ethernet PHY ICs: a much better average pincount ratio than would be
+achieved from using two RGMII PHYs.
+
+Other important details: the AX88180, AX88796A and the DM9000 all have
+had linux kernel and u-boot driver source code available for many years.
+
+Datasheet: <https://www.heyrick.co.uk/blog/files/datasheets/dm9000aep.pdf>
+
+[[!img  DM9000.jpg]]
+
+# USB-based Camera IC or Bit-banging CSI
+
+Low-cost Cameras typically require either a MIPI interface (CSI-2) or
+a Parallel Bus-style interface (CSI-1).  Theoretically it is possible
+to bit-bang the CSI-1 interface, using a PWM for generating the clock,
+reading the HSYNC and VSYNC signals and the 8 to 12-bit data, and even
+using DMA to optimise the process.  For an example implementation of this
+techique see
+<https://www.nxp.com/docs/en/application-note/AN4627.pdf>
+
+However the DMA / bit-banging technique takes up at least 12 pins,
+14 if the I2C interface is included, and many sensors require a minimum
+clockrate (data-rate) of 12 mhz before they will respond.  A way to greatly
+reduce pincount is to use a USB-based IC, such as the low-cost, mass
+produced VC0345 from VIMicro.
+
+The VC0345 can do up to VGA @ 30fps, and can take still pictures up to 3M-pixels
+so is not exactly the fastest bunny on the block, but it has the distinct
+advantage of not requiring an NDA to gain access to either the datasheet or
+the app notes, and it is so commonly available that approaching the
+manufacturer is not actually necessary: it can be obtained directly from
+Shenzhen Markets.   Also as it is a UVC-video compliant device, linux kernel
+driver support is automatic.
+
+An alternative approach to using an off-the-shelf CSI-to-USB Camera IC is
+to use a companion MCU: after all, the VC0345 is just a general-purpose
+8051 MCU.  A student achieved this with an ultra-low-cost
+Camera Sensor (QVGA) and an STM32F103 back in 2010:
+<https://github.com/adamgreig/negativeacknowledge/blob/master/content/from-wordpress/robot2-an-arm-based-colour-tracking-robot.md>
+
+However for coping with larger sensors, care has to be taken: not least,
+it is not possible to fit an entire sensor frame into the SRAM of a small
+MCU, so there has to be some care taken to avoid loss of data.  Also,
+the MCU must have 480mbit/sec USB2 capability, as beyond around
+640x480 even at 15fps a USB 1.1 11mbit/sec bus becomes completely saturated.
+Also to watch out for is whether the MCU's USB hardware supports enough
+simultaneous endpoints, particularly if USB-HID for keyboard (matrix to
+USB-HID keyboard) and/or USB-HID trackpad (mouse) or other devices are
+to be managed by the same MCU.  Those caveats in mind: it is actually
+achievable.
+
+* Datasheet: <http://hands.com/~lkcl/eoma/kde_tablet/VC0345TLNA-1102-V10-EN.pdf>
+* VC0345 App Note: <http://hands.com/~lkcl/eoma/kde_tablet/VC0345_app_notes.pdf>
+
+# USB-Based 3G / UMTS/HSDPA Modem
+
+GSM / GPRS / EDGE Modems are typically slow enough to be able to use a UART
+at 115200 baud data rates.  3G on the other hand is fast enough to warrant the
+use of a USB connection.  Depending on the firmware, some 3G USB-based Modems
+offer multiple endpoints, some of which can transfer audio data.  Others
+offer two-way duplex digital audio over a standard four-wire "PCM" arrangement.
+The MU509 also (as previously mentioned in relation to the HTC Universal)
+has GPIO pins which may be accessed over an AT command-set.  Using these
+becomes extra-complex as far as software is concerned, so should only really
+be used as a last resort.
+
+Connectivity for this particular 3G Modem is as follows, which will give
+the minimum functionality:
+
+* USB2 (+/-)
+* 3G Power Enable (to an LDO to cut/enable power to the entire Modem)
+* RESET#
+* PWRON
+* WAKEUPIN# (to wake up the 3G Modem)
+* WAKEUPOUT# (for the 3G Modem to wake up the SoC: requires EINT-capable pin)
+* SIM Card (connected to the MU509, not the SoC)
+
+This is a minimum of 5 GPIO plus 2 USB lines.  Optional extras include:
+
+* Full UART (TX/RX, CTS/RTS, DTR/DCD/DSR, RING)
+* PCM 4-wire audio (standard WAV format, supported by many Audio HW CODECs)
+* Twin Mics
+* Speaker Out
+* Headset Out
+* 12 pins GPIO
+
+Note also in the example schematic that MMBT3904 transistors have been deployed
+for simple level-shifting and also convenient inversion of the control
+signals.  Care needs to be taken in reading the datasheet to ensure that the
+voltage levels of the GPIO match the GPIO Power Domain of the SoC GPIO Bank
+to which the control signals of the MU509 are connected (and level-shifting
+deployed if needed).
+
+Also, special attention must be paid to the power supply: GSM and 3G Modems,
+particularly the "M2M" ones, require an enormous amount of current: 2 to 2.5
+**AMPS** is not unusual.  M2M modules are also typically designed to operate
+off of a direct Lithium battery voltage and are **not** to be run off of
+a 3.3v or 5.0v supply.  Hence in the example schematic below an LP6362
+high-current LDO is used.  This however requires an additional GPIO, which
+is utilised to control the power supply of the 3G Modem.
+
+Deploying hard-power-kill switches (physical and/or under SoC GPIO-control)
+is generally a good idea with USB-based 3G and GSM Modems.  During long-term
+operation, these modems, which are basically yet another ARM Processor and
+their own DDR and NAND storage with a full Software Stack (often linux kernel
+based) inside an enclosed metal box, are pretty much guaranteed to crash so
+hard that they become completely unrecoverable and unresponsive, and have
+even been known to cause the USB Host Endpoints that they are connected to
+to hard-crash as well.  The only way to deal with that is to hard power-cycle
+the Modem module in order to do a full reset of its USB PHY.
+
+The other reason for considering deployment of a hard (physical) kill-switch
+is for respecting user privacy and safety.  Also, it is worth ensuring that
+the 3G Modem does not require its firmware to be uploaded each and every time
+it is powered up: it's much better to select a Modem that has its own
+independent on-board NAND Flash (fortunately, unlike with the WIFI
+module industry which is the total opposite, it is standard practice to
+include on-board NAND on GSM/3G Modems). The hassle of getting a Modem Hardware
+Manufacturer to provide the exact and correct firmware per country per
+Cell-Operator (the FCC is particularly strict about this in the USA, and
+even requires FCC Re-Certification **per Operating System** at a cost of
+USD $50,000 per modem, per cell-operator, per firmware release, **per OS
+release**),
+all of which of course will require an NDA (for binaries??), and require
+MOQs of 100k units or above just to get them to answer enquiries: it's
+just not worth the hassle and the cost "savings" of not having NAND
+Flash on the actual Modem module.
+
+Plus, uploading of software (firmware) from main OS Storage to a peripheral
+is something that instantly terminates any possibility of obtaining RYF
+Hardware-Endorsement Certification.  To make that clear: as long as all
+peripherals (such as a 3G Modem) that run proprietary software are
+fully-functional from the moment they leave the factory, i.e. they do
+not **require** software to be uploaded to them via the main OS in order
+to do their **full** job, RYF Certification can be sought.  Ath5k and
+Ath9k WIFI modules are another example of peripherals that have on-board
+NAND and are fully-functional from the factory, so do not stop RYF
+Certification.
+
+[[!img  MU509.jpg]]
+
+# SimCOM SIM7600 / SIM7100 USB-based GSM/EDGE/3G/4G/LTE Penta-band Modem
+
+An up-to-date low-cost Modem example is one from SimCOM.  SimCOM are best
+known for their low-cost SIM800 and SIM900 "workhorse" GSM modems, which
+are extremely popular in the Shenzhen Markets.  SimCom also have some
+LTE multi-band modems, the 7100 and 7600 Series.  Full technical documents can
+be obtained by registering and then logging in to their website
+(or instead by simply searching online without registration).
+The SIM7600E is here: <http://simcomm2m.com/En/module/detail.aspx?id=178>.
+Checking pricing and availability, it actually seems that the SIM7100C
+is more popular. has lots of developer kits available, some MiniPCIe
+designs, bare modules, and, importantly, plenty of suppliers which is
+a good sign.
+
+The pinouts are pretty much exactly the same as the Huawei MU509,
+with the addition of two SD Card interfaces, two ADCs, and an SPI interface
+for running a display.  This module, it seems, is actually designed for
+use as a stand-alone, fully-functioning actual phone, not even requiring
+a companion SoC or MCU at all.  The SIM7100 also supports sending and
+reading of Audio data over USB.  The Application Notes are **significant**
+which makes it an extremely good choice.  There is even advice on how
+to design an interoperable PCB that supports the low-cost SIM800C, the
+SIM5360 and the SIM7100, all of which are in the same footprint and are
+nearly 100% pin-compatible.  Documents can be obtained without
+NDA from here: <http://simcomm2m.com/En/module/detail.aspx?id=85>
+
+[[!img  SIM7600.jpg]]
+
diff --git a/shakti/m_class/pinouts.mdwn b/shakti/m_class/pinouts.mdwn
new file mode 100644 (file)
index 0000000..17e54a9
--- /dev/null
@@ -0,0 +1,2111 @@
+['CMD', 'CLK', 'D0', 'D1', 'D2', 'D3'] None None
+['CMD', 'CLK', 'D0', 'D1', 'D2', 'D3'] None None
+['CMD', 'CLK', 'D0', 'D1', 'D2', 'D3'] None None
+['CMD', 'CLK', 'D0', 'D1', 'D2', 'D3'] None None
+['CMD', 'CLK', 'D0', 'D1', 'D2', 'D3'] None None
+['CMD', 'CLK', 'D0', 'D1', 'D2', 'D3'] None None
+['CMD', 'CLK', 'D0', 'D1', 'D2', 'D3'] None 2
+['CMD', 'CLK', 'D0', 'D1', 'D2', 'D3'] 2 None
+# Pinouts (PinMux)
+
+auto-generated by [[pinouts.py]]
+
+[[!toc  ]]
+
+| Pin | Mux0        | Mux1        | Mux2        | Mux3        |
+| --- | ----------- | ----------- | ----------- | ----------- |
+|   0 | A GPIOA0    | A MMCCMD    | A UART1_TX  | A SPI1_CLK  |
+|   1 | A GPIOA1    | A MMCCLK    | A UART1_RX  | A SPI1_NSS  |
+|   2 | A GPIOA2    | A MMCD0     | A UART1_CTS | A SPI1_MOSI |
+|   3 | A GPIOA3    | A MMCD1     | A UART1_RTS | A SPI1_MISO |
+|   4 | A GPIOA4    | A MMCD2     | A TWI1_SDA  | A EINT0     |
+|   5 | A GPIOA5    | A MMCD3     | A TWI1_SCL  | A EINT1     |
+|   6 | A GPIOA6    | A MMCD4     | A SPI2_CLK  | A EINT2     |
+|   7 | A GPIOA7    | A MMCD5     | A SPI2_NSS  | A EINT3     |
+|   8 | A GPIOA8    | A MMCD6     | A SPI2_MOSI | A EINT4     |
+|   9 | A GPIOA9    | A MMCD7     | A SPI2_MISO | A EINT5     |
+|  10 | A GPIOA10   | A EINT0     | A SD1_CMD   | A JTAG1_MS  |
+|  11 | A GPIOA11   | A EINT1     | A SD1_CLK   | A JTAG1_DI  |
+|  12 | A GPIOA12   | A EINT2     | A SD1_D0    | A JTAG1_DO  |
+|  13 | A GPIOA13   | A EINT3     | A SD1_D1    | A JTAG1_CK  |
+|  14 | A GPIOA14   | A EINT4     | A SD1_D2    | A UART2_TX  |
+|  15 | A GPIOA15   | A EINT5     | A SD1_D3    | A UART2_RX  |
+|  16 | B GPIOB0    | B LCDCK_0   | B TWI1_SDA  | B EINT6     |
+|  17 | B GPIOB1    | B LCDDE_0   | B TWI1_SCL  | B EINT7     |
+|  18 | B GPIOB2    | B LCDHS_0   | B UART2_TX  | B EINT8     |
+|  19 | B GPIOB3    | B LCDVS_0   | B UART2_RX  | B EINT9     |
+|  20 | B GPIOB4    | B LCD0_0    | B SPI3_CK   | B FB_AD8    |
+|  21 | B GPIOB5    | B LCD1_0    | B SPI3_NSS  | B FB_AD9    |
+|  22 | B GPIOB6    | B LCD2_0    | B SPI3_IO0  | B FB_AD10   |
+|  23 | B GPIOB7    | B LCD3_0    | B SPI3_IO1  | B FB_AD11   |
+|  24 | B GPIOB8    | B LCD4_0    |             | B FB_AD12   |
+|  25 | B GPIOB9    | B LCD5_0    | B PWM_0     | B FB_AD13   |
+|  26 | B GPIOB10   | B LCD6_0    | B UART4_TX  | B FB_AD14   |
+|  27 | B GPIOB11   | B LCD7_0    | B UART4_RX  | B FB_AD15   |
+|  28 | B GPIOB12   | B LCD8_0    | B SPI1_CLK  | B FB_AD16   |
+|  29 | B GPIOB13   | B LCD9_0    | B SPI1_NSS  | B FB_AD17   |
+|  30 | B GPIOB14   | B LCD10_0   | B SPI1_MOSI | B FB_AD18   |
+|  31 | B GPIOB15   | B LCD11_0   | B SPI1_MISO | B FB_AD19   |
+|  32 | B GPIOB16   | B LCD12_0   | B UART3_TX  | B FB_AD20   |
+|  33 | B GPIOB17   | B LCD13_0   | B UART3_RX  | B FB_AD21   |
+|  34 | B GPIOB18   | B LCD14_0   | B TWI3_SDA  | B FB_AD22   |
+|  35 | B GPIOB19   | B LCD15_0   | B TWI3_SCL  | B FB_AD23   |
+|  36 | B GPIOB20   | B LCD16_0   | B PWM_1     | B FB_AD24   |
+|  37 | B GPIOB21   | B LCD17_0   | B PWM_2     | B FB_AD25   |
+|  38 | B GPIOB22   | B LCD18_0   | B SD1_CMD   | B FB_AD26   |
+|  39 | B GPIOB23   | B LCD19_0   | B SD1_CLK   | B FB_AD27   |
+|  40 | B GPIOB24   | B LCD20_0   | B SD1_D0    | B FB_AD28   |
+|  41 | B GPIOB25   | B LCD21_0   | B SD1_D1    | B FB_AD29   |
+|  42 | B GPIOB26   | B LCD22_0   | B SD1_D2    | B FB_AD30   |
+|  43 | B GPIOB27   | B LCD23_0   | B SD1_D3    | B FB_AD31   |
+|  44 | C GPIOC0    | C ULPI1_CK  |             | C EINT10    |
+|  45 | C GPIOC1    | C ULPI1_DIR |             | C EINT11    |
+|  46 | C GPIOC2    | C ULPI1_STP |             | C EINT12    |
+|  47 | C GPIOC3    | C ULPI1_NXT |             | C EINT13    |
+|  48 | C GPIOC4    | C ULPI1_D0  |             | C EINT14    |
+|  49 | C GPIOC5    | C ULPI1_D1  |             | C EINT15    |
+|  50 | C GPIOC6    | C ULPI1_D2  |             | C EINT16    |
+|  51 | C GPIOC7    | C ULPI1_D3  |             | C EINT17    |
+|  52 | C GPIOC8    | C ULPI1_D4  | C SPI2_CLK  | C JTAG2_MS  |
+|  53 | C GPIOC9    | C ULPI1_D5  | C SPI2_NSS  | C JTAG2_DI  |
+|  54 | C GPIOC10   | C ULPI1_D6  | C SPI2_MOSI | C JTAG2_DO  |
+|  55 | C GPIOC11   | C ULPI1_D7  | C SPI2_MISO | C JTAG2_CK  |
+|  56 | C GPIOC12   | C ULPI2_CK  | C SPI2_NSS  | C EINT22    |
+|  57 | C GPIOC13   | C ULPI2_DIR | C IISMCK    | C EINT23    |
+|  58 | C GPIOC14   | C ULPI2_STP | C IISBCK    | C EINT24    |
+|  59 | C GPIOC15   | C ULPI2_NXT | C IISLRCK   | C EINT25    |
+|  60 | C GPIOC16   | C ULPI2_D0  | C IISDI     | C EINT26    |
+|  61 | C GPIOC17   | C ULPI2_D1  | C IISDO0    | C EINT27    |
+|  62 | C GPIOC18   | C ULPI2_D2  | C IISDO1    | C EINT28    |
+|  63 | C GPIOC19   | C ULPI2_D3  | C IISDO2    | C EINT29    |
+|  64 | C GPIOC20   | C ULPI2_D4  | C IISDO3    | C UART0_TX  |
+|  65 | C GPIOC21   | C ULPI2_D5  | C PWM_2     | C UART0_RX  |
+|  66 | C GPIOC22   | C ULPI2_D6  | C UART2_TX  | C UART0_CTS |
+|  67 | C GPIOC23   | C ULPI2_D7  | C UART2_RX  | C UART0_RTS |
+|  68 | D GPIOD0    | D FB_AD0    | D UART0_TX  | D EINT30    |
+|  69 | D GPIOD1    | D FB_AD1    | D UART0_RX  | D EINT31    |
+|  70 | D GPIOD2    | D FB_AD2    | D UART0_CTS | D TWI2_SDA  |
+|  71 | D GPIOD3    | D FB_AD3    | D UART0_RTS | D TWI2_SCL  |
+|  72 | D GPIOD4    | D FB_AD4    | D SD2_CMD   |             |
+|  73 | D GPIOD5    | D FB_AD5    | D SD2_CLK   |             |
+|  74 | D GPIOD6    | D FB_AD6    | D SD2_D0    |             |
+|  75 | D GPIOD7    | D FB_AD7    | D SD2_D1    |             |
+|  76 | D GPIOD8    | D FB_CS0    | D SD2_D2    |             |
+|  77 | D GPIOD9    | D FB_CS1    | D SD2_D3    |             |
+|  78 | D GPIOD10   | D FB_ALE    | D FB_TS     | D TWI1_SDA  |
+|  79 | D GPIOD11   | D FB_OE     | D FB_TBST   | D TWI1_SCL  |
+|  80 | D GPIOD12   | D FB_RW     |             |             |
+|  81 | D GPIOD13   | D FB_TA     | D UART4_TX  | D EINT5     |
+|  82 | D GPIOD14   | D FB_CLK    | D UART4_RX  | D EINT6     |
+|  83 | D GPIOD15   | D FB_BWE0   | D FB_TSIZ0  | D EINT7     |
+|  84 | D GPIOD16   | D FB_BWE1   | D FB_TSIZ1  | D EINT8     |
+|  85 | D GPIOD17   | D FB_BWE2   | D TWI2_SDA  | D FB_A0     |
+|  86 | D GPIOD18   | D FB_BWE3   | D TWI2_SCL  | D FB_A1     |
+|  87 | D GPIOD19   | D FB_CS4    | D TWI3_SDA  | D EINT18    |
+|  88 | D GPIOD20   | D FB_CS5    | D TWI3_SCL  | D EINT19    |
+|  89 | D GPIOD21   | D PWM_0     | D UART3_TX  | D EINT20    |
+|  90 | D GPIOD22   | D PWM_1     | D UART3_RX  | D EINT21    |
+|  91 | D GPIOD23   | D PWM_2     |             | D EINT9     |
+|  92 | E GPIOE0    | E FB_AD8    | E SD2_CMD   | E EINT10    |
+|  93 | E GPIOE1    | E FB_AD9    | E SD2_CLK   | E EINT11    |
+|  94 | E GPIOE2    | E FB_AD10   | E SD2_D0    | E EINT12    |
+|  95 | E GPIOE3    | E FB_AD11   | E SD2_D1    | E EINT13    |
+|  96 | E GPIOE4    | E FB_AD12   | E SD2_D2    | E EINT14    |
+|  97 | E GPIOE5    | E FB_AD13   | E SD2_D3    | E EINT15    |
+|  98 | E GPIOE6    | E FB_AD14   | E TWI2_SDA  | E EINT16    |
+|  99 | E GPIOE7    | E FB_AD15   | E TWI2_SCL  | E EINT17    |
+| 100 | E GPIOE8    | E FB_AD16   | E SD3_CMD   | E EINT22    |
+| 101 | E GPIOE9    | E FB_AD17   | E SD3_CLK   | E EINT23    |
+| 102 | E GPIOE10   | E FB_AD18   | E SD3_D0    | E EINT24    |
+| 103 | E GPIOE11   | E FB_AD19   | E SD3_D1    | E EINT25    |
+| 104 | E GPIOE12   | E FB_AD20   | E SD3_D2    | E EINT26    |
+| 105 | E GPIOE13   | E FB_AD21   | E SD3_D3    | E EINT27    |
+| 106 | E GPIOE14   | E FB_AD22   | E UART1_TX  | E MMCCMD    |
+| 107 | E GPIOE15   | E FB_AD23   | E UART1_RX  | E MMCCLK    |
+| 108 | E GPIOE16   | E FB_AD24   | E UART1_CTS | E MMCD0     |
+| 109 | E GPIOE17   | E FB_AD25   | E UART1_RTS | E MMCD1     |
+| 110 | E GPIOE18   | E FB_AD26   | E SPI3_CK   | E MMCD2     |
+| 111 | E GPIOE19   | E FB_AD27   | E SPI3_NSS  | E MMCD3     |
+| 112 | E GPIOE20   | E FB_AD28   | E SPI3_IO0  | E MMCD4     |
+| 113 | E GPIOE21   | E FB_AD29   | E SPI3_IO1  | E MMCD5     |
+| 114 | E GPIOE22   | E FB_AD30   | E SPI3_IO2  | E MMCD6     |
+| 115 | E GPIOE23   | E FB_AD31   | E SPI3_IO3  | E MMCD7     |
+| 116 | F GPIOF0    | F IISMCK    | F SD3_CMD   | F EINT18    |
+| 117 | F GPIOF1    | F IISBCK    | F SD3_CLK   | F EINT19    |
+| 118 | F GPIOF2    | F IISLRCK   | F SD3_D0    | F EINT20    |
+| 119 | F GPIOF3    | F IISDI     | F SD3_D1    | F EINT21    |
+| 120 | F GPIOF4    | F IISDO0    | F SD3_D2    | F PWM_2     |
+| 121 | F GPIOF5    | F IISDO1    | F SD3_D3    | F EINT7     |
+| 122 | F GPIOF6    | F IISDO2    | F TWI1_SDA  | F EINT28    |
+| 123 | F GPIOF7    | F IISDO3    | F TWI1_SCL  | F EINT29    |
+| 124 | F GPIOF8    | F UART4_TX  | F PWM_0     | F EINT30    |
+| 125 | F GPIOF9    | F UART4_RX  | F PWM_1     | F EINT31    |
+| 126 | G GPIOG0    | G RG_ERXD0  | G LCDCK_1   | G FB_AD8    |
+| 127 | G GPIOG1    | G RG_ERXD1  | G LCDDE_1   | G FB_AD9    |
+| 128 | G GPIOG2    | G RG_ERXD2  | G LCDHS_1   | G FB_AD10   |
+| 129 | G GPIOG3    | G RG_ETXD0  | G LCDVS_1   | G FB_AD11   |
+| 130 | G GPIOG4    | G RG_ETXD1  | G LCD0_1    | G FB_AD12   |
+| 131 | G GPIOG5    | G RG_ETXD2  | G LCD1_1    | G FB_AD13   |
+| 132 | G GPIOG6    | G RG_FB_CS0 | G LCD2_1    | G FB_AD14   |
+| 133 | G GPIOG7    | G RG_FB_CS1 | G LCD3_1    | G FB_AD15   |
+| 134 | G GPIOG8    | G RG_ERXCK  | G LCD4_1    | G FB_AD16   |
+| 135 | G GPIOG9    | G RG_ERXERR | G LCD5_1    | G FB_AD17   |
+| 136 | G GPIOG10   | G RG_ERXDV  | G LCD6_1    | G FB_AD18   |
+| 137 | G GPIOG11   | G RG_EMDC   | G LCD7_1    | G FB_AD19   |
+| 138 | G GPIOG12   | G RG_EMDIO  | G LCD8_1    | G FB_AD20   |
+| 139 | G GPIOG13   | G RG_ETXEN  | G LCD9_1    | G FB_AD21   |
+| 140 | G GPIOG14   | G RG_ETXCK  | G LCD10_1   | G FB_AD22   |
+| 141 | G GPIOG15   | G RG_ECRS   | G LCD11_1   | G FB_AD23   |
+| 142 | G GPIOG16   | G RG_ECOL   | G LCD12_1   | G FB_AD24   |
+| 143 | G GPIOG17   | G RG_ETXERR | G LCD13_1   | G FB_AD25   |
+| 144 | G GPIOG18   | G ULPI3_CK  | G LCD14_1   | G FB_AD26   |
+| 145 | G GPIOG19   | G ULPI3_DIR | G LCD15_1   | G FB_AD27   |
+| 146 | G GPIOG20   | G ULPI3_STP | G LCD16_1   | G FB_AD28   |
+| 147 | G GPIOG21   | G ULPI3_NXT | G LCD17_1   | G FB_AD29   |
+| 148 | G GPIOG22   | G ULPI3_D0  | G LCD18_1   | G FB_AD30   |
+| 149 | G GPIOG23   | G ULPI3_D1  | G LCD19_1   | G FB_AD31   |
+| 150 | G GPIOG24   | G ULPI3_D2  | G LCD20_1   | G SD2_CMD   |
+| 151 | G GPIOG25   | G ULPI3_D3  | G LCD21_1   | G SD2_CLK   |
+| 152 | G GPIOG26   | G ULPI3_D4  | G LCD22_1   | G SPI3_CK   |
+| 153 | G GPIOG27   | G ULPI3_D5  | G LCD23_1   | G SPI3_NSS  |
+| 154 | G GPIOG28   | G ULPI3_D6  | G SD2_D0    | G SPI3_IO0  |
+| 155 | G GPIOG29   | G ULPI3_D7  | G SD2_D1    | G SPI3_IO1  |
+| 156 | G GPIOG30   |             | G SD2_D2    | G SPI3_IO2  |
+| 157 | G GPIOG31   |             | G SD2_D3    | G SPI3_IO3  |
+
+# Pinouts (Fixed function)
+
+## CTRL_SYS
+
+* 158: 0 TEST
+* 159: 0 JTAG_SEL
+* 160: 0 UBOOT_SEL
+* 161: 0 NMI#
+* 162: 0 RESET#
+* 163: 0 CLK24M_IN CLK24M_OUT
+* 165: 0 PLLTEST PLLREGIO PLLVP25 PLLDV
+* 169: 0 PLLVREG PLLGND
+
+## DDR3
+
+* 171: 1 SDQ0 SDQ1 SDQ2 SDQ3
+* 175: 1 SDQ4 SDQ5 SDQ6 SDQ7
+* 179: 1 SDQ8 SDQ9 SDQ10 SDQ11
+* 183: 1 SDQ12 SDQ13 SDQ14 SDQ15
+* 187: 1 SDQ16 SDQ17 SDQ18 SDQ19
+* 191: 1 SDQ20 SDQ21 SDQ22 SDQ23
+* 195: 1 SDQ24 SDQ25 SDQ26 SDQ27
+* 199: 1 SDQ28 SDQ29 SDQ30 SDQ31
+* 203: 1 SVREF0 SVREF1 SVREF2 SVREF3
+* 207: 1 SDQS0 SDQS0# SDQS1 SDQS1#
+* 211: 1 SDQS2 SDQS2# SDQS3 SDQS3#
+* 215: 1 SDQM0 SDQM1 SDQM2 SDQM3
+* 219: 1 SCK# SCK SCKE0 SCKE1
+* 223: 1 SA0 SA1 SA2 SA3
+* 227: 1 SA4 SA5 SA6 SA7
+* 231: 1 SA8 SA9 SA10 SA11
+* 235: 1 SA12 SA13 SA14
+* 238: 1 SBA0 SBA1 SBA2
+* 241: 1 SWE
+* 242: 1 SCAS
+* 243: 1 SRAS
+* 244: 1 SCS0 SCS1
+* 246: 1 SZQ
+* 247: 1 SRST
+* 248: 1 SDBG0 SDBG1
+* 250: 1 ADBG
+* 251: 1 ODT0 ODT1
+
+## POWER_CPU
+
+* 253: 2 VDD0_CPU VDD1_CPU VDD2_CPU VDD3_CPU
+* 257: 2 VDD4_CPU VDD5_CPU
+* 259: 2 GND0_CPU GND1_CPU GND2_CPU GND3_CPU
+* 263: 2 GND4_CPU GND5_CPU
+
+## POWER_DLL
+
+* 265: 3 VDD0_DLL VDD1_DLL VDD2_DLL
+* 268: 3 GND0_DLL GND1_DLL GND2_DLL
+
+## POWER_DRAM
+
+* 271: 4 VCC0_DRAM VCC1_DRAM VCC2_DRAM VCC3_DRAM
+* 275: 4 VCC4_DRAM VCC5_DRAM VCC6_DRAM VCC7_DRAM
+* 279: 4 VCC8_DRAM VCC9_DRAM
+* 281: 4 GND0_DRAM GND1_DRAM GND2_DRAM GND3_DRAM
+* 285: 4 GND4_DRAM GND5_DRAM GND6_DRAM GND7_DRAM
+* 289: 4 GND8_DRAM GND9_DRAM
+
+## POWER_GPIO
+
+* 291: 5 VDD_GPIOA VDD_GPIOB VDD_GPIOC VDD_GPIOD
+* 295: 5 VDD_GPIOE VDD_GPIOF VDD_GPIOG
+* 298: 5 GND_GPIOA GND_GPIOB GND_GPIOC GND_GPIOD
+* 302: 5 GND_GPIOE GND_GPIOF GND_GPIOG
+
+## POWER_INT
+
+* 305: 6 VDD0_INT VDD1_INT VDD2_INT VDD3_INT
+* 309: 6 VDD4_INT VDD5_INT VDD6_INT VDD7_INT
+* 313: 6 VDD8_INT VDD9_INT
+* 315: 6 GND0_INT GND1_INT GND2_INT GND3_INT
+* 319: 6 GND4_INT GND5_INT GND6_INT GND7_INT
+* 323: 6 GND8_INT GND9_INT
+
+# Functions (PinMux)
+
+auto-generated by [[pinouts.py]]
+
+## EINT
+
+External Interrupt
+
+* EINT0     : A4/3 A10/1
+* EINT1     : A5/3 A11/1
+* EINT2     : A6/3 A12/1
+* EINT3     : A7/3 A13/1
+* EINT4     : A8/3 A14/1
+* EINT5     : A9/3 A15/1 D13/3
+* EINT6     : B0/3 D14/3
+* EINT7     : B1/3 D15/3 F5/3
+* EINT8     : B2/3 D16/3
+* EINT9     : B3/3 D23/3
+* EINT10    : C0/3 E0/3
+* EINT11    : C1/3 E1/3
+* EINT12    : C2/3 E2/3
+* EINT13    : C3/3 E3/3
+* EINT14    : C4/3 E4/3
+* EINT15    : C5/3 E5/3
+* EINT16    : C6/3 E6/3
+* EINT17    : C7/3 E7/3
+* EINT18    : D19/3 F0/3
+* EINT19    : D20/3 F1/3
+* EINT20    : D21/3 F2/3
+* EINT21    : D22/3 F3/3
+* EINT22    : C12/3 E8/3
+* EINT23    : C13/3 E9/3
+* EINT24    : C14/3 E10/3
+* EINT25    : C15/3 E11/3
+* EINT26    : C16/3 E12/3
+* EINT27    : C17/3 E13/3
+* EINT28    : C18/3 F6/3
+* EINT29    : C19/3 F7/3
+* EINT30    : D0/3 F8/3
+* EINT31    : D1/3 F9/3
+
+## FB
+
+MC68k FlexBus
+
+* FB_A0     : D17/3
+* FB_A1     : D18/3
+* FB_AD0    : D0/1
+* FB_AD1    : D1/1
+* FB_AD2    : D2/1
+* FB_AD3    : D3/1
+* FB_AD4    : D4/1
+* FB_AD5    : D5/1
+* FB_AD6    : D6/1
+* FB_AD7    : D7/1
+* FB_AD8    : B4/3 E0/1 G0/3
+* FB_AD9    : B5/3 E1/1 G1/3
+* FB_AD10   : B6/3 E2/1 G2/3
+* FB_AD11   : B7/3 E3/1 G3/3
+* FB_AD12   : B8/3 E4/1 G4/3
+* FB_AD13   : B9/3 E5/1 G5/3
+* FB_AD14   : B10/3 E6/1 G6/3
+* FB_AD15   : B11/3 E7/1 G7/3
+* FB_AD16   : B12/3 E8/1 G8/3
+* FB_AD17   : B13/3 E9/1 G9/3
+* FB_AD18   : B14/3 E10/1 G10/3
+* FB_AD19   : B15/3 E11/1 G11/3
+* FB_AD20   : B16/3 E12/1 G12/3
+* FB_AD21   : B17/3 E13/1 G13/3
+* FB_AD22   : B18/3 E14/1 G14/3
+* FB_AD23   : B19/3 E15/1 G15/3
+* FB_AD24   : B20/3 E16/1 G16/3
+* FB_AD25   : B21/3 E17/1 G17/3
+* FB_AD26   : B22/3 E18/1 G18/3
+* FB_AD27   : B23/3 E19/1 G19/3
+* FB_AD28   : B24/3 E20/1 G20/3
+* FB_AD29   : B25/3 E21/1 G21/3
+* FB_AD30   : B26/3 E22/1 G22/3
+* FB_AD31   : B27/3 E23/1 G23/3
+* FB_ALE    : D10/1
+* FB_BWE0   : D15/1
+* FB_BWE1   : D16/1
+* FB_BWE2   : D17/1
+* FB_BWE3   : D18/1
+* FB_CLK    : D14/1
+* FB_CS0    : D8/1
+* FB_CS1    : D9/1
+* FB_CS4    : D19/1
+* FB_CS5    : D20/1
+* FB_OE     : D11/1
+* FB_RW     : D12/1
+* FB_TA     : D13/1
+* FB_TBST   : D11/2
+* FB_TS     : D10/2
+* FB_TSIZ0  : D15/2
+* FB_TSIZ1  : D16/2
+
+## IIS
+
+I2S Audio
+
+* IISBCK    : C14/2 F1/1
+* IISDI     : C16/2 F3/1
+* IISDO0    : C17/2 F4/1
+* IISDO1    : C18/2 F5/1
+* IISDO2    : C19/2 F6/1
+* IISDO3    : C20/2 F7/1
+* IISLRCK   : C15/2 F2/1
+* IISMCK    : C13/2 F0/1
+
+## JTAG1
+
+JTAG (same as JTAG2, JTAG_SEL=LOW)
+
+* JTAG1_CK  : A13/3
+* JTAG1_DI  : A11/3
+* JTAG1_DO  : A12/3
+* JTAG1_MS  : A10/3
+
+## JTAG2
+
+JTAG (same as JTAG1, JTAG_SEL=HIGH)
+
+* JTAG2_CK  : C11/3
+* JTAG2_DI  : C9/3
+* JTAG2_DO  : C10/3
+* JTAG2_MS  : C8/3
+
+## LCD
+
+24-pin RGB/TTL LCD
+
+* LCD0_0    : B4/1
+* LCD0_1    : G4/2
+* LCD1_0    : B5/1
+* LCD1_1    : G5/2
+* LCD10_0   : B14/1
+* LCD10_1   : G14/2
+* LCD11_0   : B15/1
+* LCD11_1   : G15/2
+* LCD12_0   : B16/1
+* LCD12_1   : G16/2
+* LCD13_0   : B17/1
+* LCD13_1   : G17/2
+* LCD14_0   : B18/1
+* LCD14_1   : G18/2
+* LCD15_0   : B19/1
+* LCD15_1   : G19/2
+* LCD16_0   : B20/1
+* LCD16_1   : G20/2
+* LCD17_0   : B21/1
+* LCD17_1   : G21/2
+* LCD18_0   : B22/1
+* LCD18_1   : G22/2
+* LCD19_0   : B23/1
+* LCD19_1   : G23/2
+* LCD2_0    : B6/1
+* LCD2_1    : G6/2
+* LCD20_0   : B24/1
+* LCD20_1   : G24/2
+* LCD21_0   : B25/1
+* LCD21_1   : G25/2
+* LCD22_0   : B26/1
+* LCD22_1   : G26/2
+* LCD23_0   : B27/1
+* LCD23_1   : G27/2
+* LCD3_0    : B7/1
+* LCD3_1    : G7/2
+* LCD4_0    : B8/1
+* LCD4_1    : G8/2
+* LCD5_0    : B9/1
+* LCD5_1    : G9/2
+* LCD6_0    : B10/1
+* LCD6_1    : G10/2
+* LCD7_0    : B11/1
+* LCD7_1    : G11/2
+* LCD8_0    : B12/1
+* LCD8_1    : G12/2
+* LCD9_0    : B13/1
+* LCD9_1    : G13/2
+* LCDCK_0   : B0/1
+* LCDCK_1   : G0/2
+* LCDDE_0   : B1/1
+* LCDDE_1   : G1/2
+* LCDHS_0   : B2/1
+* LCDHS_1   : G2/2
+* LCDVS_0   : B3/1
+* LCDVS_1   : G3/2
+
+## MMC
+
+eMMC 1/2/4/8 pin
+
+* MMCCLK    : A1/1 E15/3
+* MMCCMD    : A0/1 E14/3
+* MMCD0     : A2/1 E16/3
+* MMCD1     : A3/1 E17/3
+* MMCD2     : A4/1 E18/3
+* MMCD3     : A5/1 E19/3
+* MMCD4     : A6/1 E20/3
+* MMCD5     : A7/1 E21/3
+* MMCD6     : A8/1 E22/3
+* MMCD7     : A9/1 E23/3
+
+## PWM
+
+PWM (pulse-width modulation)
+
+* PWM_0     : B9/2 D21/1 F8/2
+* PWM_1     : B20/2 D22/1 F9/2
+* PWM_2     : B21/2 C21/2 D23/1 F4/3
+
+## RG
+
+RGMII Ethernet
+
+* RG_ECOL   : G16/1
+* RG_ECRS   : G15/1
+* RG_EMDC   : G11/1
+* RG_EMDIO  : G12/1
+* RG_ERXCK  : G8/1
+* RG_ERXD0  : G0/1
+* RG_ERXD1  : G1/1
+* RG_ERXD2  : G2/1
+* RG_ERXDV  : G10/1
+* RG_ERXERR : G9/1
+* RG_ETXCK  : G14/1
+* RG_ETXD0  : G3/1
+* RG_ETXD1  : G4/1
+* RG_ETXD2  : G5/1
+* RG_ETXEN  : G13/1
+* RG_ETXERR : G17/1
+* RG_FB_CS0 : G6/1
+* RG_FB_CS1 : G7/1
+
+## SD1
+
+SD/MMC 1
+
+* SD1_CLK   : A11/2 B23/2
+* SD1_CMD   : A10/2 B22/2
+* SD1_D0    : A12/2 B24/2
+* SD1_D1    : A13/2 B25/2
+* SD1_D2    : A14/2 B26/2
+* SD1_D3    : A15/2 B27/2
+
+## SD2
+
+SD/MMC 2
+
+* SD2_CLK   : D5/2 E1/2 G25/3
+* SD2_CMD   : D4/2 E0/2 G24/3
+* SD2_D0    : D6/2 E2/2 G28/2
+* SD2_D1    : D7/2 E3/2 G29/2
+* SD2_D2    : D8/2 E4/2 G30/2
+* SD2_D3    : D9/2 E5/2 G31/2
+
+## SD3
+
+SD/MMC 3
+
+* SD3_CLK   : E9/2 F1/2
+* SD3_CMD   : E8/2 F0/2
+* SD3_D0    : E10/2 F2/2
+* SD3_D1    : E11/2 F3/2
+* SD3_D2    : E12/2 F4/2
+* SD3_D3    : E13/2 F5/2
+
+## SPI1
+
+SPI (Serial Peripheral Interface) 1
+
+* SPI1_CLK  : A0/3 B12/2
+* SPI1_MISO : A3/3 B15/2
+* SPI1_MOSI : A2/3 B14/2
+* SPI1_NSS  : A1/3 B13/2
+
+## SPI2
+
+SPI (Serial Peripheral Interface) 2
+
+* SPI2_CLK  : A6/2 C8/2
+* SPI2_MISO : A9/2 C11/2
+* SPI2_MOSI : A8/2 C10/2
+* SPI2_NSS  : A7/2 C9/2 C12/2
+
+## SPI3
+
+Quad SPI (Serial Peripheral Interface) 3
+
+* SPI3_CK   : B4/2 E18/2 G26/3
+* SPI3_IO0  : B6/2 E20/2 G28/3
+* SPI3_IO1  : B7/2 E21/2 G29/3
+* SPI3_IO2  : E22/2 G30/3
+* SPI3_IO3  : E23/2 G31/3
+* SPI3_NSS  : B5/2 E19/2 G27/3
+
+## TWI1
+
+I2C 1
+
+* TWI1_SCL  : A5/2 B1/2 D11/3 F7/2
+* TWI1_SDA  : A4/2 B0/2 D10/3 F6/2
+
+## TWI2
+
+I2C 2
+
+* TWI2_SCL  : D3/3 D18/2 E7/2
+* TWI2_SDA  : D2/3 D17/2 E6/2
+
+## TWI3
+
+I2C 3
+
+* TWI3_SCL  : B19/2 D20/2
+* TWI3_SDA  : B18/2 D19/2
+
+## UART0
+
+UART (TX/RX/CTS/RTS) 0
+
+* UART0_CTS : C22/3 D2/2
+* UART0_RTS : C23/3 D3/2
+* UART0_RX  : C21/3 D1/2
+* UART0_TX  : C20/3 D0/2
+
+## UART1
+
+UART (TX/RX/CTS/RTS) 1
+
+* UART1_CTS : A2/2 E16/2
+* UART1_RTS : A3/2 E17/2
+* UART1_RX  : A1/2 E15/2
+* UART1_TX  : A0/2 E14/2
+
+## UART2
+
+UART (TX/RX) 2
+
+* UART2_RX  : A15/3 B3/2 C23/2
+* UART2_TX  : A14/3 B2/2 C22/2
+
+## UART3
+
+UART (TX/RX) 3
+
+* UART3_RX  : B17/2 D22/2
+* UART3_TX  : B16/2 D21/2
+
+## UART4
+
+UART (TX/RX) 4
+
+* UART4_RX  : B11/2 D14/2 F9/1
+* UART4_TX  : B10/2 D13/2 F8/1
+
+## ULPI1
+
+ULPI (USB Low Pin-count) 1
+
+* ULPI1_CK  : C0/1
+* ULPI1_D0  : C4/1
+* ULPI1_D1  : C5/1
+* ULPI1_D2  : C6/1
+* ULPI1_D3  : C7/1
+* ULPI1_D4  : C8/1
+* ULPI1_D5  : C9/1
+* ULPI1_D6  : C10/1
+* ULPI1_D7  : C11/1
+* ULPI1_DIR : C1/1
+* ULPI1_NXT : C3/1
+* ULPI1_STP : C2/1
+
+## ULPI2
+
+ULPI (USB Low Pin-count) 2
+
+* ULPI2_CK  : C12/1
+* ULPI2_D0  : C16/1
+* ULPI2_D1  : C17/1
+* ULPI2_D2  : C18/1
+* ULPI2_D3  : C19/1
+* ULPI2_D4  : C20/1
+* ULPI2_D5  : C21/1
+* ULPI2_D6  : C22/1
+* ULPI2_D7  : C23/1
+* ULPI2_DIR : C13/1
+* ULPI2_NXT : C15/1
+* ULPI2_STP : C14/1
+
+## ULPI3
+
+ULPI (USB Low Pin-count) 3
+
+* ULPI3_CK  : G18/1
+* ULPI3_D0  : G22/1
+* ULPI3_D1  : G23/1
+* ULPI3_D2  : G24/1
+* ULPI3_D3  : G25/1
+* ULPI3_D4  : G26/1
+* ULPI3_D5  : G27/1
+* ULPI3_D6  : G28/1
+* ULPI3_D7  : G29/1
+* ULPI3_DIR : G19/1
+* ULPI3_NXT : G21/1
+* ULPI3_STP : G20/1
+
+# Pinmap for EOMA68
+
+## B1:LCD/22
+
+EOMA68-compliance, 18-bit RGB/TTL LCD
+
+* LCDCK_0 16 B0/1
+* LCDDE_0 17 B1/1
+* LCDHS_0 18 B2/1
+* LCDVS_0 19 B3/1
+* LCD0_0 20 B4/1
+* LCD1_0 21 B5/1
+* LCD2_0 22 B6/1
+* LCD3_0 23 B7/1
+* LCD4_0 24 B8/1
+* LCD5_0 25 B9/1
+* LCD6_0 26 B10/1
+* LCD7_0 27 B11/1
+* LCD8_0 28 B12/1
+* LCD9_0 29 B13/1
+* LCD10_0 30 B14/1
+* LCD11_0 31 B15/1
+* LCD12_0 32 B16/1
+* LCD13_0 33 B17/1
+* LCD14_0 34 B18/1
+* LCD15_0 35 B19/1
+* LCD16_0 36 B20/1
+* LCD17_0 37 B21/1
+
+## ULPI1/8
+
+user-facing: internal (on Card), USB-OTG ULPI PHY
+
+* ULPI1_CK 44 C0/1
+* ULPI1_DIR 45 C1/1
+* ULPI1_STP 46 C2/1
+* ULPI1_NXT 47 C3/1
+* ULPI1_D0 48 C4/1
+* ULPI1_D1 49 C5/1
+* ULPI1_D2 50 C6/1
+* ULPI1_D3 51 C7/1
+
+## ULPI2
+
+EOMA68-compliance: dual USB2 Host ULPI PHY
+
+* ULPI2_CK 56 C12/1
+* ULPI2_DIR 57 C13/1
+* ULPI2_STP 58 C14/1
+* ULPI2_NXT 59 C15/1
+* ULPI2_D0 60 C16/1
+* ULPI2_D1 61 C17/1
+* ULPI2_D2 62 C18/1
+* ULPI2_D3 63 C19/1
+* ULPI2_D4 64 C20/1
+* ULPI2_D5 65 C21/1
+* ULPI2_D6 66 C22/1
+* ULPI2_D7 67 C23/1
+
+## MMC
+
+internal (on Card)
+
+* MMCCMD 0 A0/1
+* MMCCLK 1 A1/1
+* MMCD0 2 A2/1
+* MMCD1 3 A3/1
+* MMCD2 4 A4/1
+* MMCD3 5 A5/1
+* MMCD4 6 A6/1
+* MMCD5 7 A7/1
+* MMCD6 8 A8/1
+* MMCD7 9 A9/1
+
+## SD1
+
+user-facing: internal (on Card), multiplexed with JTAG1
+and UART2, for debug purposes
+
+* SD1_CMD 10 A10/2
+* SD1_CLK 11 A11/2
+* SD1_D0 12 A12/2
+* SD1_D1 13 A13/2
+* SD1_D2 14 A14/2
+* SD1_D3 15 A15/2
+
+## UART3
+
+EOMA68-compliance
+
+* UART3_TX 89 D21/2
+* UART3_RX 90 D22/2
+
+## TWI3
+
+EOMA68-compliance: must be entirely free of devices.
+Address 0x51 used (externally) for EOMA68 EEPROM Id
+
+* TWI3_SDA 87 D19/2
+* TWI3_SCL 88 D20/2
+
+## SPI2
+
+EOMA68-compliance
+
+* SPI2_CLK 52 C8/2
+* SPI2_NSS 53 C9/2
+* SPI2_MOSI 54 C10/2
+* SPI2_MISO 55 C11/2
+
+## E2:SD2
+
+EOMA68-compliance
+
+* SD2_CMD 92 E0/2
+* SD2_CLK 93 E1/2
+* SD2_D0 94 E2/2
+* SD2_D1 95 E3/2
+* SD2_D2 96 E4/2
+* SD2_D3 97 E5/2
+
+## EINT
+
+* EINT16 98 E6/3 
+* EINT17 99 E7/3 
+* EINT18 116 F0/3 
+* EINT19 117 F1/3 
+
+## PWM
+
+* PWM_2 91 D23/1 
+
+## Unused Pinouts (spare as GPIO) for 'EOMA68'
+
+| Pin | Mux0        | Mux1        | Mux2        | Mux3        |
+| --- | ----------- | ----------- | ----------- | ----------- |
+|  38 | B GPIOB22   | B LCD18_0   | B SD1_CMD   | B FB_AD26   |
+|  39 | B GPIOB23   | B LCD19_0   | B SD1_CLK   | B FB_AD27   |
+|  40 | B GPIOB24   | B LCD20_0   | B SD1_D0    | B FB_AD28   |
+|  41 | B GPIOB25   | B LCD21_0   | B SD1_D1    | B FB_AD29   |
+|  42 | B GPIOB26   | B LCD22_0   | B SD1_D2    | B FB_AD30   |
+|  43 | B GPIOB27   | B LCD23_0   | B SD1_D3    | B FB_AD31   |
+|  68 | D GPIOD0    | D FB_AD0    | D UART0_TX  | D EINT30    |
+|  69 | D GPIOD1    | D FB_AD1    | D UART0_RX  | D EINT31    |
+|  70 | D GPIOD2    | D FB_AD2    | D UART0_CTS | D TWI2_SDA  |
+|  71 | D GPIOD3    | D FB_AD3    | D UART0_RTS | D TWI2_SCL  |
+|  72 | D GPIOD4    | D FB_AD4    | D SD2_CMD   |             |
+|  73 | D GPIOD5    | D FB_AD5    | D SD2_CLK   |             |
+|  74 | D GPIOD6    | D FB_AD6    | D SD2_D0    |             |
+|  75 | D GPIOD7    | D FB_AD7    | D SD2_D1    |             |
+|  76 | D GPIOD8    | D FB_CS0    | D SD2_D2    |             |
+|  77 | D GPIOD9    | D FB_CS1    | D SD2_D3    |             |
+|  78 | D GPIOD10   | D FB_ALE    | D FB_TS     | D TWI1_SDA  |
+|  79 | D GPIOD11   | D FB_OE     | D FB_TBST   | D TWI1_SCL  |
+|  80 | D GPIOD12   | D FB_RW     |             |             |
+|  81 | D GPIOD13   | D FB_TA     | D UART4_TX  | D EINT5     |
+|  82 | D GPIOD14   | D FB_CLK    | D UART4_RX  | D EINT6     |
+|  83 | D GPIOD15   | D FB_BWE0   | D FB_TSIZ0  | D EINT7     |
+|  84 | D GPIOD16   | D FB_BWE1   | D FB_TSIZ1  | D EINT8     |
+|  85 | D GPIOD17   | D FB_BWE2   | D TWI2_SDA  | D FB_A0     |
+|  86 | D GPIOD18   | D FB_BWE3   | D TWI2_SCL  | D FB_A1     |
+| 100 | E GPIOE8    | E FB_AD16   | E SD3_CMD   | E EINT22    |
+| 101 | E GPIOE9    | E FB_AD17   | E SD3_CLK   | E EINT23    |
+| 102 | E GPIOE10   | E FB_AD18   | E SD3_D0    | E EINT24    |
+| 103 | E GPIOE11   | E FB_AD19   | E SD3_D1    | E EINT25    |
+| 104 | E GPIOE12   | E FB_AD20   | E SD3_D2    | E EINT26    |
+| 105 | E GPIOE13   | E FB_AD21   | E SD3_D3    | E EINT27    |
+| 106 | E GPIOE14   | E FB_AD22   | E UART1_TX  | E MMCCMD    |
+| 107 | E GPIOE15   | E FB_AD23   | E UART1_RX  | E MMCCLK    |
+| 108 | E GPIOE16   | E FB_AD24   | E UART1_CTS | E MMCD0     |
+| 109 | E GPIOE17   | E FB_AD25   | E UART1_RTS | E MMCD1     |
+| 110 | E GPIOE18   | E FB_AD26   | E SPI3_CK   | E MMCD2     |
+| 111 | E GPIOE19   | E FB_AD27   | E SPI3_NSS  | E MMCD3     |
+| 112 | E GPIOE20   | E FB_AD28   | E SPI3_IO0  | E MMCD4     |
+| 113 | E GPIOE21   | E FB_AD29   | E SPI3_IO1  | E MMCD5     |
+| 114 | E GPIOE22   | E FB_AD30   | E SPI3_IO2  | E MMCD6     |
+| 115 | E GPIOE23   | E FB_AD31   | E SPI3_IO3  | E MMCD7     |
+| 118 | F GPIOF2    | F IISLRCK   | F SD3_D0    | F EINT20    |
+| 119 | F GPIOF3    | F IISDI     | F SD3_D1    | F EINT21    |
+| 120 | F GPIOF4    | F IISDO0    | F SD3_D2    | F PWM_2     |
+| 121 | F GPIOF5    | F IISDO1    | F SD3_D3    | F EINT7     |
+| 122 | F GPIOF6    | F IISDO2    | F TWI1_SDA  | F EINT28    |
+| 123 | F GPIOF7    | F IISDO3    | F TWI1_SCL  | F EINT29    |
+| 124 | F GPIOF8    | F UART4_TX  | F PWM_0     | F EINT30    |
+| 125 | F GPIOF9    | F UART4_RX  | F PWM_1     | F EINT31    |
+| 126 | G GPIOG0    | G RG_ERXD0  | G LCDCK_1   | G FB_AD8    |
+| 127 | G GPIOG1    | G RG_ERXD1  | G LCDDE_1   | G FB_AD9    |
+| 128 | G GPIOG2    | G RG_ERXD2  | G LCDHS_1   | G FB_AD10   |
+| 129 | G GPIOG3    | G RG_ETXD0  | G LCDVS_1   | G FB_AD11   |
+| 130 | G GPIOG4    | G RG_ETXD1  | G LCD0_1    | G FB_AD12   |
+| 131 | G GPIOG5    | G RG_ETXD2  | G LCD1_1    | G FB_AD13   |
+| 132 | G GPIOG6    | G RG_FB_CS0 | G LCD2_1    | G FB_AD14   |
+| 133 | G GPIOG7    | G RG_FB_CS1 | G LCD3_1    | G FB_AD15   |
+| 134 | G GPIOG8    | G RG_ERXCK  | G LCD4_1    | G FB_AD16   |
+| 135 | G GPIOG9    | G RG_ERXERR | G LCD5_1    | G FB_AD17   |
+| 136 | G GPIOG10   | G RG_ERXDV  | G LCD6_1    | G FB_AD18   |
+| 137 | G GPIOG11   | G RG_EMDC   | G LCD7_1    | G FB_AD19   |
+| 138 | G GPIOG12   | G RG_EMDIO  | G LCD8_1    | G FB_AD20   |
+| 139 | G GPIOG13   | G RG_ETXEN  | G LCD9_1    | G FB_AD21   |
+| 140 | G GPIOG14   | G RG_ETXCK  | G LCD10_1   | G FB_AD22   |
+| 141 | G GPIOG15   | G RG_ECRS   | G LCD11_1   | G FB_AD23   |
+| 142 | G GPIOG16   | G RG_ECOL   | G LCD12_1   | G FB_AD24   |
+| 143 | G GPIOG17   | G RG_ETXERR | G LCD13_1   | G FB_AD25   |
+| 144 | G GPIOG18   | G ULPI3_CK  | G LCD14_1   | G FB_AD26   |
+| 145 | G GPIOG19   | G ULPI3_DIR | G LCD15_1   | G FB_AD27   |
+| 146 | G GPIOG20   | G ULPI3_STP | G LCD16_1   | G FB_AD28   |
+| 147 | G GPIOG21   | G ULPI3_NXT | G LCD17_1   | G FB_AD29   |
+| 148 | G GPIOG22   | G ULPI3_D0  | G LCD18_1   | G FB_AD30   |
+| 149 | G GPIOG23   | G ULPI3_D1  | G LCD19_1   | G FB_AD31   |
+| 150 | G GPIOG24   | G ULPI3_D2  | G LCD20_1   | G SD2_CMD   |
+| 151 | G GPIOG25   | G ULPI3_D3  | G LCD21_1   | G SD2_CLK   |
+| 152 | G GPIOG26   | G ULPI3_D4  | G LCD22_1   | G SPI3_CK   |
+| 153 | G GPIOG27   | G ULPI3_D5  | G LCD23_1   | G SPI3_NSS  |
+| 154 | G GPIOG28   | G ULPI3_D6  | G SD2_D0    | G SPI3_IO0  |
+| 155 | G GPIOG29   | G ULPI3_D7  | G SD2_D1    | G SPI3_IO1  |
+| 156 | G GPIOG30   |             | G SD2_D2    | G SPI3_IO2  |
+| 157 | G GPIOG31   |             | G SD2_D3    | G SPI3_IO3  |
+
+# Pinmap for Industrial
+
+## D1:FB/17
+
+* FB_AD0 68 D0/1
+* FB_AD1 69 D1/1
+* FB_AD2 70 D2/1
+* FB_AD3 71 D3/1
+* FB_AD4 72 D4/1
+* FB_AD5 73 D5/1
+* FB_AD6 74 D6/1
+* FB_AD7 75 D7/1
+* FB_CS0 76 D8/1
+* FB_CS1 77 D9/1
+* FB_ALE 78 D10/1
+* FB_OE 79 D11/1
+* FB_RW 80 D12/1
+* FB_TA 81 D13/1
+* FB_CLK 82 D14/1
+* FB_BWE0 83 D15/1
+* FB_BWE1 84 D16/1
+
+## E1:FB/8
+
+* FB_AD8 92 E0/1
+* FB_AD9 93 E1/1
+* FB_AD10 94 E2/1
+* FB_AD11 95 E3/1
+* FB_AD12 96 E4/1
+* FB_AD13 97 E5/1
+* FB_AD14 98 E6/1
+* FB_AD15 99 E7/1
+
+## B1:LCD/22
+
+* LCDCK_0 16 B0/1
+* LCDDE_0 17 B1/1
+* LCDHS_0 18 B2/1
+* LCDVS_0 19 B3/1
+* LCD0_0 20 B4/1
+* LCD1_0 21 B5/1
+* LCD2_0 22 B6/1
+* LCD3_0 23 B7/1
+* LCD4_0 24 B8/1
+* LCD5_0 25 B9/1
+* LCD6_0 26 B10/1
+* LCD7_0 27 B11/1
+* LCD8_0 28 B12/1
+* LCD9_0 29 B13/1
+* LCD10_0 30 B14/1
+* LCD11_0 31 B15/1
+* LCD12_0 32 B16/1
+* LCD13_0 33 B17/1
+* LCD14_0 34 B18/1
+* LCD15_0 35 B19/1
+* LCD16_0 36 B20/1
+* LCD17_0 37 B21/1
+
+## ULPI1/8
+
+* ULPI1_CK 44 C0/1
+* ULPI1_DIR 45 C1/1
+* ULPI1_STP 46 C2/1
+* ULPI1_NXT 47 C3/1
+* ULPI1_D0 48 C4/1
+* ULPI1_D1 49 C5/1
+* ULPI1_D2 50 C6/1
+* ULPI1_D3 51 C7/1
+
+## ULPI2/8
+
+* ULPI2_CK 56 C12/1
+* ULPI2_DIR 57 C13/1
+* ULPI2_STP 58 C14/1
+* ULPI2_NXT 59 C15/1
+* ULPI2_D0 60 C16/1
+* ULPI2_D1 61 C17/1
+* ULPI2_D2 62 C18/1
+* ULPI2_D3 63 C19/1
+
+## MMC
+
+* MMCCMD 0 A0/1
+* MMCCLK 1 A1/1
+* MMCD0 2 A2/1
+* MMCD1 3 A3/1
+* MMCD2 4 A4/1
+* MMCD3 5 A5/1
+* MMCD4 6 A6/1
+* MMCD5 7 A7/1
+* MMCD6 8 A8/1
+* MMCD7 9 A9/1
+
+## B2:SD1
+
+* SD1_CMD 38 B22/2
+* SD1_CLK 39 B23/2
+* SD1_D0 40 B24/2
+* SD1_D1 41 B25/2
+* SD1_D2 42 B26/2
+* SD1_D3 43 B27/2
+
+## JTAG1
+
+* JTAG1_MS 10 A10/3
+* JTAG1_DI 11 A11/3
+* JTAG1_DO 12 A12/3
+* JTAG1_CK 13 A13/3
+
+## A3:UART2
+
+* UART2_TX 14 A14/3
+* UART2_RX 15 A15/3
+
+## E2:UART1
+
+* UART1_TX 106 E14/2
+* UART1_RX 107 E15/2
+* UART1_CTS 108 E16/2
+* UART1_RTS 109 E17/2
+
+## C3:UART0
+
+* UART0_TX 64 C20/3
+* UART0_RX 65 C21/3
+* UART0_CTS 66 C22/3
+* UART0_RTS 67 C23/3
+
+## F2:TWI1
+
+* TWI1_SDA 122 F6/2
+* TWI1_SCL 123 F7/2
+
+## D2:TWI2
+
+* TWI2_SDA 85 D17/2
+* TWI2_SCL 86 D18/2
+
+## D2:TWI3
+
+* TWI3_SDA 87 D19/2
+* TWI3_SCL 88 D20/2
+
+## SPI2
+
+* SPI2_CLK 52 C8/2
+* SPI2_NSS 53 C9/2
+* SPI2_MOSI 54 C10/2
+* SPI2_MISO 55 C11/2
+
+## SPI3
+
+* SPI3_CK 110 E18/2
+* SPI3_NSS 111 E19/2
+* SPI3_IO0 112 E20/2
+* SPI3_IO1 113 E21/2
+* SPI3_IO2 114 E22/2
+* SPI3_IO3 115 E23/2
+
+## F2:SD3
+
+* SD3_CMD 116 F0/2
+* SD3_CLK 117 F1/2
+* SD3_D0 118 F2/2
+* SD3_D1 119 F3/2
+* SD3_D2 120 F4/2
+* SD3_D3 121 F5/2
+
+## EINT
+
+* EINT24 102 E10/3 
+* EINT25 103 E11/3 
+* EINT26 104 E12/3 
+* EINT27 105 E13/3 
+* EINT20 89 D21/3 
+* EINT21 90 D22/3 
+* EINT22 100 E8/3 
+* EINT23 101 E9/3 
+
+## PWM
+
+* PWM_0 124 F8/2 
+* PWM_1 125 F9/2 
+* PWM_2 91 D23/1 
+
+## Unused Pinouts (spare as GPIO) for 'Industrial'
+
+| Pin | Mux0        | Mux1        | Mux2        | Mux3        |
+| --- | ----------- | ----------- | ----------- | ----------- |
+| 126 | G GPIOG0    | G RG_ERXD0  | G LCDCK_1   | G FB_AD8    |
+| 127 | G GPIOG1    | G RG_ERXD1  | G LCDDE_1   | G FB_AD9    |
+| 128 | G GPIOG2    | G RG_ERXD2  | G LCDHS_1   | G FB_AD10   |
+| 129 | G GPIOG3    | G RG_ETXD0  | G LCDVS_1   | G FB_AD11   |
+| 130 | G GPIOG4    | G RG_ETXD1  | G LCD0_1    | G FB_AD12   |
+| 131 | G GPIOG5    | G RG_ETXD2  | G LCD1_1    | G FB_AD13   |
+| 132 | G GPIOG6    | G RG_FB_CS0 | G LCD2_1    | G FB_AD14   |
+| 133 | G GPIOG7    | G RG_FB_CS1 | G LCD3_1    | G FB_AD15   |
+| 134 | G GPIOG8    | G RG_ERXCK  | G LCD4_1    | G FB_AD16   |
+| 135 | G GPIOG9    | G RG_ERXERR | G LCD5_1    | G FB_AD17   |
+| 136 | G GPIOG10   | G RG_ERXDV  | G LCD6_1    | G FB_AD18   |
+| 137 | G GPIOG11   | G RG_EMDC   | G LCD7_1    | G FB_AD19   |
+| 138 | G GPIOG12   | G RG_EMDIO  | G LCD8_1    | G FB_AD20   |
+| 139 | G GPIOG13   | G RG_ETXEN  | G LCD9_1    | G FB_AD21   |
+| 140 | G GPIOG14   | G RG_ETXCK  | G LCD10_1   | G FB_AD22   |
+| 141 | G GPIOG15   | G RG_ECRS   | G LCD11_1   | G FB_AD23   |
+| 142 | G GPIOG16   | G RG_ECOL   | G LCD12_1   | G FB_AD24   |
+| 143 | G GPIOG17   | G RG_ETXERR | G LCD13_1   | G FB_AD25   |
+| 144 | G GPIOG18   | G ULPI3_CK  | G LCD14_1   | G FB_AD26   |
+| 145 | G GPIOG19   | G ULPI3_DIR | G LCD15_1   | G FB_AD27   |
+| 146 | G GPIOG20   | G ULPI3_STP | G LCD16_1   | G FB_AD28   |
+| 147 | G GPIOG21   | G ULPI3_NXT | G LCD17_1   | G FB_AD29   |
+| 148 | G GPIOG22   | G ULPI3_D0  | G LCD18_1   | G FB_AD30   |
+| 149 | G GPIOG23   | G ULPI3_D1  | G LCD19_1   | G FB_AD31   |
+| 150 | G GPIOG24   | G ULPI3_D2  | G LCD20_1   | G SD2_CMD   |
+| 151 | G GPIOG25   | G ULPI3_D3  | G LCD21_1   | G SD2_CLK   |
+| 152 | G GPIOG26   | G ULPI3_D4  | G LCD22_1   | G SPI3_CK   |
+| 153 | G GPIOG27   | G ULPI3_D5  | G LCD23_1   | G SPI3_NSS  |
+| 154 | G GPIOG28   | G ULPI3_D6  | G SD2_D0    | G SPI3_IO0  |
+| 155 | G GPIOG29   | G ULPI3_D7  | G SD2_D1    | G SPI3_IO1  |
+| 156 | G GPIOG30   |             | G SD2_D2    | G SPI3_IO2  |
+| 157 | G GPIOG31   |             | G SD2_D3    | G SPI3_IO3  |
+
+# Pinmap for Industrial with SPI-LCD
+
+## D1:FB/17
+
+* FB_AD0 68 D0/1
+* FB_AD1 69 D1/1
+* FB_AD2 70 D2/1
+* FB_AD3 71 D3/1
+* FB_AD4 72 D4/1
+* FB_AD5 73 D5/1
+* FB_AD6 74 D6/1
+* FB_AD7 75 D7/1
+* FB_CS0 76 D8/1
+* FB_CS1 77 D9/1
+* FB_ALE 78 D10/1
+* FB_OE 79 D11/1
+* FB_RW 80 D12/1
+* FB_TA 81 D13/1
+* FB_CLK 82 D14/1
+* FB_BWE0 83 D15/1
+* FB_BWE1 84 D16/1
+
+## E1:FB/8
+
+* FB_AD8 92 E0/1
+* FB_AD9 93 E1/1
+* FB_AD10 94 E2/1
+* FB_AD11 95 E3/1
+* FB_AD12 96 E4/1
+* FB_AD13 97 E5/1
+* FB_AD14 98 E6/1
+* FB_AD15 99 E7/1
+
+## B2:SPI1
+
+Used for 320x240 or 640x480 etc. SPI-based LCD.
+Frees up large numbers of GPIO from RGB/TTL bank
+
+* SPI1_CLK 28 B12/2
+* SPI1_NSS 29 B13/2
+* SPI1_MOSI 30 B14/2
+* SPI1_MISO 31 B15/2
+
+## ULPI1/8
+
+* ULPI1_CK 44 C0/1
+* ULPI1_DIR 45 C1/1
+* ULPI1_STP 46 C2/1
+* ULPI1_NXT 47 C3/1
+* ULPI1_D0 48 C4/1
+* ULPI1_D1 49 C5/1
+* ULPI1_D2 50 C6/1
+* ULPI1_D3 51 C7/1
+
+## ULPI2/8
+
+* ULPI2_CK 56 C12/1
+* ULPI2_DIR 57 C13/1
+* ULPI2_STP 58 C14/1
+* ULPI2_NXT 59 C15/1
+* ULPI2_D0 60 C16/1
+* ULPI2_D1 61 C17/1
+* ULPI2_D2 62 C18/1
+* ULPI2_D3 63 C19/1
+
+## MMC
+
+* MMCCMD 0 A0/1
+* MMCCLK 1 A1/1
+* MMCD0 2 A2/1
+* MMCD1 3 A3/1
+* MMCD2 4 A4/1
+* MMCD3 5 A5/1
+* MMCD4 6 A6/1
+* MMCD5 7 A7/1
+* MMCD6 8 A8/1
+* MMCD7 9 A9/1
+
+## B2:SD1
+
+* SD1_CMD 38 B22/2
+* SD1_CLK 39 B23/2
+* SD1_D0 40 B24/2
+* SD1_D1 41 B25/2
+* SD1_D2 42 B26/2
+* SD1_D3 43 B27/2
+
+## JTAG1
+
+* JTAG1_MS 10 A10/3
+* JTAG1_DI 11 A11/3
+* JTAG1_DO 12 A12/3
+* JTAG1_CK 13 A13/3
+
+## A3:UART2
+
+* UART2_TX 14 A14/3
+* UART2_RX 15 A15/3
+
+## E2:UART1
+
+* UART1_TX 106 E14/2
+* UART1_RX 107 E15/2
+* UART1_CTS 108 E16/2
+* UART1_RTS 109 E17/2
+
+## C3:UART0
+
+* UART0_TX 64 C20/3
+* UART0_RX 65 C21/3
+* UART0_CTS 66 C22/3
+* UART0_RTS 67 C23/3
+
+## B2:UART4
+
+* UART4_TX 26 B10/2
+* UART4_RX 27 B11/2
+
+## B2:UART3
+
+* UART3_TX 32 B16/2
+* UART3_RX 33 B17/2
+
+## F2:TWI1
+
+* TWI1_SDA 122 F6/2
+* TWI1_SCL 123 F7/2
+
+## D2:TWI2
+
+* TWI2_SDA 85 D17/2
+* TWI2_SCL 86 D18/2
+
+## D2:TWI3
+
+* TWI3_SDA 87 D19/2
+* TWI3_SCL 88 D20/2
+
+## SPI2
+
+* SPI2_CLK 52 C8/2
+* SPI2_NSS 53 C9/2
+* SPI2_MOSI 54 C10/2
+* SPI2_MISO 55 C11/2
+
+## SPI3
+
+* SPI3_CK 20 B4/2
+* SPI3_NSS 21 B5/2
+* SPI3_IO0 22 B6/2
+* SPI3_IO1 23 B7/2
+* SPI3_IO2 114 E22/2
+* SPI3_IO3 115 E23/2
+
+## F2:SD3
+
+* SD3_CMD 116 F0/2
+* SD3_CLK 117 F1/2
+* SD3_D0 118 F2/2
+* SD3_D1 119 F3/2
+* SD3_D2 120 F4/2
+* SD3_D3 121 F5/2
+
+## EINT
+
+* EINT24 102 E10/3 
+* EINT25 103 E11/3 
+* EINT26 104 E12/3 
+* EINT27 105 E13/3 
+* EINT20 89 D21/3 
+* EINT21 90 D22/3 
+* EINT22 100 E8/3 
+* EINT23 101 E9/3 
+
+## PWM
+
+* PWM_0 124 F8/2 
+* PWM_1 125 F9/2 
+* PWM_2 91 D23/1 
+
+## Unused Pinouts (spare as GPIO) for 'Industrial with SPI-LCD'
+
+| Pin | Mux0        | Mux1        | Mux2        | Mux3        |
+| --- | ----------- | ----------- | ----------- | ----------- |
+|  16 | B GPIOB0    | B LCDCK_0   | B TWI1_SDA  | B EINT6     |
+|  17 | B GPIOB1    | B LCDDE_0   | B TWI1_SCL  | B EINT7     |
+|  18 | B GPIOB2    | B LCDHS_0   | B UART2_TX  | B EINT8     |
+|  19 | B GPIOB3    | B LCDVS_0   | B UART2_RX  | B EINT9     |
+|  24 | B GPIOB8    | B LCD4_0    |             | B FB_AD12   |
+|  25 | B GPIOB9    | B LCD5_0    | B PWM_0     | B FB_AD13   |
+|  34 | B GPIOB18   | B LCD14_0   | B TWI3_SDA  | B FB_AD22   |
+|  35 | B GPIOB19   | B LCD15_0   | B TWI3_SCL  | B FB_AD23   |
+|  36 | B GPIOB20   | B LCD16_0   | B PWM_1     | B FB_AD24   |
+|  37 | B GPIOB21   | B LCD17_0   | B PWM_2     | B FB_AD25   |
+| 110 | E GPIOE18   | E FB_AD26   | E SPI3_CK   | E MMCD2     |
+| 111 | E GPIOE19   | E FB_AD27   | E SPI3_NSS  | E MMCD3     |
+| 112 | E GPIOE20   | E FB_AD28   | E SPI3_IO0  | E MMCD4     |
+| 113 | E GPIOE21   | E FB_AD29   | E SPI3_IO1  | E MMCD5     |
+| 126 | G GPIOG0    | G RG_ERXD0  | G LCDCK_1   | G FB_AD8    |
+| 127 | G GPIOG1    | G RG_ERXD1  | G LCDDE_1   | G FB_AD9    |
+| 128 | G GPIOG2    | G RG_ERXD2  | G LCDHS_1   | G FB_AD10   |
+| 129 | G GPIOG3    | G RG_ETXD0  | G LCDVS_1   | G FB_AD11   |
+| 130 | G GPIOG4    | G RG_ETXD1  | G LCD0_1    | G FB_AD12   |
+| 131 | G GPIOG5    | G RG_ETXD2  | G LCD1_1    | G FB_AD13   |
+| 132 | G GPIOG6    | G RG_FB_CS0 | G LCD2_1    | G FB_AD14   |
+| 133 | G GPIOG7    | G RG_FB_CS1 | G LCD3_1    | G FB_AD15   |
+| 134 | G GPIOG8    | G RG_ERXCK  | G LCD4_1    | G FB_AD16   |
+| 135 | G GPIOG9    | G RG_ERXERR | G LCD5_1    | G FB_AD17   |
+| 136 | G GPIOG10   | G RG_ERXDV  | G LCD6_1    | G FB_AD18   |
+| 137 | G GPIOG11   | G RG_EMDC   | G LCD7_1    | G FB_AD19   |
+| 138 | G GPIOG12   | G RG_EMDIO  | G LCD8_1    | G FB_AD20   |
+| 139 | G GPIOG13   | G RG_ETXEN  | G LCD9_1    | G FB_AD21   |
+| 140 | G GPIOG14   | G RG_ETXCK  | G LCD10_1   | G FB_AD22   |
+| 141 | G GPIOG15   | G RG_ECRS   | G LCD11_1   | G FB_AD23   |
+| 142 | G GPIOG16   | G RG_ECOL   | G LCD12_1   | G FB_AD24   |
+| 143 | G GPIOG17   | G RG_ETXERR | G LCD13_1   | G FB_AD25   |
+| 144 | G GPIOG18   | G ULPI3_CK  | G LCD14_1   | G FB_AD26   |
+| 145 | G GPIOG19   | G ULPI3_DIR | G LCD15_1   | G FB_AD27   |
+| 146 | G GPIOG20   | G ULPI3_STP | G LCD16_1   | G FB_AD28   |
+| 147 | G GPIOG21   | G ULPI3_NXT | G LCD17_1   | G FB_AD29   |
+| 148 | G GPIOG22   | G ULPI3_D0  | G LCD18_1   | G FB_AD30   |
+| 149 | G GPIOG23   | G ULPI3_D1  | G LCD19_1   | G FB_AD31   |
+| 150 | G GPIOG24   | G ULPI3_D2  | G LCD20_1   | G SD2_CMD   |
+| 151 | G GPIOG25   | G ULPI3_D3  | G LCD21_1   | G SD2_CLK   |
+| 152 | G GPIOG26   | G ULPI3_D4  | G LCD22_1   | G SPI3_CK   |
+| 153 | G GPIOG27   | G ULPI3_D5  | G LCD23_1   | G SPI3_NSS  |
+| 154 | G GPIOG28   | G ULPI3_D6  | G SD2_D0    | G SPI3_IO0  |
+| 155 | G GPIOG29   | G ULPI3_D7  | G SD2_D1    | G SPI3_IO1  |
+| 156 | G GPIOG30   |             | G SD2_D2    | G SPI3_IO2  |
+| 157 | G GPIOG31   |             | G SD2_D3    | G SPI3_IO3  |
+
+# Pinmap for Smartphone / Tablet
+
+## B1:LCD/22
+
+RGB/TTL LCD, 800x480 or use SN75LVDS83b for up to 1440x900
+
+* LCDCK_0 16 B0/1
+* LCDDE_0 17 B1/1
+* LCDHS_0 18 B2/1
+* LCDVS_0 19 B3/1
+* LCD0_0 20 B4/1
+* LCD1_0 21 B5/1
+* LCD2_0 22 B6/1
+* LCD3_0 23 B7/1
+* LCD4_0 24 B8/1
+* LCD5_0 25 B9/1
+* LCD6_0 26 B10/1
+* LCD7_0 27 B11/1
+* LCD8_0 28 B12/1
+* LCD9_0 29 B13/1
+* LCD10_0 30 B14/1
+* LCD11_0 31 B15/1
+* LCD12_0 32 B16/1
+* LCD13_0 33 B17/1
+* LCD14_0 34 B18/1
+* LCD15_0 35 B19/1
+* LCD16_0 36 B20/1
+* LCD17_0 37 B21/1
+
+## ULPI1/8
+
+USB-OTG, connect to ULPI OTG PHY (for charging)
+as well as USB Host or USB Device
+
+* ULPI1_CK 44 C0/1
+* ULPI1_DIR 45 C1/1
+* ULPI1_STP 46 C2/1
+* ULPI1_NXT 47 C3/1
+* ULPI1_D0 48 C4/1
+* ULPI1_D1 49 C5/1
+* ULPI1_D2 50 C6/1
+* ULPI1_D3 51 C7/1
+
+## ULPI2/8
+
+USB2 Host, connect to ULPI PHY w/and 4-port USB2 Hub
+for example GL850G or FE1.1. Connects to 2/3/4G/LTE Modem, 2x USB-Camera (VC0345)
+
+* ULPI2_CK 56 C12/1
+* ULPI2_DIR 57 C13/1
+* ULPI2_STP 58 C14/1
+* ULPI2_NXT 59 C15/1
+* ULPI2_D0 60 C16/1
+* ULPI2_D1 61 C17/1
+* ULPI2_D2 62 C18/1
+* ULPI2_D3 63 C19/1
+
+## MMC
+
+eMMC: main internal storage
+
+* MMCCMD 0 A0/1
+* MMCCLK 1 A1/1
+* MMCD0 2 A2/1
+* MMCD1 3 A3/1
+* MMCD2 4 A4/1
+* MMCD3 5 A5/1
+* MMCD4 6 A6/1
+* MMCD5 7 A7/1
+* MMCD6 8 A8/1
+* MMCD7 9 A9/1
+
+## SD1
+
+internal, multiplexed with JTAG1
+and UART2, for debug purposes
+
+* SD1_CMD 10 A10/2
+* SD1_CLK 11 A11/2
+* SD1_D0 12 A12/2
+* SD1_D1 13 A13/2
+* SD1_D2 14 A14/2
+* SD1_D3 15 A15/2
+
+## F1:IIS
+
+I2C Audio, connect to AC97 Audio IC
+
+* IISMCK 116 F0/1
+* IISBCK 117 F1/1
+* IISLRCK 118 F2/1
+* IISDI 119 F3/1
+* IISDO0 120 F4/1
+* IISDO1 121 F5/1
+* IISDO2 122 F6/1
+* IISDO3 123 F7/1
+
+## TWI2
+
+Connect to AC97 Audio IC
+
+* TWI2_SDA 70 D2/3
+* TWI2_SCL 71 D3/3
+
+## E2:UART1
+
+Connect to BT on AP6234/AP6335
+
+* UART1_TX 106 E14/2
+* UART1_RX 107 E15/2
+* UART1_CTS 108 E16/2
+* UART1_RTS 109 E17/2
+
+## E2:SD2
+
+Connect to WIFI on AP6234/AP6335
+
+* SD2_CMD 92 E0/2
+* SD2_CLK 93 E1/2
+* SD2_D0 94 E2/2
+* SD2_D1 95 E3/2
+* SD2_D2 96 E4/2
+* SD2_D3 97 E5/2
+
+## C3:UART0
+
+* UART0_TX 64 C20/3
+* UART0_RX 65 C21/3
+* UART0_CTS 66 C22/3
+* UART0_RTS 67 C23/3
+
+## D2:UART3
+
+Spare? UART (or 2 extra GPIO / EINT)
+
+* UART3_TX 89 D21/2
+* UART3_RX 90 D22/2
+
+## D2:UART4
+
+Spare? UART (or 2 extra GPIO)
+
+* UART4_TX 81 D13/2
+* UART4_RX 82 D14/2
+
+## D3:TWI1
+
+Connect to PMIC
+
+* TWI1_SDA 78 D10/3
+* TWI1_SCL 79 D11/3
+
+## D2:TWI3
+
+Connect to sensors (Trackpad? CTP GSENSOR TILT COMPASS)
+
+* TWI3_SDA 87 D19/2
+* TWI3_SCL 88 D20/2
+
+## SPI2
+
+Spare? SPI, connect to higher-speed sensor?
+
+* SPI2_CLK 52 C8/2
+* SPI2_NSS 53 C9/2
+* SPI2_MOSI 54 C10/2
+* SPI2_MISO 55 C11/2
+
+## SPI3
+
+Boot Storage (connection to companion / debug / boot MCU)
+Only actually needs MISO/MOSI, bootstrap loader v. small
+Bootstrap loader checks eMMC, USB-OTG, SD/MMC, SPI, etc.
+
+* SPI3_CK 110 E18/2
+* SPI3_NSS 111 E19/2
+* SPI3_IO0 112 E20/2
+* SPI3_IO1 113 E21/2
+* SPI3_IO2 114 E22/2
+* SPI3_IO3 115 E23/2
+
+## EINT
+
+* EINT24 102 E10/3 : BT_HOST_WAKE
+* EINT25 103 E11/3 : WIFI_HOST_WAKE
+* EINT26 104 E12/3 : CTP_INT
+* EINT27 105 E13/3 : GSENSOR_INT
+* EINT8 84 D16/3 : GPS_INT
+* EINT7 83 D15/3 : TILT_SENSOR_INT
+* EINT22 100 E8/3 : COMPASS_INT
+* EINT23 101 E9/3 : MCU_INT
+* EINT16 98 E6/3 : PMIC_INT
+* EINT17 99 E7/3 : PWR_BUTTON_INT
+* EINT30 68 D0/3 : OTG_ID
+* EINT31 69 D1/3 : Spare?
+
+## PWM
+
+* PWM_0 124 F8/2 : LCD Backlight
+* PWM_1 125 F9/2 : Spare? PWM (or extra GPIO / EINT)
+* PWM_2 91 D23/1 : Spare? PWM (or extra GPIO / EINT)
+
+## Unused Pinouts (spare as GPIO) for 'Smartphone / Tablet'
+
+9 spare GPIO pins for miscellaneous functions:
+wake-up of BT, WIFI, LCD power, sensor power etc.
+4 GPIO may be needed for PWM Audio from Modem.
+LED lights for camera will be needed.
+Some phones may have clam-shell or lid switch.
+Some Modems have spare GPIO (over AT commandset).
+AXP209 PMIC has 4x GPIO, accessible over I2C.
+SPI2, UART3-4, PWM1-2 may also be spare (10 extra GPIO).
+If more needed, companion MCU may be used (48+ pin variant)
+which also includes ADC, DAC, more PWM etc.
+
+| Pin | Mux0        | Mux1        | Mux2        | Mux3        |
+| --- | ----------- | ----------- | ----------- | ----------- |
+|  38 | B GPIOB22   | B LCD18_0   | B SD1_CMD   | B FB_AD26   |
+|  39 | B GPIOB23   | B LCD19_0   | B SD1_CLK   | B FB_AD27   |
+|  40 | B GPIOB24   | B LCD20_0   | B SD1_D0    | B FB_AD28   |
+|  41 | B GPIOB25   | B LCD21_0   | B SD1_D1    | B FB_AD29   |
+|  42 | B GPIOB26   | B LCD22_0   | B SD1_D2    | B FB_AD30   |
+|  43 | B GPIOB27   | B LCD23_0   | B SD1_D3    | B FB_AD31   |
+|  72 | D GPIOD4    | D FB_AD4    | D SD2_CMD   |             |
+|  73 | D GPIOD5    | D FB_AD5    | D SD2_CLK   |             |
+|  74 | D GPIOD6    | D FB_AD6    | D SD2_D0    |             |
+|  75 | D GPIOD7    | D FB_AD7    | D SD2_D1    |             |
+|  76 | D GPIOD8    | D FB_CS0    | D SD2_D2    |             |
+|  77 | D GPIOD9    | D FB_CS1    | D SD2_D3    |             |
+|  80 | D GPIOD12   | D FB_RW     |             |             |
+|  85 | D GPIOD17   | D FB_BWE2   | D TWI2_SDA  | D FB_A0     |
+|  86 | D GPIOD18   | D FB_BWE3   | D TWI2_SCL  | D FB_A1     |
+| 126 | G GPIOG0    | G RG_ERXD0  | G LCDCK_1   | G FB_AD8    |
+| 127 | G GPIOG1    | G RG_ERXD1  | G LCDDE_1   | G FB_AD9    |
+| 128 | G GPIOG2    | G RG_ERXD2  | G LCDHS_1   | G FB_AD10   |
+| 129 | G GPIOG3    | G RG_ETXD0  | G LCDVS_1   | G FB_AD11   |
+| 130 | G GPIOG4    | G RG_ETXD1  | G LCD0_1    | G FB_AD12   |
+| 131 | G GPIOG5    | G RG_ETXD2  | G LCD1_1    | G FB_AD13   |
+| 132 | G GPIOG6    | G RG_FB_CS0 | G LCD2_1    | G FB_AD14   |
+| 133 | G GPIOG7    | G RG_FB_CS1 | G LCD3_1    | G FB_AD15   |
+| 134 | G GPIOG8    | G RG_ERXCK  | G LCD4_1    | G FB_AD16   |
+| 135 | G GPIOG9    | G RG_ERXERR | G LCD5_1    | G FB_AD17   |
+| 136 | G GPIOG10   | G RG_ERXDV  | G LCD6_1    | G FB_AD18   |
+| 137 | G GPIOG11   | G RG_EMDC   | G LCD7_1    | G FB_AD19   |
+| 138 | G GPIOG12   | G RG_EMDIO  | G LCD8_1    | G FB_AD20   |
+| 139 | G GPIOG13   | G RG_ETXEN  | G LCD9_1    | G FB_AD21   |
+| 140 | G GPIOG14   | G RG_ETXCK  | G LCD10_1   | G FB_AD22   |
+| 141 | G GPIOG15   | G RG_ECRS   | G LCD11_1   | G FB_AD23   |
+| 142 | G GPIOG16   | G RG_ECOL   | G LCD12_1   | G FB_AD24   |
+| 143 | G GPIOG17   | G RG_ETXERR | G LCD13_1   | G FB_AD25   |
+| 144 | G GPIOG18   | G ULPI3_CK  | G LCD14_1   | G FB_AD26   |
+| 145 | G GPIOG19   | G ULPI3_DIR | G LCD15_1   | G FB_AD27   |
+| 146 | G GPIOG20   | G ULPI3_STP | G LCD16_1   | G FB_AD28   |
+| 147 | G GPIOG21   | G ULPI3_NXT | G LCD17_1   | G FB_AD29   |
+| 148 | G GPIOG22   | G ULPI3_D0  | G LCD18_1   | G FB_AD30   |
+| 149 | G GPIOG23   | G ULPI3_D1  | G LCD19_1   | G FB_AD31   |
+| 150 | G GPIOG24   | G ULPI3_D2  | G LCD20_1   | G SD2_CMD   |
+| 151 | G GPIOG25   | G ULPI3_D3  | G LCD21_1   | G SD2_CLK   |
+| 152 | G GPIOG26   | G ULPI3_D4  | G LCD22_1   | G SPI3_CK   |
+| 153 | G GPIOG27   | G ULPI3_D5  | G LCD23_1   | G SPI3_NSS  |
+| 154 | G GPIOG28   | G ULPI3_D6  | G SD2_D0    | G SPI3_IO0  |
+| 155 | G GPIOG29   | G ULPI3_D7  | G SD2_D1    | G SPI3_IO1  |
+| 156 | G GPIOG30   |             | G SD2_D2    | G SPI3_IO2  |
+| 157 | G GPIOG31   |             | G SD2_D3    | G SPI3_IO3  |
+
+# Pinmap for Laptop / Netbook
+
+## D1:FB/17
+
+FlexBus.  Connect to DM9000 or AX99896A MCU-style Bus
+10/100 Ethernet PHY.
+
+* FB_AD0 68 D0/1
+* FB_AD1 69 D1/1
+* FB_AD2 70 D2/1
+* FB_AD3 71 D3/1
+* FB_AD4 72 D4/1
+* FB_AD5 73 D5/1
+* FB_AD6 74 D6/1
+* FB_AD7 75 D7/1
+* FB_CS0 76 D8/1
+* FB_CS1 77 D9/1
+* FB_ALE 78 D10/1
+* FB_OE 79 D11/1
+* FB_RW 80 D12/1
+* FB_TA 81 D13/1
+* FB_CLK 82 D14/1
+* FB_BWE0 83 D15/1
+* FB_BWE1 84 D16/1
+
+## E1:FB/8
+
+FlexBus bus bits 8-15, needed to make a 16-bit bus width
+
+* FB_AD8 92 E0/1
+* FB_AD9 93 E1/1
+* FB_AD10 94 E2/1
+* FB_AD11 95 E3/1
+* FB_AD12 96 E4/1
+* FB_AD13 97 E5/1
+* FB_AD14 98 E6/1
+* FB_AD15 99 E7/1
+
+## B1:LCD/22
+
+RGB/TTL LCD, use SN75LVDS83b for LVDS or SSD2828 for MIPI,
+or a Chrontel CH7039, CH7038, CH7034 or CH7018 for dual
+display output (eDP/LVDS and HDMI/VGA) conversion.
+
+* LCDCK_0 16 B0/1
+* LCDDE_0 17 B1/1
+* LCDHS_0 18 B2/1
+* LCDVS_0 19 B3/1
+* LCD0_0 20 B4/1
+* LCD1_0 21 B5/1
+* LCD2_0 22 B6/1
+* LCD3_0 23 B7/1
+* LCD4_0 24 B8/1
+* LCD5_0 25 B9/1
+* LCD6_0 26 B10/1
+* LCD7_0 27 B11/1
+* LCD8_0 28 B12/1
+* LCD9_0 29 B13/1
+* LCD10_0 30 B14/1
+* LCD11_0 31 B15/1
+* LCD12_0 32 B16/1
+* LCD13_0 33 B17/1
+* LCD14_0 34 B18/1
+* LCD15_0 35 B19/1
+* LCD16_0 36 B20/1
+* LCD17_0 37 B21/1
+
+## ULPI1/8
+
+USB-OTG, connect to ULPI OTG PHY (for charging)
+as well as USB Host or USB Device
+
+* ULPI1_CK 44 C0/1
+* ULPI1_DIR 45 C1/1
+* ULPI1_STP 46 C2/1
+* ULPI1_NXT 47 C3/1
+* ULPI1_D0 48 C4/1
+* ULPI1_D1 49 C5/1
+* ULPI1_D2 50 C6/1
+* ULPI1_D3 51 C7/1
+
+## ULPI2/8
+
+USB2 Host, connect to ULPI PHY w/and 4-port USB2 Hub
+for example GL850G or FE1.1. Connects to USB-Camera (VC0345 and 3x external USB Ports)
+
+* ULPI2_CK 56 C12/1
+* ULPI2_DIR 57 C13/1
+* ULPI2_STP 58 C14/1
+* ULPI2_NXT 59 C15/1
+* ULPI2_D0 60 C16/1
+* ULPI2_D1 61 C17/1
+* ULPI2_D2 62 C18/1
+* ULPI2_D3 63 C19/1
+
+## MMC
+
+eMMC: main internal storage
+
+* MMCCMD 0 A0/1
+* MMCCLK 1 A1/1
+* MMCD0 2 A2/1
+* MMCD1 3 A3/1
+* MMCD2 4 A4/1
+* MMCD3 5 A5/1
+* MMCD4 6 A6/1
+* MMCD5 7 A7/1
+* MMCD6 8 A8/1
+* MMCD7 9 A9/1
+
+## SD1
+
+internal, multiplexed with JTAG1
+and UART2, for debug purposes
+
+* SD1_CMD 10 A10/2
+* SD1_CLK 11 A11/2
+* SD1_D0 12 A12/2
+* SD1_D1 13 A13/2
+* SD1_D2 14 A14/2
+* SD1_D3 15 A15/2
+
+## F1:IIS
+
+I2C Audio, connect to AC97 Audio IC
+
+* IISMCK 116 F0/1
+* IISBCK 117 F1/1
+* IISLRCK 118 F2/1
+* IISDI 119 F3/1
+* IISDO0 120 F4/1
+* IISDO1 121 F5/1
+* IISDO2 122 F6/1
+* IISDO3 123 F7/1
+
+## TWI2
+
+Connect to AC97 Audio IC
+
+* TWI2_SDA 85 D17/2
+* TWI2_SCL 86 D18/2
+
+## E2:UART1
+
+Connect to BT on AP6234/AP6335
+
+* UART1_TX 106 E14/2
+* UART1_RX 107 E15/2
+* UART1_CTS 108 E16/2
+* UART1_RTS 109 E17/2
+
+## E2:SD3
+
+Connect to WIFI on AP6234/AP6335
+
+* SD3_CMD 100 E8/2
+* SD3_CLK 101 E9/2
+* SD3_D0 102 E10/2
+* SD3_D1 103 E11/2
+* SD3_D2 104 E12/2
+* SD3_D3 105 E13/2
+
+## D2:TWI3
+
+Connect to PMIC
+
+* TWI3_SDA 87 D19/2
+* TWI3_SCL 88 D20/2
+
+## SPI3
+
+Boot Storage (connection to companion / debug / boot MCU)
+Only actually needs MISO/MOSI, bootstrap loader v. small
+Bootstrap loader checks eMMC, USB-OTG, SD/MMC, SPI, etc.
+MCU implements keyboard-matrix for keyboard (also trackpad?)
+
+* SPI3_CK 110 E18/2
+* SPI3_NSS 111 E19/2
+* SPI3_IO0 112 E20/2
+* SPI3_IO1 113 E21/2
+* SPI3_IO2 114 E22/2
+* SPI3_IO3 115 E23/2
+
+## EINT
+
+* EINT20 89 D21/3 : BT_HOST_WAKE
+* EINT21 90 D22/3 : WIFI_HOST_WAKE
+* EINT9 91 D23/3 : MCU_INT
+* EINT31 125 F9/3 : PMIC_INT
+
+## PWM
+
+* PWM_0 124 F8/2 : LCD Backlight
+
+## Unused Pinouts (spare as GPIO) for 'Laptop / Netbook'
+
+Plenty of spare GPIO pins for miscellaneous functions
+MCU EINT-capable GPIO may be used to generate extra EINTs
+on the single MCU_INT line, if really needed
+
+| Pin | Mux0        | Mux1        | Mux2        | Mux3        |
+| --- | ----------- | ----------- | ----------- | ----------- |
+|  38 | B GPIOB22   | B LCD18_0   | B SD1_CMD   | B FB_AD26   |
+|  39 | B GPIOB23   | B LCD19_0   | B SD1_CLK   | B FB_AD27   |
+|  40 | B GPIOB24   | B LCD20_0   | B SD1_D0    | B FB_AD28   |
+|  41 | B GPIOB25   | B LCD21_0   | B SD1_D1    | B FB_AD29   |
+|  42 | B GPIOB26   | B LCD22_0   | B SD1_D2    | B FB_AD30   |
+|  43 | B GPIOB27   | B LCD23_0   | B SD1_D3    | B FB_AD31   |
+|  52 | C GPIOC8    | C ULPI1_D4  | C SPI2_CLK  | C JTAG2_MS  |
+|  53 | C GPIOC9    | C ULPI1_D5  | C SPI2_NSS  | C JTAG2_DI  |
+|  54 | C GPIOC10   | C ULPI1_D6  | C SPI2_MOSI | C JTAG2_DO  |
+|  55 | C GPIOC11   | C ULPI1_D7  | C SPI2_MISO | C JTAG2_CK  |
+|  64 | C GPIOC20   | C ULPI2_D4  | C IISDO3    | C UART0_TX  |
+|  65 | C GPIOC21   | C ULPI2_D5  | C PWM_2     | C UART0_RX  |
+|  66 | C GPIOC22   | C ULPI2_D6  | C UART2_TX  | C UART0_CTS |
+|  67 | C GPIOC23   | C ULPI2_D7  | C UART2_RX  | C UART0_RTS |
+| 126 | G GPIOG0    | G RG_ERXD0  | G LCDCK_1   | G FB_AD8    |
+| 127 | G GPIOG1    | G RG_ERXD1  | G LCDDE_1   | G FB_AD9    |
+| 128 | G GPIOG2    | G RG_ERXD2  | G LCDHS_1   | G FB_AD10   |
+| 129 | G GPIOG3    | G RG_ETXD0  | G LCDVS_1   | G FB_AD11   |
+| 130 | G GPIOG4    | G RG_ETXD1  | G LCD0_1    | G FB_AD12   |
+| 131 | G GPIOG5    | G RG_ETXD2  | G LCD1_1    | G FB_AD13   |
+| 132 | G GPIOG6    | G RG_FB_CS0 | G LCD2_1    | G FB_AD14   |
+| 133 | G GPIOG7    | G RG_FB_CS1 | G LCD3_1    | G FB_AD15   |
+| 134 | G GPIOG8    | G RG_ERXCK  | G LCD4_1    | G FB_AD16   |
+| 135 | G GPIOG9    | G RG_ERXERR | G LCD5_1    | G FB_AD17   |
+| 136 | G GPIOG10   | G RG_ERXDV  | G LCD6_1    | G FB_AD18   |
+| 137 | G GPIOG11   | G RG_EMDC   | G LCD7_1    | G FB_AD19   |
+| 138 | G GPIOG12   | G RG_EMDIO  | G LCD8_1    | G FB_AD20   |
+| 139 | G GPIOG13   | G RG_ETXEN  | G LCD9_1    | G FB_AD21   |
+| 140 | G GPIOG14   | G RG_ETXCK  | G LCD10_1   | G FB_AD22   |
+| 141 | G GPIOG15   | G RG_ECRS   | G LCD11_1   | G FB_AD23   |
+| 142 | G GPIOG16   | G RG_ECOL   | G LCD12_1   | G FB_AD24   |
+| 143 | G GPIOG17   | G RG_ETXERR | G LCD13_1   | G FB_AD25   |
+| 144 | G GPIOG18   | G ULPI3_CK  | G LCD14_1   | G FB_AD26   |
+| 145 | G GPIOG19   | G ULPI3_DIR | G LCD15_1   | G FB_AD27   |
+| 146 | G GPIOG20   | G ULPI3_STP | G LCD16_1   | G FB_AD28   |
+| 147 | G GPIOG21   | G ULPI3_NXT | G LCD17_1   | G FB_AD29   |
+| 148 | G GPIOG22   | G ULPI3_D0  | G LCD18_1   | G FB_AD30   |
+| 149 | G GPIOG23   | G ULPI3_D1  | G LCD19_1   | G FB_AD31   |
+| 150 | G GPIOG24   | G ULPI3_D2  | G LCD20_1   | G SD2_CMD   |
+| 151 | G GPIOG25   | G ULPI3_D3  | G LCD21_1   | G SD2_CLK   |
+| 152 | G GPIOG26   | G ULPI3_D4  | G LCD22_1   | G SPI3_CK   |
+| 153 | G GPIOG27   | G ULPI3_D5  | G LCD23_1   | G SPI3_NSS  |
+| 154 | G GPIOG28   | G ULPI3_D6  | G SD2_D0    | G SPI3_IO0  |
+| 155 | G GPIOG29   | G ULPI3_D7  | G SD2_D1    | G SPI3_IO1  |
+| 156 | G GPIOG30   |             | G SD2_D2    | G SPI3_IO2  |
+| 157 | G GPIOG31   |             | G SD2_D3    | G SPI3_IO3  |
+
+# Pinmap for IoT
+
+## B1:LCD
+
+RGB/TTL LCD, use SN75LVDS83b for LVDS or SSD2828 for MIPI,
+or a Chrontel CH7039, CH7038, CH7034 or CH7018 for dual
+display output (eDP/LVDS and HDMI/VGA) conversion.
+
+* LCDCK_0 16 B0/1
+* LCDDE_0 17 B1/1
+* LCDHS_0 18 B2/1
+* LCDVS_0 19 B3/1
+* LCD0_0 20 B4/1
+* LCD1_0 21 B5/1
+* LCD2_0 22 B6/1
+* LCD3_0 23 B7/1
+* LCD4_0 24 B8/1
+* LCD5_0 25 B9/1
+* LCD6_0 26 B10/1
+* LCD7_0 27 B11/1
+* LCD8_0 28 B12/1
+* LCD9_0 29 B13/1
+* LCD10_0 30 B14/1
+* LCD11_0 31 B15/1
+* LCD12_0 32 B16/1
+* LCD13_0 33 B17/1
+* LCD14_0 34 B18/1
+* LCD15_0 35 B19/1
+* LCD16_0 36 B20/1
+* LCD17_0 37 B21/1
+* LCD18_0 38 B22/1
+* LCD19_0 39 B23/1
+* LCD20_0 40 B24/1
+* LCD21_0 41 B25/1
+* LCD22_0 42 B26/1
+* LCD23_0 43 B27/1
+
+## ULPI2/8
+
+USB-OTG, connect to ULPI OTG PHY (for charging)
+as well as USB Host or USB Device
+
+* ULPI2_CK 56 C12/1
+* ULPI2_DIR 57 C13/1
+* ULPI2_STP 58 C14/1
+* ULPI2_NXT 59 C15/1
+* ULPI2_D0 60 C16/1
+* ULPI2_D1 61 C17/1
+* ULPI2_D2 62 C18/1
+* ULPI2_D3 63 C19/1
+
+## ULPI1/8
+
+USB2 Host, connect to ULPI PHY
+
+* ULPI1_CK 44 C0/1
+* ULPI1_DIR 45 C1/1
+* ULPI1_STP 46 C2/1
+* ULPI1_NXT 47 C3/1
+* ULPI1_D0 48 C4/1
+* ULPI1_D1 49 C5/1
+* ULPI1_D2 50 C6/1
+* ULPI1_D3 51 C7/1
+
+## MMC
+
+eMMC: main internal storage
+
+* MMCCMD 0 A0/1
+* MMCCLK 1 A1/1
+* MMCD0 2 A2/1
+* MMCD1 3 A3/1
+* MMCD2 4 A4/1
+* MMCD3 5 A5/1
+* MMCD4 6 A6/1
+* MMCD5 7 A7/1
+* MMCD6 8 A8/1
+* MMCD7 9 A9/1
+
+## SD1
+
+internal, multiplexed with JTAG1
+and UART2, for debug purposes
+
+* SD1_CMD 10 A10/2
+* SD1_CLK 11 A11/2
+* SD1_D0 12 A12/2
+* SD1_D1 13 A13/2
+* SD1_D2 14 A14/2
+* SD1_D3 15 A15/2
+
+## F1:IIS
+
+I2C Audio, connect to AC97 Audio IC
+
+* IISMCK 116 F0/1
+* IISBCK 117 F1/1
+* IISLRCK 118 F2/1
+* IISDI 119 F3/1
+* IISDO0 120 F4/1
+* IISDO1 121 F5/1
+* IISDO2 122 F6/1
+* IISDO3 123 F7/1
+
+## C3:UART0
+
+Connect to HSPA UART
+
+* UART0_TX 64 C20/3
+* UART0_RX 65 C21/3
+* UART0_CTS 66 C22/3
+* UART0_RTS 67 C23/3
+
+## E2:UART1
+
+Connect to BT UART
+
+* UART1_TX 106 E14/2
+* UART1_RX 107 E15/2
+* UART1_CTS 108 E16/2
+* UART1_RTS 109 E17/2
+
+## C2:SPI2
+
+HSPA SPI
+
+* SPI2_CLK 52 C8/2
+* SPI2_NSS 53 C9/2
+* SPI2_MOSI 54 C10/2
+* SPI2_MISO 55 C11/2
+
+## E2:SD3
+
+Connect to WIFI
+
+* SD3_CMD 100 E8/2
+* SD3_CLK 101 E9/2
+* SD3_D0 102 E10/2
+* SD3_D1 103 E11/2
+* SD3_D2 104 E12/2
+* SD3_D3 105 E13/2
+
+## D3:TWI1
+
+Connect to sensors CTP
+
+* TWI1_SDA 78 D10/3
+* TWI1_SCL 79 D11/3
+
+## D2:TWI3
+
+Connect to PMIC
+
+* TWI3_SDA 87 D19/2
+* TWI3_SCL 88 D20/2
+
+## SPI3
+
+Boot Storage (connection to companion / debug / boot MCU)
+Only actually needs MISO/MOSI, bootstrap loader v. small
+Bootstrap loader checks eMMC, USB-OTG, SD/MMC, SPI, etc.
+MCU implements keyboard-matrix for keyboard (also trackpad?)
+
+* SPI3_CK 110 E18/2
+* SPI3_NSS 111 E19/2
+* SPI3_IO0 112 E20/2
+* SPI3_IO1 113 E21/2
+* SPI3_IO2 114 E22/2
+* SPI3_IO3 115 E23/2
+
+## GPIO
+
+* GPIOD12  80 D12 : LCD_RDN
+* GPIOD17  85 D17 : LCD_WRN
+* GPIOD18  86 D18 : LCD_RS
+* GPIOD2   70 D2  : HSPA_SHUTDOWN
+* GPIOD21  89 D21 : LCD_CSN
+* GPIOD3   71 D3  : CTP_RST
+* GPIOD4   72 D4  : WL_WAKE_AP
+* GPIOD5   73 D5  : BT_WAKE_AP
+* GPIOD6   74 D6  : AP_WAKE_BT
+* GPIOD7   75 D7  : AP_CK32KO
+* GPIOD8   76 D8  : HSPA_PWRON
+* GPIOD9   77 D9  : BT_RST_N
+* GPIOE5   97 E5  : HSPA_ON_OFF
+
+## EINT
+
+* EINT5 81 D13/3 : HSPA_MST_RDY
+* EINT6 82 D14/3 : HSPA_SL_RDY
+* EINT7 83 D15/3 : HSPA_RING
+* EINT8 84 D16/3 : WL_PMU_EN
+* EINT9 91 D23/3 : HSPA_GPIO1
+* EINT10 92 E0/3 : IR_DT
+* EINT11 93 E1/3 : BT_PCM_CLK
+* EINT12 94 E2/3 : BT_PCM_DIN
+* EINT13 95 E3/3 : BT_PCM_SYNC
+* EINT14 96 E4/3 : BT_PCM_DOUT
+* EINT16 98 E6/3 : USB_DRVVBUS
+* EINT17 99 E7/3 : USB_VBUSDET
+* EINT21 90 D22/3 : USB_ID
+* EINT30 68 D0/3 : CTP_INT
+* EINT31 69 D1/3 : SD_DETN
+
+## PWM
+
+* PWM_0 124 F8/2 : LCD Backlight
+
+## Unused Pinouts (spare as GPIO) for 'IoT'
+
+Plenty of spare GPIO pins for miscellaneous functions
+MCU EINT-capable GPIO may be used to generate extra EINTs
+on the single MCU_INT line, if really needed
+
+| Pin | Mux0        | Mux1        | Mux2        | Mux3        |
+| --- | ----------- | ----------- | ----------- | ----------- |
+| 125 | F GPIOF9    | F UART4_RX  | F PWM_1     | F EINT31    |
+| 126 | G GPIOG0    | G RG_ERXD0  | G LCDCK_1   | G FB_AD8    |
+| 127 | G GPIOG1    | G RG_ERXD1  | G LCDDE_1   | G FB_AD9    |
+| 128 | G GPIOG2    | G RG_ERXD2  | G LCDHS_1   | G FB_AD10   |
+| 129 | G GPIOG3    | G RG_ETXD0  | G LCDVS_1   | G FB_AD11   |
+| 130 | G GPIOG4    | G RG_ETXD1  | G LCD0_1    | G FB_AD12   |
+| 131 | G GPIOG5    | G RG_ETXD2  | G LCD1_1    | G FB_AD13   |
+| 132 | G GPIOG6    | G RG_FB_CS0 | G LCD2_1    | G FB_AD14   |
+| 133 | G GPIOG7    | G RG_FB_CS1 | G LCD3_1    | G FB_AD15   |
+| 134 | G GPIOG8    | G RG_ERXCK  | G LCD4_1    | G FB_AD16   |
+| 135 | G GPIOG9    | G RG_ERXERR | G LCD5_1    | G FB_AD17   |
+| 136 | G GPIOG10   | G RG_ERXDV  | G LCD6_1    | G FB_AD18   |
+| 137 | G GPIOG11   | G RG_EMDC   | G LCD7_1    | G FB_AD19   |
+| 138 | G GPIOG12   | G RG_EMDIO  | G LCD8_1    | G FB_AD20   |
+| 139 | G GPIOG13   | G RG_ETXEN  | G LCD9_1    | G FB_AD21   |
+| 140 | G GPIOG14   | G RG_ETXCK  | G LCD10_1   | G FB_AD22   |
+| 141 | G GPIOG15   | G RG_ECRS   | G LCD11_1   | G FB_AD23   |
+| 142 | G GPIOG16   | G RG_ECOL   | G LCD12_1   | G FB_AD24   |
+| 143 | G GPIOG17   | G RG_ETXERR | G LCD13_1   | G FB_AD25   |
+| 144 | G GPIOG18   | G ULPI3_CK  | G LCD14_1   | G FB_AD26   |
+| 145 | G GPIOG19   | G ULPI3_DIR | G LCD15_1   | G FB_AD27   |
+| 146 | G GPIOG20   | G ULPI3_STP | G LCD16_1   | G FB_AD28   |
+| 147 | G GPIOG21   | G ULPI3_NXT | G LCD17_1   | G FB_AD29   |
+| 148 | G GPIOG22   | G ULPI3_D0  | G LCD18_1   | G FB_AD30   |
+| 149 | G GPIOG23   | G ULPI3_D1  | G LCD19_1   | G FB_AD31   |
+| 150 | G GPIOG24   | G ULPI3_D2  | G LCD20_1   | G SD2_CMD   |
+| 151 | G GPIOG25   | G ULPI3_D3  | G LCD21_1   | G SD2_CLK   |
+| 152 | G GPIOG26   | G ULPI3_D4  | G LCD22_1   | G SPI3_CK   |
+| 153 | G GPIOG27   | G ULPI3_D5  | G LCD23_1   | G SPI3_NSS  |
+| 154 | G GPIOG28   | G ULPI3_D6  | G SD2_D0    | G SPI3_IO0  |
+| 155 | G GPIOG29   | G ULPI3_D7  | G SD2_D1    | G SPI3_IO1  |
+| 156 | G GPIOG30   |             | G SD2_D2    | G SPI3_IO2  |
+| 157 | G GPIOG31   |             | G SD2_D3    | G SPI3_IO3  |
+
+# Reference Datasheets
+
+datasheets and pinout links
+
+* <http://datasheets.chipdb.org/AMD/8018x/80186/amd-80186.pdf>
+* <http://hands.com/~lkcl/eoma/shenzen/frida/FRD144A2701.pdf>
+* <http://pinouts.ru/Memory/sdcard_pinout.shtml>
+* p8 <http://www.onfi.org/~/media/onfi/specs/onfi_2_0_gold.pdf?la=en>
+* <https://www.heyrick.co.uk/blog/files/datasheets/dm9000aep.pdf>
+* <http://cache.freescale.com/files/microcontrollers/doc/app_note/AN4393.pdf>
+* <https://www.nxp.com/docs/en/data-sheet/MCF54418.pdf>
+* ULPI OTG PHY, ST <http://www.st.com/en/interfaces-and-transceivers/stulpi01a.html>
+* ULPI OTG PHY, TI TUSB1210 <http://ti.com/product/TUSB1210/>
diff --git a/shakti/m_class/pinouts.py b/shakti/m_class/pinouts.py
new file mode 100644 (file)
index 0000000..996f935
--- /dev/null
@@ -0,0 +1,1000 @@
+#!/usr/bin/env python
+
+from copy import deepcopy
+
+def pins(pingroup, bankspec, suffix, offs, bank, mux, spec=None, limit=None):
+    res = {}
+    names = {}
+    idx = 0
+    for name in pingroup[:limit]:
+        if suffix:
+            name_ = "%s_%s" % (name, suffix)
+        else:
+            name_ = name
+        if spec and spec.has_key(name):
+            continue
+        pin = {mux: (name_, bank)}
+        offs_bank, offs_ = offs
+        idx_ = offs_ + idx
+        idx += 1
+        idx_ += bankspec[bank]
+        res[idx_] = pin
+        names[name] = idx_
+    for name in pingroup:
+        if suffix:
+            name_ = "%s_%s" % (name, suffix)
+        else:
+            name_ = name
+        if not spec:
+            continue
+        if not spec.has_key(name):
+            continue
+        idx_, mux_, bank_ = spec[name]
+        idx_ = names[idx_]
+        #idx_ += bankspec[bank_]
+        pin = {mux_: (name_, bank_)}
+        if res.has_key(idx_):
+            res[idx_].update(pin)
+        else:
+            res[idx_] = pin
+    return res
+
+def i2s(bankspec, suffix, offs, bank, mux=1, spec=None, limit=None):
+    i2spins = ['IISMCK', 'IISBCK', 'IISLRCK', 'IISDI']
+    for i in range(4):
+        i2spins.append("IISDO%d" % i)
+    return pins(i2spins, bankspec, suffix, offs, bank, mux, spec, limit)
+
+def emmc(bankspec, suffix, offs, bank, mux=1, spec=None):
+    emmcpins = ['MMCCMD', 'MMCCLK']
+    for i in range(8):
+        emmcpins.append("MMCD%d" % i)
+    return pins(emmcpins, bankspec, suffix, offs, bank, mux, spec)
+
+def sdmmc(bankspec, suffix, offs, bank, mux=1, spec=None,
+                start=None, limit=None):
+    sdmmcpins = ['CMD', 'CLK']
+    for i in range(4):
+        sdmmcpins.append("D%d" % i)
+    print sdmmcpins, start, limit
+    sdmmcpins = sdmmcpins[start:limit]
+    sdmmcpins = namesuffix('SD', suffix, sdmmcpins)
+    return pins(sdmmcpins, bankspec, '', offs, bank, mux, spec)
+
+def spi(bankspec, suffix, offs, bank, mux=1, spec=None):
+    spipins = namesuffix('SPI', suffix,
+                ['CLK', 'NSS', 'MOSI', 'MISO', 'NSS'])
+    return pins(spipins, bankspec, '', offs, bank, mux, spec)
+
+def quadspi(bankspec, suffix, offs, bank, mux=1, spec=None, limit=None):
+    spipins = namesuffix('SPI', suffix,
+                ['CK', 'NSS', 'IO0', 'IO1', 'IO2', 'IO3'])
+    return pins(spipins, bankspec, '', offs, bank, mux, spec, limit)
+
+def i2c(bankspec, suffix, offs, bank, mux=1, spec=None):
+    spipins = namesuffix('TWI', suffix,
+                ['SDA', 'SCL'])
+    return pins(spipins, bankspec, '', offs, bank, mux, spec)
+
+def jtag(bankspec, suffix, offs, bank, mux=1, spec=None):
+    uartpins = namesuffix('JTAG', suffix, ['MS', 'DI', 'DO', 'CK'])
+    return pins(uartpins, bankspec, '', offs, bank, mux, spec)
+
+def uart(bankspec, suffix, offs, bank, mux=1, spec=None):
+    uartpins = namesuffix('UART', suffix, ['TX', 'RX'])
+    return pins(uartpins, bankspec, '', offs, bank, mux, spec)
+
+def namesuffix(name, suffix, namelist):
+    names = []
+    for n in namelist:
+        names.append("%s%s_%s" % (name, suffix, n))
+    return names
+
+def ulpi(bankspec, suffix, offs, bank, mux=1, spec=None):
+    ulpipins = namesuffix('ULPI', suffix, ['CK', 'DIR', 'STP', 'NXT'])
+    for i in range(8):
+        ulpipins.append('ULPI%s_D%d' % (suffix, i))
+    return pins(ulpipins, bankspec, "", offs, bank, mux, spec)
+
+def uartfull(bankspec, suffix, offs, bank, mux=1, spec=None):
+    uartpins = namesuffix('UART', suffix, ['TX', 'RX', 'CTS', 'RTS'])
+    return pins(uartpins, bankspec, '', offs, bank, mux, spec)
+
+def rgbttl(bankspec, suffix, offs, bank, mux=1, spec=None):
+    ttlpins = ['LCDCK', 'LCDDE', 'LCDHS', 'LCDVS']
+    for i in range(24):
+        ttlpins.append("LCD%d" % i)
+    return pins(ttlpins, bankspec, suffix, offs, bank, mux, spec)
+
+def rgmii(bankspec, suffix, offs, bank, mux=1, spec=None):
+    buspins = []
+    for i in range(3):
+        buspins.append("RG_ERXD%d" % i)
+    for i in range(3):
+        buspins.append("RG_ETXD%d" % i)
+    for i in range(2):
+        buspins.append("RG_FB_CS%d" % i)
+    buspins += ['RG_ERXCK', 'RG_ERXERR', 'RG_ERXDV',
+                'RG_EMDC', 'RG_EMDIO',
+                'RG_ETXEN', 'RG_ETXCK', 'RG_ECRS',
+                'RG_ECOL', 'RG_ETXERR']
+    return pins(buspins, bankspec, suffix, offs, bank, mux, spec)
+
+def flexbus1(bankspec, suffix, offs, bank, mux=1, spec=None):
+    buspins = []
+    for i in range(8):
+        buspins.append("FB_AD%d" % i)
+    for i in range(2):
+        buspins.append("FB_CS%d" % i)
+    buspins += ['FB_ALE', 'FB_OE', 'FB_RW', 'FB_TA', 'FB_CLK',
+                'FB_A0', 'FB_A1', 'FB_TS', 'FB_TBST',
+                'FB_TSIZ0', 'FB_TSIZ1']
+    for i in range(4):
+        buspins.append("FB_BWE%d" % i)
+    for i in range(2,6):
+        buspins.append("FB_CS%d" % i)
+    return pins(buspins, bankspec, suffix, offs, bank, mux, spec)
+
+def flexbus2(bankspec, suffix, offs, bank, mux=1, spec=None):
+    buspins = []
+    for i in range(8,32):
+        buspins.append("FB_AD%d" % i)
+    return pins(buspins, bankspec, suffix, offs, bank, mux, spec)
+
+def mcu8080(bankspec, suffix, offs, bank, mux=1, spec=None):
+    buspins = []
+    for i in range(8):
+        buspins.append("MCUD%d" % i)
+    for i in range(8):
+        buspins.append("MCUAD%d" % (i+8))
+    for i in range(6):
+        buspins.append("MCUCS%d" % i)
+    for i in range(2):
+        buspins.append("MCUNRB%d" % i)
+    buspins += ['MCUCD', 'MCURD', 'MCUWR', 'MCUCLE', 'MCUALE',
+                'MCURST']
+    return pins(buspins, bankspec, suffix, offs, bank, mux, spec)
+
+def _pinbank(bankspec, prefix, suffix, offs, bank, gpiooffs, gpionum=1, mux=1, spec=None):
+    gpiopins = []
+    for i in range(gpiooffs, gpiooffs+gpionum):
+        gpiopins.append("%s%s%d" % (prefix, bank, i))
+    return pins(gpiopins, bankspec, suffix, offs, bank, mux, spec)
+
+def eint(bankspec, suffix, offs, bank, gpiooffs, gpionum=1, mux=1, spec=None):
+    gpiopins = []
+    for i in range(gpiooffs, gpiooffs+gpionum):
+        gpiopins.append("EINT%d" % (i))
+    return pins(gpiopins, bankspec, suffix, offs, bank, mux, spec)
+
+def pwm(bankspec, suffix, offs, bank, mux=1, spec=None):
+    return pins(['PWM', ], bankspec, suffix, offs, bank, mux, spec)
+
+def gpio(bankspec, suffix, offs, bank, gpiooffs, gpionum=1, mux=1, spec=None):
+    return _pinbank(bankspec, "GPIO", suffix, offs, bank, gpiooffs,
+                              gpionum, mux=0, spec=None)
+
+def display(pins):
+    print "| Pin | Mux0        | Mux1        | Mux2        | Mux3        |"
+    print "| --- | ----------- | ----------- | ----------- | ----------- |"
+    pinidx = pins.keys()
+    pinidx.sort()
+    for pin in pinidx:
+        pdata = pins[pin]
+        res = '| %3d |' % pin
+        for mux in range(4):
+            if not pdata.has_key(mux):
+                res += "             |"
+                continue
+            name, bank = pdata[mux]
+            res += " %s %-9s |" % (bank, name)
+        print res
+
+def fnsplit(f):
+    a = ''
+    n = 0
+    if not f.startswith('FB_'):
+        f2 = f.split('_')
+        if len(f2) == 2:
+            if f2[1].isdigit():
+                return f2[0], int(f2[1])
+            return f2[0], f2[1]
+    #print f
+    while f and not f[0].isdigit():
+        a += f[0]
+        f = f[1:]
+    return a, int(f) if f else None
+
+def fnsort(f1, f2):
+    a1, n1 = fnsplit(f1)
+    a2, n2 = fnsplit(f2)
+    x = cmp(a1, a2)
+    if x != 0:
+        return x
+    return cmp(n1, n2)
+    
+def find_fn(fname, names):
+    for n in names:
+        if fname.startswith(n):
+            return n
+
+def display_fns(bankspec, pins, function_names):
+    fn_names = function_names.keys()
+    fns = {}
+    for (pin, pdata) in pins.items():
+        for mux in range(1,4): # skip GPIO for now
+            if not pdata.has_key(mux):
+                continue
+            name, bank = pdata[mux]
+            if not fns.has_key(name):
+                fns[name] = []
+            fns[name].append((pin-bankspec[bank], mux, bank))
+
+    fnidx = fns.keys()
+    fnidx.sort(fnsort)
+    current_fn = None
+    for fname in fnidx:
+        fnbase = find_fn(fname, fn_names)
+        if fnbase != current_fn:
+            if current_fn is not None:
+                print
+            print "## %s" % fnbase
+            print
+            print function_names[fnbase]
+            print
+            current_fn = fnbase
+        print "* %-9s :" % fname,
+        for (pin, mux, bank) in fns[fname]:
+            print "%s%d/%d" % (bank, pin, mux),
+        print
+
+    return fns
+
+def check_functions(title, bankspec, fns, pins, required, eint, pwm,
+                    descriptions=None):
+    fns = deepcopy(fns)
+    pins = deepcopy(pins)
+    if descriptions is None:
+        descriptions = {}
+
+    print "# Pinmap for %s" % title
+    print
+
+
+    for name in required:
+        print "## %s" % name
+        print
+        if descriptions and descriptions.has_key(name):
+            print descriptions[name]
+            print
+
+        name = name.split(':')
+        if len(name) == 2:
+            findbank = name[0][0]
+            findmux = int(name[0][1:])
+            name = name[1]
+        else:
+            name = name[0]
+            findbank = None
+            findmux = None
+        name = name.split('/')
+        if len(name) == 2:
+            count = int(name[1])
+        else:
+            count = 100000
+        name = name[0]
+        found = set()
+        fnidx = fns.keys()
+        #fnidx.sort(fnsort)
+        pinfound = {}
+        for fname in fnidx:
+            if not fname.startswith(name):
+                continue
+            for pin, mux, bank in fns[fname]:
+                if findbank is not None:
+                    if findbank != bank:
+                        continue
+                    if findmux != mux:
+                        continue
+                pin_ = pin + bankspec[bank]
+                if pins.has_key(pin_):
+                    pinfound[pin_] = (fname, pin_, bank, pin, mux)
+
+        pinidx = pinfound.keys()
+        pinidx.sort()
+
+        for pin_ in pinidx:
+            fname, pin_, bank, pin, mux = pinfound[pin_]
+            if fname in found:
+                continue
+            found.add(fname)
+            if len(found) > count:
+                continue
+            del pins[pin_]
+            print "* %s %d %s%d/%d" % (fname, pin_, bank, pin, mux)
+
+        print
+
+    # gpios
+    gpios = []
+    for name in descriptions.keys():
+        if not name.startswith('GPIO'):
+            continue
+        if name == 'GPIO':
+            continue
+        gpios.append(name)
+    gpios.sort()
+    
+    if gpios:
+        print "## GPIO"
+        print
+
+        for fname in gpios:
+            if fname in found:
+                continue
+            desc = ''
+            if descriptions and descriptions.has_key(fname):
+                desc = ': %s' % descriptions[fname]
+            bank = fname[4]
+            pin = int(fname[5:])
+            pin_ = pin + bankspec[bank]
+            if not pins.has_key(pin_):
+                continue
+            del pins[pin_]
+            found.add(fname)
+            print "* %-8s %d %s%-2d %s" % (fname, pin_, bank, pin, desc)
+        print
+
+    if eint:
+        display_group("EINT", eint, fns, pins, descriptions)
+    if pwm:
+        display_group("PWM", pwm, fns, pins, descriptions)
+
+    print "## Unused Pinouts (spare as GPIO) for '%s'" % title
+    print
+    if descriptions and descriptions.has_key('GPIO'):
+        print descriptions['GPIO']
+        print 
+    display(pins)
+    print
+
+    return pins # unused
+
+def display_group(title, todisplay, fns, pins, descriptions):
+    print "## %s" % title
+    print
+
+    found = set()
+    for fname in todisplay:
+        desc = ''
+        if descriptions and descriptions.has_key(fname):
+            desc = ': %s' % descriptions[fname]
+        fname = fname.split(':')
+        if len(fname) == 2:
+            findbank = fname[0][0]
+            findmux = int(fname[0][1:])
+            fname = fname[1]
+        else:
+            fname = fname[0]
+            findbank = None
+            findmux = None
+        for (pin, mux, bank) in fns[fname]:
+            if findbank is not None:
+                if findbank != bank:
+                    continue
+                if findmux != mux:
+                    continue
+            if fname in found:
+                continue
+            pin_ = pin + bankspec[bank]
+            if not pins.has_key(pin_):
+                continue
+            del pins[pin_]
+            found.add(fname)
+            print "* %s %d %s%d/%d %s" % (fname, pin_, bank, pin, mux, desc)
+    print
+
+def pinmerge(pins, fn):
+    for (pinidx, v) in fn.items():
+        if not pins.has_key(pinidx):
+            pins[pinidx] = v
+            continue
+        pins[pinidx].update(v)
+
+def display_fixed(fixed, offs):
+
+    fkeys = fixed.keys()
+    fkeys.sort()
+    pin_ = offs
+    for pin, k in enumerate(fkeys):
+        print "## %s" % k
+        print
+        prevname = ''
+        linecount = 0
+        for name in fixed[k]:
+            if linecount == 4:
+                linecount = 0
+                print
+            if prevname[:2] == name[:2] and linecount != 0:
+                print name,
+                linecount += 1
+            else:
+                if linecount != 0:
+                    print
+                print "* %d: %d %s" % (pin_, pin, name),
+                linecount = 1
+            prevname = name
+            pin_ += 1
+        if linecount != 0:
+            print
+        print
+
+if __name__ == '__main__':
+    pinouts = {}
+
+    pinbanks = {'A': 16,
+                'B': 28,
+                'C': 24,
+                'D': 24,
+                'E': 24,
+                'F': 10,
+                'G': 32,
+              }
+    bankspec = {}
+    pkeys = pinbanks.keys()
+    pkeys.sort()
+    offs = 0
+    for kn in pkeys:
+        bankspec[kn] = offs
+        offs += pinbanks[kn]
+
+    # Bank A, 0-15
+    pinmerge(pinouts, gpio(bankspec, "", ('A', 0), "A", 0, 16, 0))
+    pinmerge(pinouts, spi(bankspec, "1", ('A', 0), "A", 3))
+    pinmerge(pinouts, uartfull(bankspec, "1", ('A', 0), "A", 2))
+    pinmerge(pinouts, i2c(bankspec, "1", ('A', 4), "A", 2))
+    pinmerge(pinouts, emmc(bankspec, "", ('A', 0), "A", 1))
+    #pinmerge(pinouts, uart(bankspec, "2", ('A', 14), "A", 1))
+    pinmerge(pinouts, spi(bankspec, "2", ('A', 6), "A", 2))
+    pinmerge(pinouts, eint(bankspec, "", ('A', 10), "A", 0, 6))
+    pinmerge(pinouts, eint(bankspec, "", ('A', 4), "A", 0, 6, mux=3))
+    pinmerge(pinouts, sdmmc(bankspec, "1", ('A', 10), "A", 2))
+    pinmerge(pinouts, jtag(bankspec, "1", ('A', 10), "A", 3))
+    pinmerge(pinouts, uart(bankspec, "2", ('A', 14), "A", 3))
+
+    # Bank B, 16-47
+    pinmerge(pinouts, gpio(bankspec, "", ('B', 0), "B", 0, 28, 0))
+    pinmerge(pinouts, rgbttl(bankspec, "0", ('B', 0), "B", 1))
+    pinmerge(pinouts, spi(bankspec, "1", ('B', 12), "B", 2))
+    pinmerge(pinouts, quadspi(bankspec, "3", ('B', 4), "B", 2, limit=4))
+    pinmerge(pinouts, uart(bankspec, "3", ('B', 16), "B", 2))
+    pinmerge(pinouts, i2c(bankspec, "3", ('B', 18), "B", 2))
+    pinmerge(pinouts, pwm(bankspec, "0", ('B', 9), "B", mux=2))
+    pinmerge(pinouts, pwm(bankspec, "1", ('B', 20), "B", mux=2))
+    pinmerge(pinouts, pwm(bankspec, "2", ('B', 21), "B", mux=2))
+    pinmerge(pinouts, sdmmc(bankspec, "1", ('B', 22), "B", 2))
+    pinmerge(pinouts, eint(bankspec, "", ('B', 0), "B", 6, 4, mux=3))
+    pinmerge(pinouts, flexbus2(bankspec, "", ('B', 4), "B", 3))
+    pinmerge(pinouts, i2c(bankspec, "1", ('B', 0), "B", 2))
+    pinmerge(pinouts, uart(bankspec, "2", ('B', 2), "B", 2))
+    pinmerge(pinouts, uart(bankspec, "4", ('B', 10), "B", 2))
+
+    # Bank C, 48-71
+    pinmerge(pinouts, gpio(bankspec, "", ("C", 0), "C", 0, 24, 0))
+    pinmerge(pinouts, ulpi(bankspec, "1", ('C', 0), "C", 1))
+    pinmerge(pinouts, ulpi(bankspec, "2", ('C', 12), "C", 1))
+    pinmerge(pinouts, spi(bankspec, "2", ('C', 8), "C", 2))
+    #pinmerge(pinouts, spi(bankspec, "2", ('C', 28), "C", 2))
+    pinmerge(pinouts, uartfull(bankspec, "0", ('C', 20), "C", 3))
+    pinmerge(pinouts, eint(bankspec, "", ('C', 0), "C", 10, 8, mux=3))
+    pinmerge(pinouts, jtag(bankspec, "2", ('C', 8), "C", 3))
+    pinmerge(pinouts, eint(bankspec, "", ('C', 12), "C", 22, 8, mux=3))
+    pinmerge(pinouts, uart(bankspec, "2", ('C', 22), "C", 2))
+    pinmerge(pinouts, i2s(bankspec, "", ('C', 13), "C", 2))
+    pinmerge(pinouts, pwm(bankspec, "2", ('C', 21), "C", mux=2))
+
+    # Bank D, 72-96
+    flexspec = {
+        'FB_TS': ('FB_ALE', 2, "D"),
+        'FB_CS2': ('FB_BWE2', 2, "D"),
+        'FB_A0': ('FB_BWE2', 3, "D"),
+        'FB_CS3': ('FB_BWE3', 2, "D"),
+        'FB_A1': ('FB_BWE3', 3, "D"),
+        'FB_TBST': ('FB_OE', 2, "D"),
+        'FB_TSIZ0': ('FB_BWE0', 2, "D"),
+        'FB_TSIZ1': ('FB_BWE1', 2, "D"),
+    }
+    #pinmerge(pinouts, mcu8080("", 72, "D", 1))
+    pinmerge(pinouts, gpio(bankspec, "", ('D', 0), "D", 0, 24, 0))
+    pinmerge(pinouts, flexbus1(bankspec, "", ('D', 0), "D", 1, spec=flexspec))
+    pinmerge(pinouts, i2c(bankspec, "2", ('D', 17), "D", 2))
+    pinmerge(pinouts, pwm(bankspec, "0", ('D', 21), "D", mux=1))
+    pinmerge(pinouts, pwm(bankspec, "1", ('D', 22), "D", mux=1))
+    pinmerge(pinouts, pwm(bankspec, "2", ('D', 23), "D", mux=1))
+    pinmerge(pinouts, i2c(bankspec, "1", ('D', 10), "D", 3))
+    pinmerge(pinouts, i2c(bankspec, "3", ('D', 19), "D", 2))
+    pinmerge(pinouts, uartfull(bankspec, "0", ('D', 0), "D", 2))
+    pinmerge(pinouts, uart(bankspec, "3", ('D', 21), "D", 2))
+    pinmerge(pinouts, uart(bankspec, "4", ('D', 13), "D", 2))
+    pinmerge(pinouts, eint(bankspec, "", ('D', 19), "D", 18, 4, mux=3))
+    pinmerge(pinouts, eint(bankspec, "", ('D', 23), "D", 9, 1, mux=3))
+    pinmerge(pinouts, eint(bankspec, "", ('D', 13), "D", 5, 4, mux=3))
+    pinmerge(pinouts, eint(bankspec, "", ('D', 0), "D", 30, 2, mux=3))
+    pinmerge(pinouts, i2c(bankspec, "2", ('D', 2), "D", 3))
+    pinmerge(pinouts, sdmmc(bankspec, "2", ('D', 4), "D", 2))
+
+    # Bank E
+    pinmerge(pinouts, gpio(bankspec, "", ('E', 0), "E", 0, 24, 0))
+    pinmerge(pinouts, flexbus2(bankspec, "", ('E', 0), "E", 1))
+    pinmerge(pinouts, sdmmc(bankspec, "2", ('E', 0), "E", 2))
+    pinmerge(pinouts, sdmmc(bankspec, "3", ('E', 8), "E", 2))
+    pinmerge(pinouts, quadspi(bankspec, "3", ('E', 18), "E", 2))
+    pinmerge(pinouts, uartfull(bankspec, "1", ('E', 14), "E", 2))
+    pinmerge(pinouts, i2c(bankspec, "2", ('E', 6), "E", 2))
+    pinmerge(pinouts, eint(bankspec, "", ('E', 0), "E", 10, 8, mux=3))
+    pinmerge(pinouts, eint(bankspec, "", ('E', 8), "E", 22, 6, mux=3))
+    pinmerge(pinouts, emmc(bankspec, "", ('E', 14), "E", 3))
+
+    # Bank F
+    pinmerge(pinouts, gpio(bankspec, "", ('F', 0), "F", 0, 10, 0))
+    pinmerge(pinouts, i2s(bankspec, "", ('F', 0), "F", 1))
+    pinmerge(pinouts, i2c(bankspec, "1", ('F', 6), "F", 2))
+    pinmerge(pinouts, pwm(bankspec, "0", ('F', 8), "F", mux=2))
+    pinmerge(pinouts, pwm(bankspec, "1", ('F', 9), "F", mux=2))
+    pinmerge(pinouts, uart(bankspec, "4", ('F', 8), "F", 1))
+    pinmerge(pinouts, sdmmc(bankspec, "3", ('F', 0), "F", 2))
+    pinmerge(pinouts, eint(bankspec, "", ('F', 0), "F", 18, 4, mux=3))
+    pinmerge(pinouts, pwm(bankspec, "2", ('F', 4), "F", mux=3))
+    pinmerge(pinouts, eint(bankspec, "", ('F', 5), "F", 7, 1, mux=3))
+    pinmerge(pinouts, eint(bankspec, "", ('F', 6), "F", 28, 4, mux=3))
+
+    # Bank G
+    pinmerge(pinouts, gpio(bankspec, "", ('G', 0), "G", 0, 32, 0))
+    pinmerge(pinouts, rgmii(bankspec, "", ('G', 0), "G", 1))
+    pinmerge(pinouts, ulpi(bankspec, "3", ('G', 18), "G", 1))
+    pinmerge(pinouts, rgbttl(bankspec, "1", ('G', 0), "G", 2))
+    pinmerge(pinouts, quadspi(bankspec, "3", ('G', 26), "G", 3))
+    pinmerge(pinouts, flexbus2(bankspec, "", ('G', 0), "G", 3))
+    mmc2 = sdmmc(bankspec, "2", ('G', 24), "G", 3, limit=2)
+    pinmerge(pinouts, mmc2)
+    mmc2 = sdmmc(bankspec, "2", ('G', 28), "G", 2, start=2)
+    pinmerge(pinouts, mmc2)
+
+    print "# Pinouts (PinMux)"
+    print
+    print "auto-generated by [[pinouts.py]]"
+    print
+    print "[[!toc  ]]"
+    print
+    display(pinouts)
+    print
+
+    print "# Pinouts (Fixed function)"
+    print
+
+    fixedpins = {
+      'DDR3':
+        ['SDQ0', 'SDQ1', 'SDQ2', 'SDQ3', 'SDQ4', 'SDQ5', 'SDQ6', 'SDQ7',
+         'SDQ8', 'SDQ9', 'SDQ10', 'SDQ11', 'SDQ12', 'SDQ13', 'SDQ14', 'SDQ15',
+         'SDQ16', 'SDQ17', 'SDQ18', 'SDQ19', 'SDQ20', 'SDQ21', 'SDQ22', 'SDQ23',
+         'SDQ24', 'SDQ25', 'SDQ26', 'SDQ27', 'SDQ28', 'SDQ29', 'SDQ30', 'SDQ31',
+         'SVREF0', 'SVREF1', 'SVREF2', 'SVREF3',
+         'SDQS0', 'SDQS0#', 'SDQS1', 'SDQS1#',
+         'SDQS2', 'SDQS2#', 'SDQS3', 'SDQS3#',
+         'SDQM0', 'SDQM1', 'SDQM2', 'SDQM3',
+         'SCK#', 'SCK', 'SCKE0', 'SCKE1',
+         'SA0', 'SA1', 'SA2', 'SA3', 'SA4', 'SA5', 'SA6', 'SA7',
+         'SA8', 'SA9', 'SA10', 'SA11', 'SA12', 'SA13', 'SA14',
+         'SBA0', 'SBA1', 'SBA2',
+         'SWE', 'SCAS', 'SRAS',
+         'SCS0', 'SCS1',
+         'SZQ', 'SRST',
+         'SDBG0', 'SDBG1', 'ADBG',
+         'ODT0', 'ODT1'
+        ],
+
+      'CTRL_SYS':
+        [
+        'TEST', 'JTAG_SEL', 'UBOOT_SEL', 
+        'NMI#', 'RESET#', 
+        'CLK24M_IN', 'CLK24M_OUT', 
+        'PLLTEST', 'PLLREGIO', 'PLLVP25', 
+        'PLLDV', 'PLLVREG', 'PLLGND', 
+       ],
+
+      'POWER_DRAM':
+        ['VCC0_DRAM', 'VCC1_DRAM', 'VCC2_DRAM', 'VCC3_DRAM', 'VCC4_DRAM', 
+         'VCC5_DRAM', 'VCC6_DRAM', 'VCC7_DRAM', 'VCC8_DRAM', 'VCC9_DRAM',
+        'GND0_DRAM', 'GND1_DRAM', 'GND2_DRAM', 'GND3_DRAM', 'GND4_DRAM',
+        'GND5_DRAM', 'GND6_DRAM', 'GND7_DRAM', 'GND8_DRAM', 'GND9_DRAM',
+        ],
+
+      'POWER_CPU':
+        ['VDD0_CPU', 'VDD1_CPU', 'VDD2_CPU', 'VDD3_CPU', 'VDD4_CPU', 'VDD5_CPU',
+         'GND0_CPU', 'GND1_CPU', 'GND2_CPU', 'GND3_CPU', 'GND4_CPU', 'GND5_CPU',
+        ],
+
+      'POWER_DLL':
+        ['VDD0_DLL', 'VDD1_DLL', 'VDD2_DLL', 
+         'GND0_DLL', 'GND1_DLL', 'GND2_DLL', 
+        ],
+
+      'POWER_INT':
+        ['VDD0_INT', 'VDD1_INT', 'VDD2_INT', 'VDD3_INT', 'VDD4_INT', 
+         'VDD5_INT', 'VDD6_INT', 'VDD7_INT', 'VDD8_INT', 'VDD9_INT', 
+         'GND0_INT', 'GND1_INT', 'GND2_INT', 'GND3_INT', 'GND4_INT', 
+         'GND5_INT', 'GND6_INT', 'GND7_INT', 'GND8_INT', 'GND9_INT', 
+        ],
+
+      'POWER_GPIO':
+        ['VDD_GPIOA', 'VDD_GPIOB', 'VDD_GPIOC',
+         'VDD_GPIOD', 'VDD_GPIOE', 'VDD_GPIOF',
+         'VDD_GPIOG',
+         'GND_GPIOA', 'GND_GPIOB', 'GND_GPIOC',
+         'GND_GPIOD', 'GND_GPIOE', 'GND_GPIOF', 
+         'GND_GPIOG',
+        ]
+
+      }
+
+    display_fixed(fixedpins, len(pinouts))
+
+    print "# Functions (PinMux)"
+    print
+    print "auto-generated by [[pinouts.py]]"
+    print
+
+    function_names = {'EINT': 'External Interrupt',
+                      'FB': 'MC68k FlexBus',
+                      'IIS': 'I2S Audio',
+                      'JTAG1': 'JTAG (same as JTAG2, JTAG_SEL=LOW)',
+                      'JTAG2': 'JTAG (same as JTAG1, JTAG_SEL=HIGH)',
+                      'LCD': '24-pin RGB/TTL LCD',
+                      'RG': 'RGMII Ethernet',
+                      'MMC': 'eMMC 1/2/4/8 pin',
+                      'PWM': 'PWM (pulse-width modulation)',
+                      'SD1': 'SD/MMC 1',
+                      'SD2': 'SD/MMC 2',
+                      'SD3': 'SD/MMC 3',
+                      'SPI1': 'SPI (Serial Peripheral Interface) 1',
+                      'SPI2': 'SPI (Serial Peripheral Interface) 2',
+                      'SPI3': 'Quad SPI (Serial Peripheral Interface) 3',
+                      'TWI1': 'I2C 1',
+                      'TWI2': 'I2C 2',
+                      'TWI3': 'I2C 3',
+                      'UART0': 'UART (TX/RX/CTS/RTS) 0',
+                      'UART1': 'UART (TX/RX/CTS/RTS) 1',
+                      'UART2': 'UART (TX/RX) 2',
+                      'UART3': 'UART (TX/RX) 3',
+                      'UART4': 'UART (TX/RX) 4',
+                      'ULPI1': 'ULPI (USB Low Pin-count) 1',
+                      'ULPI2': 'ULPI (USB Low Pin-count) 2',
+                      'ULPI3': 'ULPI (USB Low Pin-count) 3',
+                    }
+            
+    fns = display_fns(bankspec, pinouts, function_names)
+    print
+
+    # Scenarios below can be spec'd out as either "find first interface"
+    # by name/number e.g. SPI1, or as "find in bank/mux" which must be
+    # spec'd as "BM:Name" where B is bank (A-F), M is Mux (0-3)
+    # EINT and PWM are grouped together, specially, but may still be spec'd
+    # using "BM:Name".  Pins are removed in-order as listed from
+    # lists (interfaces, EINTs, PWMs) from available pins.
+
+    # EOMA68 scenario.  not totally complete (some GPIO needed for PMIC)
+    # One interface to be connected to the MCU to give RTC and boot/dbg
+    # VBUS_EN, OTG_ID etc. are all not included below, there is plenty
+    # of spare GPIO.
+
+    eoma68 = ['B1:LCD/22', 'ULPI1/8', 'ULPI2', 'MMC', 'SD1', 'UART3',
+              'TWI3', 'SPI2', 'E2:SD2',]
+    eoma68_eint = ['EINT16', 'EINT17', 'EINT18', 'EINT19']
+    eoma68_pwm = ['D1:PWM_2']
+    descriptions = {
+            'MMC': 'internal (on Card)',
+            'SD1': 'user-facing: internal (on Card), multiplexed with JTAG1\n'
+                   'and UART2, for debug purposes',
+            'TWI3': 'EOMA68-compliance: must be entirely free of devices.\n'
+                    'Address 0x51 used (externally) for EOMA68 EEPROM Id',
+            'E2:SD2': 'EOMA68-compliance',
+            'SPI2': 'EOMA68-compliance',
+            'UART3': 'EOMA68-compliance',
+            'B1:LCD/22': 'EOMA68-compliance, 18-bit RGB/TTL LCD',
+            'ULPI1/8': 'user-facing: internal (on Card), USB-OTG ULPI PHY',
+            'ULPI2': 'EOMA68-compliance: dual USB2 Host ULPI PHY'
+    }
+
+    unused_pins = check_functions("EOMA68", bankspec, fns, pinouts,
+                 eoma68, eoma68_eint, eoma68_pwm,
+                 descriptions)
+
+    # Industrial scenario.  not totally complete (some GPIO needed for PMIC)
+    # One interface to be connected to the MCU to give RTC, boot/dbg,
+    # option of CAN Bus, ADC, DAC, OWB, more GPIO, more PWM etc. etc.
+    # Focus is on getting as many UARTs, SPIs and TWIs as possible.
+    # OTG_ID (if to be used) would require dropping some functions in order
+    # to free up GPIO.  LCD could be reduced to 15-bit (freeing 3).
+    # MMC could be reduced to 4-bit-wide, used as SD/MMC (freeing 4).
+    # SPI3 could be used in 1-bit (MOSI/MISO) mode (freeing up 2 more).
+
+    industrial = ['D1:FB/17', 'E1:FB/8', 'B1:LCD/22', 'ULPI1/8', 'ULPI2/8',
+                'MMC', 'B2:SD1',
+                'JTAG1', 'A3:UART2', 'E2:UART1', 'C3:UART0',
+              'F2:TWI1', 'D2:TWI2', 'D2:TWI3', 'SPI2', 'SPI3', 'F2:SD3']
+    industrial_pwm = ['F2:PWM_0', 'F2:PWM_1', 'D1:PWM_2']
+    industrial_eint = ['EINT24', 'EINT25', 'EINT26', 'EINT27',
+                       'EINT20', 'EINT21', 'EINT22', 'EINT23']
+
+    unused_pins = check_functions("Industrial", bankspec, fns, pinouts,
+                 industrial, industrial_eint, industrial_pwm)
+
+    # Industrial scenario, using an SPI-based LCD instead of RGB/TTL
+    # not totally complete (some GPIO needed for PMIC)
+    # One interface to be connected to the MCU to give RTC, boot/dbg,
+    # option of CAN Bus, ADC, DAC, OWB, more GPIO, more PWM etc. etc.
+    # Focus is on getting as many UARTs, SPIs and TWIs as possible,
+    # leaving some GPIO spare from the RGB/TTL bank (SPI CS#)
+    # also possibility of freeing up FlexBus CS# with a little reorg.
+
+    industrial = ['D1:FB/17', 'E1:FB/8', 'B2:SPI1', 'ULPI1/8', 'ULPI2/8',
+                'MMC', 'B2:SD1',
+                'JTAG1',
+                'A3:UART2', 'E2:UART1', 'C3:UART0', 'B2:UART4', 'B2:UART3',
+              'F2:TWI1', 'D2:TWI2', 'D2:TWI3', 'SPI2', 'SPI3', 'F2:SD3']
+    industrial_pwm = ['F2:PWM_0', 'F2:PWM_1', 'D1:PWM_2']
+    industrial_eint = ['EINT24', 'EINT25', 'EINT26', 'EINT27',
+                       'EINT20', 'EINT21', 'EINT22', 'EINT23']
+    ind_descriptions = {
+            'B2:SPI1': 'Used for 320x240 or 640x480 etc. SPI-based LCD.\n'
+                        'Frees up large numbers of GPIO from RGB/TTL bank'
+    }
+    unused_pins = check_functions("Industrial with SPI-LCD",
+                 bankspec, fns, pinouts,
+                 industrial, industrial_eint, industrial_pwm,
+                 ind_descriptions)
+
+    # Smartphone / Tablet - basically the same thing
+
+    tablet = ['B1:LCD/22', 'ULPI1/8', 'ULPI2/8',
+                'MMC', 'SD1',
+                'F1:IIS', # I2C Audio
+                'TWI2',   # I2C Audio
+                'E2:UART1', # WIFI/BT 
+                'E2:SD2',   # WIFI
+                'C3:UART0', # GPS
+                'D2:UART3', 
+                'D2:UART4', 
+              'D3:TWI1', 'D2:TWI3', 'SPI2', 'SPI3']
+    tablet_pwm = ['F2:PWM_0', # LCD_BACKLIGHT
+                  'F2:PWM_1', 'D1:PWM_2']
+    tablet_eint = ['EINT24', # BT_HOST_WAKE
+                   'EINT25', # WIFI_HOST_WAKE 
+                   'EINT26', # CTP_INT
+                    'EINT27', # GSENSOR_INT
+                    'EINT8', # GPS_INT
+                    'EINT7', # TILT_SENSOR_INT
+                    'EINT22', # COMPASS_INT
+                    'EINT23',  # MCU_INT
+                    'EINT16', # PMIC_INT
+                    'EINT17',  # PWR_BUTTON_INT
+                    'EINT30', # OTG_ID
+                    'EINT31',
+                ]
+    descriptions = {
+        'B1:LCD/22':
+             'RGB/TTL LCD, 800x480 or use SN75LVDS83b for up to 1440x900',
+        'MMC': 'eMMC: main internal storage',
+        'ULPI1/8': 'USB-OTG, connect to ULPI OTG PHY (for charging)\n'
+                   'as well as USB Host or USB Device',
+        'ULPI2/8': 'USB2 Host, connect to ULPI PHY w/and 4-port USB2 Hub\n'
+                    'for example GL850G or FE1.1. '
+                    'Connects to 2/3/4G/LTE Modem, 2x USB-Camera (VC0345)',
+        'SD1': 'internal, multiplexed with JTAG1\n'
+               'and UART2, for debug purposes',
+        'F1:IIS': 'I2C Audio, connect to AC97 Audio IC',
+        'TWI2': 'Connect to AC97 Audio IC',
+        'E2:UART1': 'Connect to BT on AP6234/AP6335',
+        'E2:SD2': 'Connect to WIFI on AP6234/AP6335',
+        'SPI3': 'Boot Storage (connection to companion / debug / boot MCU)\n'
+                'Only actually needs MISO/MOSI, bootstrap loader v. small\n'
+                'Bootstrap loader checks eMMC, USB-OTG, SD/MMC, SPI, etc.',
+        'SPI2': 'Spare? SPI, connect to higher-speed sensor?',
+        'D2:UART3': 'Spare? UART (or 2 extra GPIO / EINT)',
+        'D2:UART4': 'Spare? UART (or 2 extra GPIO)',
+        'D3:TWI1': 'Connect to PMIC',
+        'D2:TWI3': 'Connect to sensors (Trackpad? CTP GSENSOR TILT COMPASS)',
+        'GPIO': '9 spare GPIO pins for miscellaneous functions:\n'
+                'wake-up of BT, WIFI, LCD power, sensor power etc.\n'
+                '4 GPIO may be needed for PWM Audio from Modem.\n'
+                'LED lights for camera will be needed.\n'
+                'Some phones may have clam-shell or lid switch.\n'
+                'Some Modems have spare GPIO (over AT commandset).\n'
+                'AXP209 PMIC has 4x GPIO, accessible over I2C.\n'
+                'SPI2, UART3-4, PWM1-2 may also be spare (10 extra GPIO).\n'
+                'If more needed, companion MCU may be used (48+ pin variant)\n'
+                'which also includes ADC, DAC, more PWM etc.',
+        'F2:PWM_0': 'LCD Backlight',
+        'F2:PWM_1': 'Spare? PWM (or extra GPIO / EINT)',
+        'D1:PWM_2': 'Spare? PWM (or extra GPIO / EINT)',
+        'EINT24': 'BT_HOST_WAKE',
+        'EINT25': 'WIFI_HOST_WAKE',
+        'EINT26': 'CTP_INT',
+        'EINT27': 'GSENSOR_INT',
+        'EINT8': 'GPS_INT',
+        'EINT7': 'TILT_SENSOR_INT',
+        'EINT22': 'COMPASS_INT',
+        'EINT23': 'MCU_INT',
+        'EINT16': 'PMIC_INT',
+        'EINT17': 'PWR_BUTTON_INT',
+        'EINT30': 'OTG_ID',
+        'EINT31': 'Spare?',
+    }
+    unused_pins = check_functions("Smartphone / Tablet",
+                 bankspec, fns, pinouts,
+                 tablet, tablet_eint, tablet_pwm,
+                 descriptions)
+
+    # Laptop
+
+    laptop = ['D1:FB/17', 'E1:FB/8', 'B1:LCD/22', 'ULPI1/8', 'ULPI2/8',
+                'MMC', 'SD1',
+                'F1:IIS', # I2C Audio
+                'TWI2',   # I2C Audio
+                'E2:UART1', # WIFI/BT 
+                'E2:SD3',   # WIFI
+              'D2:TWI3', 'SPI3']
+    laptop_pwm = ['F2:PWM_0', # LCD_BACKLIGHT
+                 ]
+    laptop_eint = ['EINT20', # BT_HOST_WAKE
+                   'EINT21', # WIFI_HOST_WAKE 
+                    'EINT9',  # MCU_INT
+                    'EINT31', # PMIC_INT
+                ]
+    descriptions = {
+        'D1:FB/17': 'FlexBus.  Connect to DM9000 or AX99896A MCU-style Bus\n'
+                    '10/100 Ethernet PHY.',
+        'E1:FB/8': 'FlexBus bus bits 8-15, needed to make a 16-bit bus width',
+        'B1:LCD/22':
+             'RGB/TTL LCD, use SN75LVDS83b for LVDS or SSD2828 for MIPI,\n'
+             'or a Chrontel CH7039, CH7038, CH7034 or CH7018 for dual\n'
+             'display output (eDP/LVDS and HDMI/VGA) '
+             'conversion.',
+        'MMC': 'eMMC: main internal storage',
+        'ULPI1/8': 'USB-OTG, connect to ULPI OTG PHY (for charging)\n'
+                   'as well as USB Host or USB Device',
+        'ULPI2/8': 'USB2 Host, connect to ULPI PHY w/and 4-port USB2 Hub\n'
+                    'for example GL850G or FE1.1. '
+                    'Connects to USB-Camera (VC0345 and 3x external USB Ports)',
+        'SD1': 'internal, multiplexed with JTAG1\n'
+               'and UART2, for debug purposes',
+        'F1:IIS': 'I2C Audio, connect to AC97 Audio IC',
+        'TWI2': 'Connect to AC97 Audio IC',
+        'E2:UART1': 'Connect to BT on AP6234/AP6335',
+        'E2:SD3': 'Connect to WIFI on AP6234/AP6335',
+        'SPI3': 'Boot Storage (connection to companion / debug / boot MCU)\n'
+                'Only actually needs MISO/MOSI, bootstrap loader v. small\n'
+                'Bootstrap loader checks eMMC, USB-OTG, SD/MMC, SPI, etc.\n'
+                'MCU implements keyboard-matrix for keyboard (also trackpad?)',
+        'D2:TWI3': 'Connect to PMIC',
+        'GPIO': 'Plenty of spare GPIO pins for miscellaneous functions\n'
+                'MCU EINT-capable GPIO may be used to generate extra EINTs\n'
+                'on the single MCU_INT line, if really needed',
+        'F2:PWM_0': 'LCD Backlight',
+        'EINT20': 'BT_HOST_WAKE',
+        'EINT21': 'WIFI_HOST_WAKE',
+        'EINT9': 'MCU_INT',
+        'EINT31': 'PMIC_INT',
+    }
+    unused_pins = check_functions("Laptop / Netbook",
+                 bankspec, fns, pinouts,
+                 laptop, laptop_eint, laptop_pwm,
+                 descriptions)
+
+    # IoT
+
+    iot = ['B1:LCD', 'ULPI2/8', 'ULPI1/8',
+                'MMC', 'SD1',
+                'F1:IIS', # I2C Audio
+                #'TWI2',   # I2C Audio
+                'C3:UART0', # HSPA UART
+                'E2:UART1', # BT UART
+                'C2:SPI2', # HSPI SPI
+                'E2:SD3',   # WIFI
+                'D3:TWI1', # sensors CTP,
+              'D2:TWI3', 'SPI3']
+    iot_pwm = ['F2:PWM_0', # LCD_BACKLIGHT
+                 ]
+    iot_eint = [ 'EINT5', # 'HSPA_MST_RDY',
+                'EINT6', # 'HSPA_SL_RDY',
+                'EINT7', # 'HSPA_RING',
+                'EINT8', # 'WL_PMU_EN',
+                'EINT9', # HSPA_GPIO1
+                'EINT10', # IR_DT
+                'EINT11', # 'BT_PCM_CLK',
+                'EINT12', # 'BT_PCM_DIN',
+                'EINT13', # 'BT_PCM_SYNC',
+                'EINT14', # 'BT_PCM_DOUT',
+                'EINT16', # 'USB_DRVVBUS',
+                'EINT17', # 'USB_VBUSDET',
+                'EINT21', # 'USB_ID',
+                'EINT30', # 'CTP_INT',
+                'EINT31', # 'SD_DET#',
+                ]
+    descriptions = {
+        'B1:LCD':
+             'RGB/TTL LCD, use SN75LVDS83b for LVDS or SSD2828 for MIPI,\n'
+             'or a Chrontel CH7039, CH7038, CH7034 or CH7018 for dual\n'
+             'display output (eDP/LVDS and HDMI/VGA) '
+             'conversion.',
+        'MMC': 'eMMC: main internal storage',
+        'F1:IIS': 'I2C Audio, connect to AC97 Audio IC',
+        'ULPI2/8': 'USB-OTG, connect to ULPI OTG PHY (for charging)\n'
+                   'as well as USB Host or USB Device',
+        'ULPI1/8': 'USB2 Host, connect to ULPI PHY',
+        'SD1': 'internal, multiplexed with JTAG1\n'
+               'and UART2, for debug purposes',
+        'C3:UART0': 'Connect to HSPA UART',
+        'E2:UART1': 'Connect to BT UART',
+        'E2:SD3': 'Connect to WIFI',
+        'C2:SPI2': 'HSPA SPI',
+        'SPI3': 'Boot Storage (connection to companion / debug / boot MCU)\n'
+                'Only actually needs MISO/MOSI, bootstrap loader v. small\n'
+                'Bootstrap loader checks eMMC, USB-OTG, SD/MMC, SPI, etc.\n'
+                'MCU implements keyboard-matrix for keyboard (also trackpad?)',
+        'D2:TWI3': 'Connect to PMIC',
+        'D3:TWI1': 'Connect to sensors CTP',
+        'GPIO': 'Plenty of spare GPIO pins for miscellaneous functions\n'
+                'MCU EINT-capable GPIO may be used to generate extra EINTs\n'
+                'on the single MCU_INT line, if really needed',
+        'F2:PWM_0': 'LCD Backlight',
+        'GPIOD4': 'WL_WAKE_AP',
+        'GPIOD5': 'BT_WAKE_AP',
+        'GPIOD6': 'AP_WAKE_BT',
+        'GPIOD7': 'AP_CK32KO',
+        'GPIOD8': 'HSPA_PWRON',
+        'GPIOD9': 'BT_RST_N',
+        'GPIOE5': 'HSPA_ON_OFF',
+        'GPIOD2': 'HSPA_SHUTDOWN',
+        'GPIOD3': 'CTP_RST',
+        'GPIOD12': 'LCD_RDN',
+        'GPIOD17': 'LCD_WRN',
+        'GPIOD18': 'LCD_RS',
+        'GPIOD21': 'LCD_CSN',
+
+        'EINT5': 'HSPA_MST_RDY',
+        'EINT6': 'HSPA_SL_RDY',
+        'EINT7': 'HSPA_RING',
+        'EINT8': 'WL_PMU_EN',
+        'EINT9': 'HSPA_GPIO1',
+        'EINT10': 'IR_DT',
+        'EINT11': 'BT_PCM_CLK',
+        'EINT12': 'BT_PCM_DIN',
+        'EINT13': 'BT_PCM_SYNC',
+        'EINT14': 'BT_PCM_DOUT',
+
+        'EINT16': 'USB_DRVVBUS',
+        'EINT17': 'USB_VBUSDET',
+        'EINT21': 'USB_ID',
+        'EINT30': 'CTP_INT',
+        'EINT31': 'SD_DETN',
+    }
+    unused_pins = check_functions("IoT",
+                 bankspec, fns, pinouts,
+                 iot, iot_eint, iot_pwm,
+                 descriptions)
+
+    print "# Reference Datasheets"
+    print
+    print "datasheets and pinout links"
+    print
+    print "* <http://datasheets.chipdb.org/AMD/8018x/80186/amd-80186.pdf>"
+    print "* <http://hands.com/~lkcl/eoma/shenzen/frida/FRD144A2701.pdf>"
+    print "* <http://pinouts.ru/Memory/sdcard_pinout.shtml>"
+    print "* p8 <http://www.onfi.org/~/media/onfi/specs/onfi_2_0_gold.pdf?la=en>"
+    print "* <https://www.heyrick.co.uk/blog/files/datasheets/dm9000aep.pdf>"
+    print "* <http://cache.freescale.com/files/microcontrollers/doc/app_note/AN4393.pdf>"
+    print "* <https://www.nxp.com/docs/en/data-sheet/MCF54418.pdf>"
+    print "* ULPI OTG PHY, ST <http://www.st.com/en/interfaces-and-transceivers/stulpi01a.html>"
+    print "* ULPI OTG PHY, TI TUSB1210 <http://ti.com/product/TUSB1210/>"
+
diff --git a/shakti/m_class/ramanalysis.mdwn b/shakti/m_class/ramanalysis.mdwn
new file mode 100644 (file)
index 0000000..da1c2ce
--- /dev/null
@@ -0,0 +1,335 @@
+# Analysis of Options for Memory Interfaces for a Mobile-class Libre SoC
+
+This document covers why, according to best risk-reducing and practical
+issues, DDR3/DDR3L/LPDDR3 is the best option for a mobile-class SoC
+*at the time of writing*.
+
+The requirements which minimise risk are:
+
+* Reasonable power consumption for the target SoC (well below 1.5 watts)
+ power budget for the RAM ICs.
+* Minimum or equivalent of 700mhz @ 32-bit transfers (so 350mhz clockrate
+  for a total 700mhz DDR @ 32-bit or 175mhz @ 64-bit or 700mhz @ 16-bit)
+* Mass-volume pricing
+* High availability
+* Multiple suppliers
+* No more than 15 cm^3 board area required for RAM plus routing to SoC
+  (just about covers 4x DDR3 78-pin FBGA ICs, or 4x DDR3 96-pin FBGA ICs).
+  Around 15 cm^3 is quite generous, and is practical for making a credit-card
+  sized SBC with all RAM ICs and the SoC on TOP side of the PCB.
+
+Each of these will be covered in turn, below.  Then, there will be a
+separate section covering the various types of RAM offerings, including
+some innovative (research-style) ideas.  These are:
+
+* Package-on-Package (POP)
+* RAM on-die (known as Multi-Chip Modules)
+* MCM standard and *non*-standard interfaces (custom-designed)
+* Standard off-the-shelf die vs custom-made DRAM or SRAM ASIC
+* DDR1, DDR2, DDR3, DDR4 ....
+
+# Requirements
+
+## Power Consumption
+
+Lowering the power consumption is simply a practical consideration to keep
+cost down and make component selection, manufacturing and design of the PCB
+easier.  For example: if the AXP209 can be utilised as the PMIC for the
+entire product, that is a USD $0.5 part and the layout, amount of current
+it consumes, and general support including linux drivers makes it an easy
+choice.  On the other hand, if more complex PMIC layouts are required that
+automatically pushes pricing up, introduces risk and NREs.
+
+Therefore if the total budget for the entire design can be kept below
+around 3.5 watts, which translates roughly to around 1.5 watts for the memory
+and around 1.5 to 2W for the SoC, a lower-cost PMIC can be deployed *and*
+there is a lot less to worry about when it comes to thermal dissipation.
+
+Note that from Micron's Technical Note TN-41-01, a single x16 1033mhz
+DDR3 (not DDR3L) DRAM can consume 436mW on its own.  If two of those
+are deployed to give a 32-bit-wide memory interface @ 1033mhz, that's
+872mW which is just about acceptable.  It would be much better to
+consider using DDR3L (1.35v instead of 1.5v) as this would lower power
+consumption roughly on a square law with voltage for an approximate
+20% drop.
+
+## Minimum 700mhz @ 32-bit transfer rates
+
+This is a practical consideration for delivering reasonable performance
+and being able to cover 720 / 1080p video playback without stalling.
+Once decoded from their compressed format, video framebuffers take up
+an enormous amount of memory bandwidth, which cannot be cached on-chip
+so has to be written out to RAM and then read back in again.  Video
+(and 3D) therefore have a massive impact on the SoC's performance when
+using a lower-cost "shared memory bus" architecture.
+
+1.4 Gigabytes per second of raw reads/writes is therefore a reasonable
+compromise between development costs, overall system price, running too
+hot, and running so slow that users start complaining or cannot play
+certain videos or applications at all.
+If better than this absolute minimum can be achieved within the power
+budget that would be great.
+
+Other options to include are: going for a 64-bit wide total bus bandwidth,
+which can be achieved with either 4x 16-bit FBGA96 ICs, or 2x 32-bit
+FBGA168 LPDDR3 ICs.  The issue is: that assumes that it's okay to
+correspondingly increase the number of pins of the SoC by an extra
+100 on its pincount, in order to cover dual 32-bit DRAM interfaces.
+Aside from the increased licensing costs and power consumption associated
+with twin DRAM interfaces, the current proposed SoC is only 290 pins, meaning
+that it can be done as a 0.8mm pitch BGA that is only around 15mm on
+a side.  That makes it extremely low-cost and very easy to manufacture,
+even being possible to consider 4-layer PCBs and 10mil drill-holes
+(very cheap).
+
+If the pincount were increased to 400 it would be necessary to go to
+a 0.6mm pin pitch in order to keep the package size down.  That then in
+turn increases manufacturing costs (6-7 mil BGA VIA drill-holes, requiring
+laser-drilling) and so on.  Whilst it seems strange to consider the
+pin count and pin pitch of an SoC when considering something like the
+bandwidth of the memory bus, it goes some way to illustrate quite how
+interconnected everything really is.
+
+Bottom line: yes you *could* go to dual 32-bit-wide DDR RAM interfaces,
+but the *production* cost increases in doing so need to be taken into
+consideration.  Some SoCs do actually take only a 16-bit wide DDR RAM
+interface: these tend not to be very popular (or are used in specialist
+markets such as smart watches) as the reduction in memory bandwidth tends
+to go hand-in-hand with ultra-low-power scenarios.  Try putting them into
+the hands of mass-volume end users running general-purpose OSes such as
+Android and the users only complain and consider their purchase to have
+been a total waste of money.  32-bit-wide at around 1066mhz seems
+to be an acceptable compromise on all fronts.
+
+## Mass-volume Pricing, High availability, Multiple Suppliers
+
+These are all important inter-related considerations.  Surprisingly,
+older ICs *and* newer ICs tend to be higher cost.  It comes down to
+what is currently available and being mass-produced.  Older ICs fall
+out of popularity and thus become harder to find, or move to "legacy"
+foundries that have a higher cost per unit production.
+
+Newer ICs tend to be higher speeds and higher capacities, meaning that
+the yields are lower, the demands higher.  Costs can be sky high on a
+near-exponential curve based on capacity and speed compared to other
+offerings.
+
+Picking the right RAM interface (*and* picking the right speed grade range
+and bus bandwidth)
+that will ensure that the entire SoC
+has a useful lifetime is therefore really rather important!  If the
+expected lifetime is to be for example 5 years, it would be foolish
+to pick a DDR RAM interface that, towards the end of those 5 years,
+the cost of the only available RAM ICs is ten times higher than it
+was when the SoC first came out.
+
+In short - jumping the gun somewhat on why this document has been
+written - this means that DDR3/DDR3L/LPDDR3 is the preferred interface
+*at the moment*, given especially that SoCs such as the iMX6 have a
+support profile (lifetime) of 19 years, another 15 of which are
+still to go before the iMX6 reaches EOL.  Whilst DDR4/LPDDR4 would be
+"nice to have", it's still simply not reached the point yet where
+it's commonly available from multiple suppliers, and will not do
+so for many years yet.  It will require at least two Chinese
+Memory Manufacturers (not just Hynix, Micron and Samsung basically)
+before it starts to become price-competitive.  A quick search
+on taobao.com for Hynix P/N H9HCNNNBUUMLHR basically tells you
+what you need to know: very few suppliers, all with multiple
+"fake" listings, fluffing themselves up literally like a peacock
+to make them appear more attractive.  Compare that to searching
+for P/N H5TC4G63CFR on taobao and the fact that there are 5 *pages*
+of results from wildly disparate sellers, all roughly around the
+same price of RMB 20 (around USD $3) and that tells you that it's
+mass-produced and commonly available.
+
+## Board area
+
+15 cm^2 is about the minimum in which either four x8 or x16 DDR3 RAM ICs
+can be accommodated, including their routing, on one side of the PCB.
+There are other arrangements however 15 cm^2 is still reasonable
+for the majority of products with the exception of mobile phones and
+smaller sized smartphones.  7in Tablets, SBCs, Netbooks, Media Centres:
+all these products can be designed with a 15 cm^2 budget for RAM, and
+meet a very reasonable target price due to not needing 8+ layers, blind
+vias, double-sided reflow involving epoxy resin to glue underside ICs,
+or other strategies that get really quite expensive if they are to be
+considered for small initial production runs.
+
+With massive production budgets to jump over many of the hurdles, there is
+nothing to be concerned about.  However if considering a production and
+design budget below USD $50,000 and initial production runs using Shenzhen
+factories for pre-production and prototyping, "techniques" such as
+blind vias, 8+ layer PCBs and epoxy resin for gluing ICs onto the underside
+of PCBs become quickly cost-prohibitive, despite the costs averaging out
+by the time mass-production is reached.
+
+So there is a barrier to entry to overcome, and the simplest way to
+overcome that is to not get into the "small PCB budget" territory that
+requires these techniques in the first place.
+
+# RAM Design Options
+
+This section covers various options for board layout and IC selection,
+including custom-designing ICs.
+
+## Multi-Chip Modules
+
+This is basically where the SoC and the RAM bare die are on a common
+PCB *inside* the same IC packaging.  Routing between the dies is carried
+out on the common PCB, which is usually multi-layer.
+
+With the down-side that it requires large up-front costs to produce, plus
+an overhead on production costs when compared to separate ICs, the space
+and pincount savings can be enormous: one IC taking up 1.5 cm^2 instead
+of up to 15 cm^2 for a larger SoC plus routing plus 4 DRAM ICs, plus a
+saving of around 75 pins for 32-bit-wide DDR RAM not being needed to be
+brought out.
+
+In addition, beyond a certain speed (and number of dies on-board), the
+amount of power consumption could potentially exceed the thermal capacity
+of smaller packages in the first place.
+
+The short version is: for smaller DRAM sizes (32mb up to 256mb), on-board
+RAM as a Multi-Chip Module has proven extremely successful, as evidenced
+by the Ingenic M200 and X1000 SoCs that are used in smart watches sold in
+China.  Beyond that capacity (512mb and above) the cost of the resultant
+multi-die chip appear less attractive than a multi-chip solution, meaning
+that it is quite a risky investment proposition.
+
+## Package-on-Package RAM
+
+The simplest way to express how much PoP RAM is not a good idea is
+to reference the following, an analysis of a rather useful but
+very expensive lesson:
+<http://laforge.gnumonks.org/blog/20170306-gta04-omap3_pop_soldering/>
+
+Package-on-Package RAM basically saves a lot of space on a PCB by stacking
+ICs vertically.  It's typically used in mobile phones where space is at
+a premium, yet the flexibility when compared to (fixed capacity) Multi-Chip
+Modules is desirable.
+
+The problem comes in assembly, as the GTA04 / GTA05 team found out to their
+cost.  In the case of the TI SoC selected, it was discovered - *after* the
+design had been finalised and pre-production prototypes were being assembled -
+that the SoC actually *warped and buckled* under the heat of the reflow oven.
+"Fixing" this involves extremely careful analysis and much more costly
+equipment than is commonly available, plus trying tricks such as covering
+the SoC and the PoP RAM in U.V. sensitive epoxy resin prior to placing it
+into the reflow oven, as a way to make sure that the IC "stack" has a
+reduced chance of warpage.
+
+Normally, a PoP RAM supplier, knowing that these problems can occur, simply
+will not sell the RAM to a manufacturer unless they have proven expertise
+or deep pockets to solve these kinds of issues.  Nokia for example was known
+to have tried, in one case, to have failed sufficient times such that they
+had around 10,000 to 50,000 production-grade PCBs that needed to be recovered
+before they managed to find a solution.  Once they had succeeded they went
+back to those failed units, had the SoC and PoP RAM removed (and either
+re-balled or, if too badly warped, simply thrown out), and re-processed
+the PCBs with new PoP RAM and SoC on them rather than write them off entirely:
+still a costly proposition all on its own.
+
+In short: Package-on-Package RAM is only something that, realistically, a
+multi-billion-dollar company can consider, when the supply volumes are
+*guaranteed* to exceed tens of millions of units.
+
+## Multi-chip Module RAM Interfaces
+
+One possibility would be to consider either custom-designing
+a RAM IC vs using a standard (JEDEC) RAM interface, or even some kind
+of pre-existing Bus (ATI, Wishbone, AXI).  When DDR (JEDEC) standard
+interfaces are utilised, the advantage is that off-the-shelf die pricing
+and supply can be negotiated with any of the DRAM vendors.
+
+However, in a fully libre IC, if that is indeed one of the goals,
+it becomes necessary to actually implement the DRAM interface (JEDEC
+standard DDRn).  Several independent designers have considered this:
+there even exists two published DDR3 designs that are already available
+online, the only problem being: they are Controllers not including the
+PHY (actual pin pads).
+
+So to save on doing that, logically we might consider utilising a
+pre-existing bus for which the VHDL / Verilog source code already
+exists: ATI Bus, SRAM Bus, even ONFI, or better Wishbone or AXI.
+The only problem is: now that you are into non-standard territory,
+it becomes necessary to consider *designing and making your own DRAM*.
+This is covered in the following section.
+
+## Custom DRAM or SRAM vs off-the-shelf dies
+
+The distinct advantage of an off-the-shelf die that conforms to the JEDEC
+DDR1/2/3/4 standard is: it's a known quantity, mass-produced (all the
+advantages already described above).  We might reasonably wish to consider
+utilising SRAM instead, but SRAM is a multi-gate solution per "bit" whereas
+a DRAM cell is basically a capacitor, taking up only one gate's worth of
+space per bit: absolutely tiny, in other words, which is why it's used.
+
+Not only that but considering creating your own custom DRAM, you in effect
+become your own "single supplier", with Research and Development overheads
+to have had to take into consideration as well.
+
+In short: it's a huge risk with no guaranteed payoff, and not only that
+but if the development of the alternative DRAM fails but the SoC was
+designed exclusively without a JEDEC-standard DRAM interface on the
+expectation that the alternative DRAM *would* succeed, the SoC is now
+up the creek without a paddle.
+
+In reverse-engineering terms: the rule of thumb is, you never make more
+than one change at a time, because then you cannot tell which change
+actually caused the error.  An adaptation of this rule of thumb to apply
+heree: there are *three* changes being made: one to use a non-standard
+Memory interface, two to develop and eentirely new DRAM chip and three to
+use the same non-standard Memory interface *on* that DRAM IC.  In short,
+it's too much to consider all at once.
+
+## DDR1..DDR4
+
+Overall it's pointing towards using one of the standard JEDEC DDR interfaces.
+DDR1 only runs at 133mhz and the power consumption is enormous: 1.8v and above
+is not uncommon.  DDR2 again is too slow and too power-hungry.  DDR3 hits
+the right spot in terms of "common mass production" whereas DDR4, despite
+its speed and power consumption advantages, is migrating towards being
+too challenging.
+
+In an earlier section the availability of LPDDR4 RAM ICs, which would be great
+to use if they were easily accessible, was shown to be far too low.  Not only
+that but DDR4 runs at a minimum 2400mhz DDR clock rate: 1200mhz (1.2ghz!)
+signal paths.  It's now necessary to take into consideration the length of
+the tracks *on the actual dies* - both in the SoC and inside the DRAM - when
+designing the tracks between the two.  It's just far too risky to consider
+tackling.
+
+So overall this is reinforcing that DDR3/DDR3L/LPDDR3 is the right choice
+*at this time*.
+
+# Conclusion: DDR3/DDR3L/LPDDR3
+
+DDR3 basically meets the requirements.
+
+* 4x DDR3L 8-bit FBGA78 ICs @ 1066mhz meets the power budget
+* Likewise 2x DDR3L 16-bit FBGA96 @ 1066mhz
+* Likewise 1x LPDDR3 32-bit FBGA168 @ 1866mhz
+* Pricing and availability is good on 8x and 16x DDR3/DDR3L ICs
+  (not so much on LPDDR3)
+* There are multiple suppliers of DDR3 including some chinese companies
+* 4x DDR3 8/16-bit RAM ICs easily fits into around 15 cm^2.
+
+Risks are reduced, pricing is competitive, supply is guaranteed, future
+supply as speeds increase is also guaranteed, power consumption is reasonable.
+Overall everything points towards DDR3 *at the moment*.  Despite the iMX6
+still having nearly 15 years until it is EOL, meaning that Freescale / NXP
+genuinely anticipate availability of the types (speed grades) of DDR3 RAM ICs
+with which the iMX6 is compatible, it is *always* sensible to monitor the
+situation continuously, and, critically, to bear in mind that, in the
+projected lifespan planning, an SoC takes at least 18 months before it
+hits production.
+
+So from the moment that the SoC is planned, whatever peripherals (including
+DRAM ICs) it is to be used with, the availability planning starts a
+full *eighteen months* into the future.  For a libre SoC where many
+people working on it will not consider signing NDAs, it becomes even
+more critically important to ensure that whatever ICs it requires -
+DRAM especially - are cast-iron guaranteed to be available within the SoC's
+projected lifespan.  DDR3 it can be said to meet that and all other
+requirements.
+