Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allwinner: Support for H2+ and H3 (OrangePiZero) #23

Merged
merged 3 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion allwinner/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ func IsA64() bool {
return detection.isA64
}

// IsH3 detects whether the host CPU is an Allwinner H3/H2+ Plus CPU.
//
// It looks for the string "sun8i-h2-plus" or "sun8i-h3" in /proc/device-tree/compatible.
func IsH3() bool {
detection.do()
return detection.isH3
}

// IsH5 detects whether the host CPU is an Allwinner H5 CPU.
//
// It looks for the string "sun50i-h5" in /proc/device-tree/compatible.
Expand All @@ -61,6 +69,7 @@ type detectionS struct {
isR8 bool
isA20 bool
isA64 bool
isH3 bool
isH5 bool
}

Expand All @@ -87,11 +96,16 @@ func (d *detectionS) do() {
if strings.Contains(c, "sun7i-a20") {
d.isA20 = true
}
// H2+ is a subtype of H3 and nearly compatible (only lacks GBit MAC and
// 4k HDMI Output), so it is safe to map H2+ as an H3.
if strings.Contains(c, "sun8i-h2-plus") || strings.Contains(c, "sun8i-h3") {
d.isH3 = true
}
if strings.Contains(c, "sun50i-h5") {
d.isH5 = true
}
}
d.isAllwinner = d.isA64 || d.isR8 || d.isA20 || d.isH5
d.isAllwinner = d.isA64 || d.isR8 || d.isA20 || d.isH3 || d.isH5

if !d.isAllwinner {
// The kernel in the image that comes pre-installed on the pcDuino3 Nano
Expand Down
4 changes: 4 additions & 0 deletions allwinner/gpio.go
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,10 @@ func (d *driverGPIO) Init() (bool, error) {
if err := mapA20Pins(); err != nil {
return true, err
}
case IsH3():
if err := mapH3Pins(); err != nil {
return true, err
}
case IsH5():
if err := mapH5Pins(); err != nil {
return true, err
Expand Down
141 changes: 141 additions & 0 deletions allwinner/h3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package allwinner

import (
"strings"

"periph.io/x/conn/v3/pin"
"periph.io/x/host/v3/sysfs"
)

// Page 74 (Chapter 3.2 GPIO Multiplexing Functions)
// http://dl.linux-sunxi.org/H3/Allwinner_H3_Datasheet_V1.0.pdf
var mappingH3 = map[string][5]pin.Func{
"PA0": {"UART2_TX", "JTAG_MS", "", "", "PA_EINT0"},
"PA1": {"UART2_RX", "JTAG_CK", "", "", "PA_EINT1"},
"PA2": {"UART2_RTS", "JTAG_DO", "", "", "PA_EINT2"},
"PA3": {"UART2_CTS", "JTAG_DI", "", "", "PA_EINT3"},
"PA4": {"UART0_TX", "", "", "", "PA_EINT4"},
"PA5": {"UART0_RX", "PWM0", "", "", "PA_EINT5"},
"PA6": {"SIM_PWREN", "PWM1", "", "", "PA_EINT6"},
"PA7": {"SIM_CK", "", "", "", "PA_EINT7"},
"PA8": {"SIM_DATA", "", "", "", "PA_EINT8"},
"PA9": {"SIM_RST", "", "", "", "PA_EINT9"},
"PA10": {"SIM_DET", "", "", "", "PA_EINT10"},
"PA11": {"TWI0_SCK", "DI_TX", "", "", "PA_EINT11"},
"PA12": {"TWI0_SDA", "DI_RX", "", "", "PA_EINT12"},
"PA13": {"SPI1_CS", "UART3_TX", "", "", "PA_EINT13"},
"PA14": {"SPI1_CLK", "UART3_RX", "", "", "PA_EINT14"},
"PA15": {"SPI1_MOSI", "UART3_RTS", "", "", "PA_EINT15"},
"PA16": {"SPI1_MOSI", "UART3_CTS", "", "", "PA_EINT16"},
"PA17": {"OWA_OUT", "", "", "", "PA_EINT17"},
"PA18": {"PCM0_SYNC", "TWI1_SCK", "", "", "PA_EINT18"},
"PA19": {"PCM0_CLK", "TWI1_SDA", "", "", "PA_EINT19"},
"PA20": {"PCM0_DOUT", "SIM_VPPEN", "", "", "PA_EINT20"},
"PA21": {"PCM0_DIN", "SIM_VPPPP", "", "", "PA_EINT21"},

"PC0": {"NAND_WE", "SPI0_MOSI"},
"PC1": {"NAND_ALE", "SPI0_MISO"},
"PC2": {"NAND_CLE", "SPI0_CLK"},
"PC3": {"NAND_CE1", "SPI0_CS"},
"PC4": {"NAND_CE0"},
"PC5": {"NAND_RE", "SDC2_CLK"},
"PC6": {"NAND_RB0", "SDC2_CMD"},
"PC7": {"NAND_RB1"},
"PC8": {"NAND_DQ0", "SDC2_D0"},
"PC9": {"NAND_DQ1", "SDC2_D1"},
"PC10": {"NAND_DQ2", "SDC2_D2"},
"PC11": {"NAND_DQ3", "SDC2_D3"},
"PC12": {"NAND_DQ4", "SDC2_D4"},
"PC13": {"NAND_DQ5", "SDC2_D5"},
"PC14": {"NAND_DQ6", "SDC2_D6"},
"PC15": {"NAND_DQ7", "SDC2_D7"},
"PC16": {"NAND_DQS", "SDC2_RST"},

"PD0": {"RGMII_RXD3"},
"PD1": {"RGMII_RXD2"},
"PD2": {"RGMII_RXD1"},
"PD3": {"RGMII_RXD0"},
"PD4": {"RGMII_RXCK"},
"PD5": {"RGMII_RXCTL"},
"PD6": {"RGMII_NULL"},
"PD7": {"RGMII_TXD3"},
"PD8": {"RGMII_TXD2"},
"PD9": {"RGMII_TXD1"},
"PD10": {"RGMII_TXD0"},
"PD11": {"RGMII_NULL"},
"PD12": {"RGMII_TXCK"},
"PD13": {"RGMII_TXCTL"},
"PD14": {"RGMII_NULL"},
"PD15": {"RGMII_CLKIN"},
"PD16": {"MDC"},
"PD17": {"MDIO"},

"PE0": {"CSI_PCLK", "TS_CLK"},
"PE1": {"CSI_MCLK", "TS_ERR"},
"PE2": {"CSI_HSYNC", "TS_SYNC"},
"PE3": {"CSI_VSYNC", "TS_DVLD"},
"PE4": {"CSI_D0", "TS_D0"},
"PE5": {"CSI_D1", "TS_D1"},
"PE6": {"CSI_D2", "TS_D2"},
"PE7": {"CSI_D3", "TS_D3"},
"PE8": {"CSI_D4", "TS_D4"},
"PE9": {"CSI_D5", "TS_D5"},
"PE10": {"CSI_D6", "TS_D6"},
"PE11": {"CSI_D7", "TS_D7"},
"PE12": {"CSI_SCK", "TWI2_SCK"},
"PE13": {"CSI_SDA", "TWI2_SDA"},
"PE14": {""},
"PE15": {""},

"PF0": {"SDC0_D1", "JTAG_MS"},
"PF1": {"SDC0_D0", "JTAG_DI"},
"PF2": {"SDC0_CLK", "UART0_TX"},
"PF3": {"SDC0_CMD", "JTAG_DO"},
"PF4": {"SDC0_D3", "UART0_RX"},
"PF5": {"SDC0_D2", "JTAG_CK"},
"PF6": {"SDC0_DET"},

"PG0": {"SDC1_CLK", "", "", "", "PG_EINT0"},
"PG1": {"SDC1_CMD", "", "", "", "PG_EINT1"},
"PG2": {"SDC1_D0", "", "", "", "PG_EINT2"},
"PG3": {"SDC1_D1", "", "", "", "PG_EINT3"},
"PG4": {"SDC1_D2", "", "", "", "PG_EINT4"},
"PG5": {"SDC1_D3", "", "", "", "PG_EINT5"},
"PG6": {"UART1_TX", "", "", "", "PG_EINT6"},
"PG7": {"UART1_RX", "", "", "", "PG_EINT7"},
"PG8": {"UART1_RTS", "", "", "", "PG_EINT8"},
"PG9": {"UART1_CTS", "", "", "", "PG_EINT9"},
"PG10": {"PCM1_SYNC", "", "", "", "PG_EINT10"},
"PG11": {"PCM1_CLK", "", "", "", "PG_EINT11"},
"PG12": {"PCM1_DOUT", "", "", "", "PG_EINT12"},
"PG13": {"PCM1_DIN", "", "", "", "PG_EINT13"},

"PL0": {"S_TWI_SCK", "", "", "", "S_PL_EINT0"},
"PL1": {"S_TWI_SDA", "", "", "", "S_PL_EINT1"},
"PL2": {"S_UART_TX", "", "", "", "S_PL_EINT2"},
"PL3": {"S_UART_RX", "", "", "", "S_PL_EINT3"},
"PL4": {"S_JTAG_MS", "", "", "", "S_PL_EINT4"},
"PL5": {"S_JTAG_CK", "", "", "", "S_PL_EINT5"},
"PL6": {"S_JTAG_DO", "", "", "", "S_PL_EINT6"},
"PL7": {"S_JTAG_DI", "", "", "", "S_PL_EINT7"},
"PL8": {"", "", "", "", "S_PL_EINT8"},
"PL9": {"", "", "", "", "S_PL_EINT9"},
"PL10": {"S_PWM", "", "", "", "S_PL_EINT10"},
"PL11": {"S_CIR_RX", "", "", "", "S_PL_EINT12"},
}

func mapH3Pins() error {
for name, altFuncs := range mappingH3 {
pin := cpupins[name]
pin.altFunc = altFuncs
pin.available = true
if strings.Contains(string(altFuncs[4]), "_EINT") ||
strings.Contains(string(altFuncs[3]), "_EINT") {
pin.supportEdge = true
}

// Initializes the sysfs corresponding pin right away.
pin.sysfsPin = sysfs.Pins[pin.Number()]
}
return nil
}
12 changes: 12 additions & 0 deletions orangepi/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// copyright 2016 the periph authors. all rights reserved.
// use of this source code is governed under the apache license, version 2.0
// that can be found in the license file.

// package orangepi contains Orange Pi hardware logic.
//
// requires armbian jessie server.
//
// physical
//
// http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/index.html
package orangepi
149 changes: 149 additions & 0 deletions orangepi/orangepi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package orangepi

import (
"errors"
"fmt"
"strings"

"periph.io/x/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/pin"
"periph.io/x/conn/v3/pin/pinreg"
"periph.io/x/host/v3/allwinner"
"periph.io/x/host/v3/distro"
)

func Present() bool {
if isArm {
return strings.HasPrefix(distro.DTModel(), "OrangePi")
}

return false
}

const (
boardZero string = "Orange Pi Zero" // + LTS (H2/H3 have identical pinouts)
)

var (
PA1_1 pin.Pin = pin.DC_IN // VCC 3v3 Ext
PA1_2 pin.Pin = pin.V5
PA1_3 gpio.PinIO = allwinner.PA12
PA1_4 pin.Pin = pin.V5
PA1_5 gpio.PinIO = allwinner.PA11
PA1_6 pin.Pin = pin.GROUND
PA1_7 gpio.PinIO = allwinner.PA6
PA1_8 gpio.PinIO = allwinner.PG6
PA1_9 pin.Pin = pin.GROUND
PA1_10 gpio.PinIO = allwinner.PG7
PA1_11 gpio.PinIO = allwinner.PA1
PA1_12 gpio.PinIO = allwinner.PA7
PA1_13 gpio.PinIO = allwinner.PA0
PA1_14 pin.Pin = pin.GROUND
PA1_15 gpio.PinIO = allwinner.PA3
PA1_16 gpio.PinIO = allwinner.PA19
PA1_17 pin.Pin = pin.DC_IN // VCC 3v3 Ext
PA1_18 gpio.PinIO = allwinner.PA18
PA1_19 gpio.PinIO = allwinner.PA15
PA1_20 pin.Pin = pin.GROUND
PA1_21 gpio.PinIO = allwinner.PA16
PA1_22 gpio.PinIO = allwinner.PA2
PA1_23 gpio.PinIO = allwinner.PA14
PA1_24 gpio.PinIO = allwinner.PA13
PA1_25 pin.Pin = pin.GROUND
PA1_26 gpio.PinIO = allwinner.PA10

FUN1_1 pin.Pin = pin.V5
FUN1_2 pin.Pin = pin.GROUND
FUN1_3 pin.Pin = gpio.INVALID // USB-DM2
FUN1_4 pin.Pin = gpio.INVALID // USB-DP2
FUN1_5 pin.Pin = gpio.INVALID // USB-DM3
FUN1_6 pin.Pin = gpio.INVALID // USB-DP3
FUN1_7 pin.Pin = allwinner.HP_RIGHT // LINEOUTR
FUN1_8 pin.Pin = allwinner.HP_LEFT // LINEOUTL
FUN1_9 pin.Pin = gpio.INVALID // TVOUT
FUN1_10 pin.Pin = gpio.INVALID // MBIAS, Bias Voltage output for mic
FUN1_11 pin.Pin = allwinner.MIC_IN // INPUT Analog Microphone pin (+)
FUN1_12 pin.Pin = allwinner.MIC_GND // INPUT Analog Microphone pin (-)
FUN1_13 pin.Pin = allwinner.PL11 // IR-RX
)

func registerHeaders(model string) {
// http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero.html
if strings.Contains(model, boardZero) {
// 26pin expansion port
pinreg.Register("PA", [][]pin.Pin{
{PA1_1, PA1_2},
{PA1_3, PA1_4},
{PA1_5, PA1_6},
{PA1_7, PA1_8},
{PA1_9, PA1_10},
{PA1_11, PA1_12},
{PA1_13, PA1_14},
{PA1_15, PA1_16},
{PA1_17, PA1_18},
{PA1_19, PA1_20},
{PA1_21, PA1_22},
{PA1_23, PA1_24},
{PA1_25, PA1_26},
})

// 13pin function interface
pinreg.Register("FUN", [][]pin.Pin{
{FUN1_1},
{FUN1_2},
{FUN1_3},
{FUN1_4},
{FUN1_5},
{FUN1_6},
{FUN1_7},
{FUN1_8},
{FUN1_9},
{FUN1_10},
{FUN1_11},
{FUN1_12},
{FUN1_13},
})
}
}

type driver struct {
}

func (d *driver) String() string {
return "orangepi"
}

func (d *driver) Prerequisites() []string {
return nil
}

func (d *driver) After() []string {
return []string{"allwinner-gpio", "allwinner-gpio-pl"}
}

func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("borad Orange Pi not detected")
}

model := distro.DTModel()
if model == "<unknown>" {
return true, fmt.Errorf("orangepi: failed to obtain model")
}

registerHeaders(model)
return true, nil
}

func init() {
if isArm {
driverreg.MustRegister(&drv)
}
}

var drv driver
7 changes: 7 additions & 0 deletions orangepi/orangepi_arm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package orangepi

const isArm = true
10 changes: 10 additions & 0 deletions orangepi/orangepi_arm64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

//go:build arm64
// +build arm64

package orangepi

const isArm = true
10 changes: 10 additions & 0 deletions orangepi/orangepi_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

//go:build !arm && !arm64
// +build !arm,!arm64

package orangepi

const isArm = false