diff --git a/Documentation/platforms/arm/a64/boards/pinephone/index.rst b/Documentation/platforms/arm/a64/boards/pinephone/index.rst index b515e50a13b..e0c22c01059 100644 --- a/Documentation/platforms/arm/a64/boards/pinephone/index.rst +++ b/Documentation/platforms/arm/a64/boards/pinephone/index.rst @@ -145,6 +145,8 @@ NuttX for PinePhone supports these peripherals: =========== ======= ===== Peripheral Support NOTES =========== ======= ===== +MIPI D-PHY Yes +MIPI DSI Yes PIO Yes UART Yes Only UART0 is supported =========== ======= ===== diff --git a/arch/arm64/src/a64/Kconfig b/arch/arm64/src/a64/Kconfig index 55665849bb4..35a988fa1ea 100644 --- a/arch/arm64/src/a64/Kconfig +++ b/arch/arm64/src/a64/Kconfig @@ -6,10 +6,21 @@ if ARCH_CHIP_A64 menu "Allwinner A64 Peripheral Selection" + +config A64_MIPI_DSI + bool "MIPI DSI" + default n + ---help--- + Select to enable support for MIPI Display Serial Interface (DSI) + and MIPI Display Physical Layer (D-PHY). + config A64_UART bool "UART" default n select UART1_SERIALDRIVER + ---help--- + Select to enable support for UART. + endmenu # Allwinner A64 Peripheral Selection endif # ARCH_CHIP_A64 diff --git a/arch/arm64/src/a64/Make.defs b/arch/arm64/src/a64/Make.defs index a82916b8e16..38a59040175 100644 --- a/arch/arm64/src/a64/Make.defs +++ b/arch/arm64/src/a64/Make.defs @@ -23,4 +23,8 @@ include common/Make.defs # Allwinner A64 specific C source files CHIP_CSRCS = a64_boot.c a64_pio.c a64_serial.c +ifeq ($(CONFIG_A64_MIPI_DSI),y) +CHIP_CSRCS += a64_mipi_dphy.c a64_mipi_dsi.c mipi_dsi.c +endif + CHIP_ASRCS = a64_lowputc.S diff --git a/arch/arm64/src/a64/a64_mipi_dphy.c b/arch/arm64/src/a64/a64_mipi_dphy.c new file mode 100644 index 00000000000..46e4db64477 --- /dev/null +++ b/arch/arm64/src/a64/a64_mipi_dphy.c @@ -0,0 +1,162 @@ +/**************************************************************************** + * arch/arm64/src/a64/a64_mipi_dphy.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Reference: + * + * "Understanding PinePhone's Display (MIPI DSI)" + * https://lupyuen.github.io/articles/dsi + * + * "NuttX RTOS for PinePhone: Display Driver in Zig" + * https://lupyuen.github.io/articles/dsi2 + * + * "A64 Page" refers to Allwinner A64 User Manual + * https://lupyuen.github.io/images/Allwinner_A64_User_Manual_V1.1.pdf + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include "arm64_arch.h" +#include "a64_mipi_dphy.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* A64 CCU Registers and Bit Definitions ************************************/ + +/* MIPI_DSI Clock Register */ + +#define MIPI_DSI_CLK_REG (A64_CCU_ADDR + 0x168) +#define DPHY_CLK_DIV_M(n) ((n) << 0) +#define DSI_DPHY_SRC_SEL(n) ((n) << 8) +#define DSI_DPHY_GATING (1 << 15) + +/* A64 MIPI D-PHY Registers (Undocumented) **********************************/ + +#define DPHY_TX_CTL_REG (A64_DPHY_ADDR + 0x04) +#define DPHY_TX_TIME0_REG (A64_DPHY_ADDR + 0x10) +#define DPHY_TX_TIME1_REG (A64_DPHY_ADDR + 0x14) +#define DPHY_TX_TIME2_REG (A64_DPHY_ADDR + 0x18) +#define DPHY_TX_TIME3_REG (A64_DPHY_ADDR + 0x1c) +#define DPHY_TX_TIME4_REG (A64_DPHY_ADDR + 0x20) +#define DPHY_GCTL_REG (A64_DPHY_ADDR + 0x00) +#define DPHY_ANA0_REG (A64_DPHY_ADDR + 0x4c) +#define DPHY_ANA1_REG (A64_DPHY_ADDR + 0x50) +#define DPHY_ANA4_REG (A64_DPHY_ADDR + 0x5c) +#define DPHY_ANA2_REG (A64_DPHY_ADDR + 0x54) +#define DPHY_ANA3_REG (A64_DPHY_ADDR + 0x58) + +/* A64 MIPI D-PHY Values (Undocumented) */ + +#define ANA1_VTTMODE 0x80000000 +#define ANA2_ENABLECKCPU 0x10 +#define ANA2_ENABLEP2SCPU 0xf000000 +#define ANA3_ENABLEVTTC 0xf8000000 +#define ANA3_ENABLEDIV 0x4000000 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: a64_mipi_dphy_enable + * + * Description: + * Enable MIPI Display Physical Layer (D-PHY). + * + * Input Parameters: + * None + * + * Returned Value: + * OK is always returned at present. + * + ****************************************************************************/ + +int a64_mipi_dphy_enable(void) +{ + uint32_t mipi_dsi_clk; + + /* Set DSI Clock to 150 MHz (600 MHz / 4) *********************************/ + + ginfo("Set DSI Clock to 150 MHz\n"); + + /* MIPI_DSI Clock Register + * Set DSI_DPHY_GATING (Bit 15) to 1 + * (DSI DPHY Clock is On) + * Set DSI_DPHY_SRC_SEL (Bits 8 to 9) to 0b10 + * (DSI DPHY Clock Source is PLL_PERIPH0(1X)) + * Set DPHY_CLK_DIV_M (Bits 0 to 3) to 3 + * (DSI DPHY Clock divide ratio - 1) + */ + + mipi_dsi_clk = DSI_DPHY_GATING | + DSI_DPHY_SRC_SEL(0b10) | + DPHY_CLK_DIV_M(3); + putreg32(mipi_dsi_clk, MIPI_DSI_CLK_REG); + + /* Power on DPHY Tx (Undocumented) ****************************************/ + + ginfo("Power on DPHY Tx\n"); + putreg32(0x10000000, DPHY_TX_CTL_REG); + putreg32(0xa06000e, DPHY_TX_TIME0_REG); + putreg32(0xa033207, DPHY_TX_TIME1_REG); + putreg32(0x1e, DPHY_TX_TIME2_REG); + putreg32(0x0, DPHY_TX_TIME3_REG); + putreg32(0x303, DPHY_TX_TIME4_REG); + + /* Enable DPHY (Undocumented) *********************************************/ + + ginfo("Enable DPHY\n"); + putreg32(0x31, DPHY_GCTL_REG); + putreg32(0x9f007f00, DPHY_ANA0_REG); + putreg32(0x17000000, DPHY_ANA1_REG); + putreg32(0x1f01555, DPHY_ANA4_REG); + putreg32(0x2, DPHY_ANA2_REG); + up_mdelay(1); /* Wait at least 5 microseconds */ + + /* Enable LDOR, LDOC, LDOD (Undocumented) *********************************/ + + ginfo("Enable LDOR, LDOC, LDOD\n"); + putreg32(0x3040000, DPHY_ANA3_REG); + up_mdelay(1); /* Wait at least 1 microsecond */ + + modreg32(ANA3_ENABLEVTTC, ANA3_ENABLEVTTC, DPHY_ANA3_REG); + up_mdelay(1); /* Wait at least 1 microsecond */ + + modreg32(ANA3_ENABLEDIV, ANA3_ENABLEDIV, DPHY_ANA3_REG); + up_mdelay(1); /* Wait at least 1 microsecond */ + + modreg32(ANA2_ENABLECKCPU, ANA2_ENABLECKCPU, DPHY_ANA2_REG); + up_mdelay(1); /* Wait at least 1 microsecond */ + + modreg32(ANA1_VTTMODE, ANA1_VTTMODE, DPHY_ANA1_REG); + modreg32(ANA2_ENABLEP2SCPU, ANA2_ENABLEP2SCPU, DPHY_ANA2_REG); + + return OK; +} diff --git a/arch/arm64/src/a64/a64_mipi_dphy.h b/arch/arm64/src/a64/a64_mipi_dphy.h new file mode 100644 index 00000000000..6f9693f7494 --- /dev/null +++ b/arch/arm64/src/a64/a64_mipi_dphy.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * arch/arm64/src/a64/a64_mipi_dphy.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_A64_A64_MIPI_DPHY_H +#define __ARCH_ARM64_SRC_A64_A64_MIPI_DPHY_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/a64_memorymap.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: a64_mipi_dphy_enable + * + * Description: + * Enable MIPI Display Physical Layer (D-PHY). + * + * Input Parameters: + * None + * + * Returned Value: + * OK is always returned at present. + * + ****************************************************************************/ + +int a64_mipi_dphy_enable(void); + +#endif /* __ARCH_ARM64_SRC_A64_A64_MIPI_DPHY_H */ diff --git a/arch/arm64/src/a64/a64_mipi_dsi.c b/arch/arm64/src/a64/a64_mipi_dsi.c new file mode 100644 index 00000000000..87f08952f61 --- /dev/null +++ b/arch/arm64/src/a64/a64_mipi_dsi.c @@ -0,0 +1,993 @@ +/**************************************************************************** + * arch/arm64/src/a64/a64_mipi_dsi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Reference: + * + * "Understanding PinePhone's Display (MIPI DSI)" + * https://lupyuen.github.io/articles/dsi + * + * "NuttX RTOS for PinePhone: Display Driver in Zig" + * https://lupyuen.github.io/articles/dsi2 + * + * "A31 Page" refers to Allwinner A31 User Manual + * https://lupyuen.github.io/images/A31_User_Manual_v1.3_20150510.pdf + * + * "A64 Page" refers to Allwinner A64 User Manual + * https://lupyuen.github.io/images/Allwinner_A64_User_Manual_V1.1.pdf + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include "arm64_arch.h" +#include "mipi_dsi.h" +#include "a64_mipi_dsi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum Size of DSI Packets that will be sent */ + +#define DSI_MAX_PACKET_SIZE 128 /* In bytes */ + +/* Timeout for DSI Transmission in milliseconds */ + +#define DSI_TIMEOUT_MS 5 + +/* A64 CCU Registers and Bit Definitions ************************************/ + +/* Bus Clock Gating Register 0 (A64 Page 100) */ + +#define BUS_CLK_GATING_REG0 (A64_CCU_ADDR + 0x60) +#define MIPIDSI_GATING (1 << 1) + +/* Bus Software Reset Register 0 (A64 Page 138) */ + +#define BUS_SOFT_RST_REG0 (A64_CCU_ADDR + 0x2C0) +#define MIPI_DSI_RST (1 << 1) + +/* A64 MIPI DSI Registers and Bit Definitions *******************************/ + +/* DSI Control Register (A31 Page 843) */ + +#define DSI_CTL_REG (A64_DSI_ADDR + 0x0) +#define DSI_EN (1 << 0) + +/* DSI Basic Control Register (Undocumented) */ + +#define DSI_BASIC_CTL_REG (A64_DSI_ADDR + 0x0c) + +/* DSI Configuration Register 0 (A31 Page 845) */ + +#define DSI_BASIC_CTL0_REG (A64_DSI_ADDR + 0x10) +#define INSTRU_EN (1 << 0) +#define ECC_EN (1 << 16) +#define CRC_EN (1 << 17) + +/* DSI Configuration Register 1 (A31 Page 846) */ + +#define DSI_BASIC_CTL1_REG (A64_DSI_ADDR + 0x14) +#define DSI_MODE (1 << 0) +#define VIDEO_FRAME_START (1 << 1) +#define VIDEO_PRECISION_MODE_ALIGN (1 << 2) +#define VIDEO_START_DELAY(n) ((n) << 4) + +/* DSI Line Number Register 0 (A31 Page 847) */ + +#define DSI_BASIC_SIZE0_REG (A64_DSI_ADDR + 0x18) +#define VIDEO_VSA(n) ((n) << 0) +#define VIDEO_VBP(n) ((n) << 16) + +/* DSI Line Number Register 1 (A31 Page 847) */ + +#define DSI_BASIC_SIZE1_REG (A64_DSI_ADDR + 0x1c) +#define VIDEO_VACT(n) ((n) << 0) +#define VIDEO_VT(n) ((n) << 16) + +/* DSI Instruction Function Register (Undocumented) */ + +#define DSI_INST_FUNC_REG(n) (A64_DSI_ADDR + 0x020 + (n) * 0x04) +#define DSI_INST_FUNC_LANE_CEN (1 << 4) + +/* DSI Instruction Loop Select Register (Undocumented) */ + +#define DSI_INST_LOOP_SEL_REG (A64_DSI_ADDR + 0x40) + +/* DSI Instruction Loop Number Register (Undocumented) */ + +#define DSI_INST_LOOP_NUM_REG(n) (A64_DSI_ADDR + 0x44 + (n) * 0x10) + +/* DSI Instruction Jump Select Register (Undocumented) */ + +#define DSI_INST_JUMP_SEL_REG (A64_DSI_ADDR + 0x48) +#define DSI_INST_ID_LP11 0 +#define DSI_INST_ID_TBA 1 +#define DSI_INST_ID_HSC 2 +#define DSI_INST_ID_HSD 3 +#define DSI_INST_ID_LPDT 4 +#define DSI_INST_ID_HSCEXIT 5 +#define DSI_INST_ID_NOP 6 +#define DSI_INST_ID_DLY 7 +#define DSI_INST_ID_END 15 + +/* DSI Instruction Jump Configuration Register (Undocumented) */ + +#define DSI_INST_JUMP_CFG_REG(n) (A64_DSI_ADDR + 0x4c + (n) * 0x04) +#define DSI_INST_JUMP_CFG 0 + +/* DSI Transfer Start Register (Undocumented) */ + +#define DSI_TRANS_START_REG (A64_DSI_ADDR + 0x60) + +/* DSI Transfer Zero Register (Undocumented) */ + +#define DSI_TRANS_ZERO_REG (A64_DSI_ADDR + 0x78) + +/* DSI Timing Controller DRQ Register (Undocumented) */ + +#define DSI_TCON_DRQ_REG (A64_DSI_ADDR + 0x7c) + +/* DSI Pixel Format Register 0 (A31 Page 847) */ + +#define DSI_PIXEL_CTL0_REG (A64_DSI_ADDR + 0x80) +#define PIXEL_FORMAT(n) ((n) << 0) +#define PIXEL_ENDIAN (0 << 4) +#define PD_PLUG_DIS (1 << 16) + +/* DSI Pixel Package Register 0 (A31 Page 848) */ + +#define DSI_PIXEL_PH_REG (A64_DSI_ADDR + 0x90) +#define PIXEL_DT(n) ((n) << 0) +#define PIXEL_VC(n) ((n) << 6) +#define PIXEL_WC(n) ((n) << 8) +#define PIXEL_ECC(n) ((n) << 24) + +/* DSI Pixel Package Register 2 (A31 Page 849) */ + +#define DSI_PIXEL_PF0_REG (A64_DSI_ADDR + 0x98) +#define CRC_FORCE 0xffff + +/* DSI Pixel Package Register 3 (A31 Page 849) */ + +#define DSI_PIXEL_PF1_REG (A64_DSI_ADDR + 0x9c) +#define CRC_INIT_LINE0(n) ((n) << 0) +#define CRC_INIT_LINEN(n) ((n) << 16) + +/* DSI Sync Package Register 0 (A31 Page 850) */ + +#define DSI_SYNC_HSS_REG (A64_DSI_ADDR + 0xb0) +#define SYNC_ECC(n) ((n) << 24) +#define SYNC_D1(n) ((n) << 16) +#define SYNC_D0(n) ((n) << 8) +#define SYNC_VC(n) ((n) << 6) +#define SYNC_DT(n) ((n) << 0) + +/* DSI Sync Package Register 1 (A31 Page 850) */ + +#define DSI_SYNC_HSE_REG (A64_DSI_ADDR + 0xb4) + +/* DSI Sync Package Register 2 (A31 Page 851) */ + +#define DSI_SYNC_VSS_REG (A64_DSI_ADDR + 0xb8) + +/* DSI Sync Package Register 3 (A31 Page 851) */ + +#define DSI_SYNC_VSE_REG (A64_DSI_ADDR + 0xbc) + +/* DSI Blank Package Register 0 (A31 Page 852) */ + +#define DSI_BLK_HSA0_REG (A64_DSI_ADDR + 0xc0) + +/* DSI Blank Package Register 1 (A31 Page 852) */ + +#define DSI_BLK_HSA1_REG (A64_DSI_ADDR + 0xc4) +#define HSA_PD(n) ((n) << 0) +#define HSA_PF(n) ((n) << 16) + +/* DSI Blank Package Register 2 (A31 Page 852) */ + +#define DSI_BLK_HBP0_REG (A64_DSI_ADDR + 0xc8) + +/* DSI Blank Package Register 3 (A31 Page 852) */ + +#define DSI_BLK_HBP1_REG (A64_DSI_ADDR + 0xcc) +#define HBP_PD(n) ((n) << 0) +#define HBP_PF(n) ((n) << 16) + +/* DSI Blank Package Register 4 (A31 Page 852) */ + +#define DSI_BLK_HFP0_REG (A64_DSI_ADDR + 0xd0) + +/* DSI Blank Package Register 5 (A31 Page 853) */ + +#define DSI_BLK_HFP1_REG (A64_DSI_ADDR + 0xd4) +#define HFP_PD(n) ((n) << 0) +#define HFP_PF(n) ((n) << 16) + +/* DSI Blank Package Register 6 (A31 Page 853) */ + +#define DSI_BLK_HBLK0_REG (A64_DSI_ADDR + 0xe0) + +/* DSI Blank Package Register 7 (A31 Page 853) */ + +#define DSI_BLK_HBLK1_REG (A64_DSI_ADDR + 0xe4) +#define HBLK_PD(n) ((n) << 0) +#define HBLK_PF(n) ((n) << 16) + +/* DSI Blank Package Register 8 (A31 Page 854) */ + +#define DSI_BLK_VBLK0_REG (A64_DSI_ADDR + 0xe8) + +/* DSI Blank Package Register 9 (A31 Page 854) */ + +#define DSI_BLK_VBLK1_REG (A64_DSI_ADDR + 0xec) +#define VBLK_PD(n) ((n) << 0) +#define VBLK_PF(n) ((n) << 16) + +/* DSI Low Power Control Register (A31 Page 854) */ + +#define DSI_CMD_CTL_REG (A64_DSI_ADDR + 0x200) +#define TX_FLAG (1 << 9) +#define RX_FLAG (1 << 25) +#define RX_OVERFLOW (1 << 26) + +/* DSI Debug Data Register (Undocumented) */ + +#define DSI_DEBUG_DATA_REG (A64_DSI_ADDR + 0x2f8) + +/* DSI Low Power Transmit Package Register (A31 Page 856) */ + +#define DSI_CMD_TX_REG (A64_DSI_ADDR + 0x300) +#define DSI_CMD_TX_END (A64_DSI_ADDR + 0x3fc) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: a64_disable_dsi_processing + * + * Description: + * Disable DSI Processing + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void a64_disable_dsi_processing(void) +{ + /* DSI Configuration Register 0 (A31 Page 845) + * Set INSTRU_EN (Bit 0) to 0 + * (Disable DSI Processing) + */ + + modreg32(0, INSTRU_EN, DSI_BASIC_CTL0_REG); +} + +/**************************************************************************** + * Name: a64_enable_dsi_processing + * + * Description: + * Enable DSI Processing + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void a64_enable_dsi_processing(void) +{ + /* DSI Configuration Register 0 (A31 Page 845) + * Set INSTRU_EN (Bit 0) to 1 + * (Enable DSI Processing from Instruction 0) + */ + + modreg32(INSTRU_EN, INSTRU_EN, DSI_BASIC_CTL0_REG); +} + +/**************************************************************************** + * Name: a64_wait_dsi_transmit + * + * Description: + * Wait for DSI Transmission to complete. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; ERROR if timeout. + * + ****************************************************************************/ + +static int a64_wait_dsi_transmit(void) +{ + int i; + + /* Retry sending until timeout */ + + for (i = 0; i < DSI_TIMEOUT_MS; i++) + { + /* To check whether the transmission is complete, + * we poll on INSTRU_EN (Bit 0) + */ + + if ((getreg32(DSI_BASIC_CTL0_REG) & INSTRU_EN) == 0) + { + /* If INSTRU_EN is 0, then transmission is complete */ + + return 0; + } + + /* Sleep 1 millisecond and try again */ + + up_mdelay(1); + } + + gerr("DSI Transmit Timeout"); + return ERROR; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: a64_mipi_dsi_write + * + * Description: + * Transmit the payload data to the MIPI DSI Bus as a MIPI DSI Short or + * Long Packet. This function is called to initialize the LCD Controller. + * Assumes that the MIPI DSI Block has been enabled on the SoC. + * + * Input Parameters: + * channel - Virtual Channel + * cmd - DCS Command (Data Type) + * txbuf - Payload data for the packet + * txlen - Length of payload data (Max 65541 bytes) + * + * Returned Value: + * Number of bytes transmitted; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +ssize_t a64_mipi_dsi_write(uint8_t channel, + enum mipi_dsi_e cmd, + FAR const uint8_t *txbuf, + size_t txlen) +{ + int ret; + ssize_t pktlen = -1; + uint8_t pkt[DSI_MAX_PACKET_SIZE]; + uint64_t addr; + int i; + + /* Length should be 1 for Short Write, 2 for Short Write With Param */ + + ginfo("channel=%d, cmd=0x%x, txlen=%ld\n", channel, cmd, txlen); + DEBUGASSERT(txbuf != NULL); + if (cmd == MIPI_DSI_DCS_SHORT_WRITE && txlen != 1) + { + DEBUGPANIC(); + return ERROR; + } + else if (cmd == MIPI_DSI_DCS_SHORT_WRITE_PARAM && txlen != 2) + { + DEBUGPANIC(); + return ERROR; + } + + /* Erase the Packet Buffer */ + + memset(pkt, 0, sizeof(pkt)); + + /* Compose Short or Long Packet depending on DCS Command */ + + switch (cmd) + { + /* For DCS Long Write: Compose Long Packet */ + + case MIPI_DSI_DCS_LONG_WRITE: + pktlen = mipi_dsi_long_packet(pkt, sizeof(pkt), channel, cmd, + txbuf, txlen); + break; + + /* For DCS Short Write (with and without parameter): + * Compose Short Packet + */ + + case MIPI_DSI_DCS_SHORT_WRITE: + pktlen = mipi_dsi_short_packet(pkt, sizeof(pkt), channel, cmd, + txbuf, txlen); + break; + + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + pktlen = mipi_dsi_short_packet(pkt, sizeof(pkt), channel, cmd, + txbuf, txlen); + break; + + default: + DEBUGPANIC(); /* Invalid DCS Command */ + return ERROR; + }; + + /* Check for Packet Error */ + + ginfo("pktlen=%ld\n", pktlen); + if (pktlen < 0) + { + return pktlen; + } + + ginfodumpbuffer("pkt", pkt, pktlen); + DEBUGASSERT(pktlen >= 4); + + /* DSI Low Power Control Register (A31 Page 854) + * Set RX_Overflow (Bit 26) to 1 (Clear flag for "Receive Overflow") + * Set RX_Flag (Bit 25) to 1 (Clear flag for "Receive has started") + * Set TX_Flag (Bit 9) to 1 (Clear flag for "Transmit has started") + */ + + putreg32(RX_OVERFLOW | RX_FLAG | TX_FLAG, DSI_CMD_CTL_REG); + + /* Write the packet to DSI Low Power Transmit Package Register + * (A31 Page 856) + */ + + addr = DSI_CMD_TX_REG; + for (i = 0; i < pktlen; i += 4) + { + /* Fetch the next 4 bytes, fill with 0 if not available */ + + const uint32_t b[4] = + { + pkt[i], + (i + 1 < pktlen) ? pkt[i + 1] : 0, + (i + 2 < pktlen) ? pkt[i + 2] : 0, + (i + 3 < pktlen) ? pkt[i + 3] : 0 + }; + + /* Merge the next 4 bytes into a 32-bit value */ + + const uint32_t v = b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); + + /* Write the 32-bit value */ + + DEBUGASSERT(addr <= DSI_CMD_TX_END); + modreg32(v, 0xffffffff, addr); + addr += 4; + } + + /* DSI Low Power Control Register (A31 Page 854) + * Set TX_Size (Bits 0 to 7) to Packet Length - 1 + */ + + modreg32(pktlen - 1, 0xff, DSI_CMD_CTL_REG); + + /* DSI Instruction Jump Select Register (Undocumented) + * Set to begin the Low Power Transmission (LPTX) + */ + + putreg32(DSI_INST_ID_LPDT << (4 * DSI_INST_ID_LP11) | + DSI_INST_ID_END << (4 * DSI_INST_ID_LPDT), + DSI_INST_JUMP_SEL_REG); + + /* Disable DSI Processing then Enable DSI Processing */ + + a64_disable_dsi_processing(); + a64_enable_dsi_processing(); + + /* Wait for transmission to complete */ + + ret = a64_wait_dsi_transmit(); + if (ret < 0) + { + a64_disable_dsi_processing(); + return ret; + } + + /* Return number of bytes transmitted */ + + return txlen; +} + +/**************************************************************************** + * Name: a64_mipi_dsi_enable + * + * Description: + * Enable the MIPI DSI Block on the SoC. Should be called before + * transferring data on the MIPI DSI Bus. + * + * Input Parameters: + * None + * + * Returned Value: + * OK is always returned at present. + * + ****************************************************************************/ + +int a64_mipi_dsi_enable(void) +{ + uint32_t dsi_basic_ctl0; + uint32_t dsi_basic_ctl1; + uint32_t dsi_pixel_ph; + uint32_t dsi_pixel_pf1; + uint32_t dsi_pixel_ctl0; + uint32_t dsi_sync_hss; + uint32_t dsi_sync_hse; + uint32_t dsi_sync_vss; + uint32_t dsi_sync_vse; + uint32_t dsi_basic_size0; + uint32_t dsi_basic_size1; + uint32_t dsi_blk_hsa1; + uint32_t dsi_blk_hbp1; + uint32_t dsi_blk_hfp1; + uint32_t dsi_blk_hblk1; + uint32_t dsi_blk_vblk1; + + /* Enable MIPI DSI Bus ****************************************************/ + + ginfo("Enable MIPI DSI Bus\n"); + + /* Bus Clock Gating Register 0 (A64 Page 100) + * Set MIPIDSI_GATING (Bit 1) to 1 + * (Pass Gating Clock for MIPI DSI) + */ + + modreg32(MIPIDSI_GATING, MIPIDSI_GATING, BUS_CLK_GATING_REG0); + + /* Bus Software Reset Register 0 (A64 Page 138) + * Set MIPI_DSI_RST (Bit 1) to 1 + * (Deassert MIPI DSI Reset) + */ + + modreg32(MIPI_DSI_RST, MIPI_DSI_RST, BUS_SOFT_RST_REG0); + + /* Enable DSI Block *******************************************************/ + + ginfo("Enable DSI Block\n"); + + /* DSI Control Register (A31 Page 843) + * Set DSI_En (Bit 0) to 1 (Enable DSI) + */ + + putreg32(DSI_EN, DSI_CTL_REG); + + /* DSI Configuration Register 0 (A31 Page 845) + * Set CRC_En (Bit 17) to 1 (Enable CRC) + * Set ECC_En (Bit 16) to 1 (Enable ECC) + */ + + dsi_basic_ctl0 = CRC_EN | ECC_EN; + putreg32(dsi_basic_ctl0, DSI_BASIC_CTL0_REG); + + /* DSI Transfer Start Register (Undocumented) + * Set to 10 + */ + + putreg32(10, DSI_TRANS_START_REG); + + /* DSI Transfer Zero Register (Undocumented) + * Set to 0 + */ + + putreg32(0, DSI_TRANS_ZERO_REG); + + /* Set Instructions (Undocumented) */ + + ginfo("Set Instructions\n"); + + /* DSI Instruction Function Register (Undocumented) + * Set DSI_INST_ID_LP11 to 0x1f + * Set DSI_INST_ID_TBA to 0x1000 0001 + * Set DSI_INST_ID_HSC to 0x2000 0010 + * Set DSI_INST_ID_HSD to 0x2000 000f + */ + + putreg32(0x1f, DSI_INST_FUNC_REG(DSI_INST_ID_LP11)); + putreg32(0x10000001, DSI_INST_FUNC_REG(DSI_INST_ID_TBA)); + putreg32(0x20000010, DSI_INST_FUNC_REG(DSI_INST_ID_HSC)); + putreg32(0x2000000f, DSI_INST_FUNC_REG(DSI_INST_ID_HSD)); + + /* Set DSI_INST_ID_LPDT to 0x3010 0001 + * Set DSI_INST_ID_HSCEXIT to 0x4000 0010 + * Set DSI_INST_ID_NOP to 0xf + * Set DSI_INST_ID_DLY to 0x5000 001f + */ + + putreg32(0x30100001, DSI_INST_FUNC_REG(DSI_INST_ID_LPDT)); + putreg32(0x40000010, DSI_INST_FUNC_REG(DSI_INST_ID_HSCEXIT)); + putreg32(0xf, DSI_INST_FUNC_REG(DSI_INST_ID_NOP)); + putreg32(0x5000001f, DSI_INST_FUNC_REG(DSI_INST_ID_DLY)); + + /* Configure Jump Instructions (Undocumented) *****************************/ + + ginfo("Configure Jump Instructions\n"); + + /* DSI Instruction Jump Configuration Register (Undocumented) + * Set DSI_INST_JUMP_CFG to 0x56 0001 + */ + + putreg32(0x560001, DSI_INST_JUMP_CFG_REG(DSI_INST_JUMP_CFG)); + + /* DSI Debug Data Register (Undocumented) + * Set to 0xff + */ + + putreg32(0xff, DSI_DEBUG_DATA_REG); + + /* Set Video Start Delay **************************************************/ + + ginfo("Set Video Start Delay\n"); + + /* DSI Configuration Register 1 (A31 Page 846) + * Set Video_Start_Delay (Bits 4 to 16) to 1468 (Line Delay) + * Set Video_Precision_Mode_Align (Bit 2) to 1 (Fill Mode) + * Set Video_Frame_Start (Bit 1) to 1 (Precision Mode) + * Set DSI_Mode (Bit 0) to 1 (Video Mode) + * Note: Video_Start_Delay is actually 13 bits, not 8 bits as stated + * in A31 User Manual + */ + + dsi_basic_ctl1 = VIDEO_START_DELAY(1468) | + VIDEO_PRECISION_MODE_ALIGN | + VIDEO_FRAME_START | + DSI_MODE; + putreg32(dsi_basic_ctl1, DSI_BASIC_CTL1_REG); + + /* Set Burst (Undocumented) ***********************************************/ + + ginfo("Set Burst\n"); + + /* DSI Timing Controller DRQ Register (Undocumented) + * Set to 0x1000 0007 + */ + + putreg32(0x10000007, DSI_TCON_DRQ_REG); + + /* Set Instruction Loop (Undocumented) ************************************/ + + ginfo("Set Instruction Loop\n"); + + /* DSI Instruction Loop Select Register (Undocumented) + * Set to 0x3000 0002 + */ + + putreg32(0x30000002, DSI_INST_LOOP_SEL_REG); + + /* DSI Instruction Loop Number Register (Undocumented) + * Set Register 0 to 0x31 0031 + * Set Register 1 to 0x31 0031 + */ + + putreg32(0x310031, DSI_INST_LOOP_NUM_REG(0)); + putreg32(0x310031, DSI_INST_LOOP_NUM_REG(1)); + + /* Set Pixel Format *******************************************************/ + + ginfo("Set Pixel Format\n"); + + /* DSI Pixel Package Register 0 (A31 Page 848) + * Set ECC (Bits 24 to 31) to 19 + * Set WC (Bits 8 to 23) to 2160 (Byte Numbers of PD in a Pixel Packet) + * Set VC (Bits 6 to 7) to 0 (Virtual Channel) + * Set DT (Bits 0 to 5) to 0x3E (24-bit Video Mode) + */ + + dsi_pixel_ph = PIXEL_ECC(19) | + PIXEL_WC(2160) | + PIXEL_VC(A64_MIPI_DSI_VIRTUAL_CHANNEL) | + PIXEL_DT(0x3e); + putreg32(dsi_pixel_ph, DSI_PIXEL_PH_REG); + + /* DSI Pixel Package Register 2 (A31 Page 849) + * Set CRC_Force (Bits 0 to 15) to 0xffff (Force CRC to this value) + */ + + putreg32(CRC_FORCE, DSI_PIXEL_PF0_REG); + + /* DSI Pixel Package Register 3 (A31 Page 849) + * Set CRC_Init_LineN (Bits 16 to 31) to 0xffff + * (CRC initial to this value in transmitions except 1st one) + * Set CRC_Init_Line0 (Bits 0 to 15) to 0xffff + * (CRC initial to this value in 1st transmition every frame) + */ + + dsi_pixel_pf1 = CRC_INIT_LINEN(0XFFFF) | CRC_INIT_LINE0(0XFFFF); + putreg32(dsi_pixel_pf1, DSI_PIXEL_PF1_REG); + + /* DSI Pixel Format Register 0 (A31 Page 847) + * Set PD_Plug_Dis (Bit 16) to 1 + * (Disable PD plug before pixel bytes) + * Set Pixel_Endian (Bit 4) to 0 + * (LSB first) + * Set Pixel_Format (Bits 0 to 3) to 8 + * (24-bit RGB888) + */ + + dsi_pixel_ctl0 = PD_PLUG_DIS | PIXEL_ENDIAN | PIXEL_FORMAT(8); + putreg32(dsi_pixel_ctl0, DSI_PIXEL_CTL0_REG); + + /* Set Sync Timings *******************************************************/ + + ginfo("Set Sync Timings\n"); + + /* DSI Basic Control Register (Undocumented) + * Set to 0 + */ + + putreg32(0x0, DSI_BASIC_CTL_REG); + + /* DSI Sync Package Register 0 (A31 Page 850) + * Set ECC (Bits 24 to 31) to 0x12 + * Set D1 (Bits 16 to 23) to 0 + * Set D0 (Bits 8 to 15) to 0 + * Set VC (Bits 6 to 7) to 0 (Virtual Channel) + * Set DT (Bits 0 to 5) to 0x21 (HSS) + */ + + dsi_sync_hss = SYNC_ECC(0x12) | + SYNC_D1(0) | + SYNC_D0(0) | + SYNC_VC(A64_MIPI_DSI_VIRTUAL_CHANNEL) | + SYNC_DT(0x21); + putreg32(dsi_sync_hss, DSI_SYNC_HSS_REG); + + /* DSI Sync Package Register 1 (A31 Page 850) + * Set ECC (Bits 24 to 31) to 1 + * Set D1 (Bits 16 to 23) to 0 + * Set D0 (Bits 8 to 15) to 0 + * Set VC (Bits 6 to 7) to 0 (Virtual Channel) + * Set DT (Bits 0 to 5) to 0x31 (HSE) + */ + + dsi_sync_hse = SYNC_ECC(1) | + SYNC_D1(0) | + SYNC_D0(0) | + SYNC_VC(A64_MIPI_DSI_VIRTUAL_CHANNEL) | + SYNC_DT(0x31); + putreg32(dsi_sync_hse, DSI_SYNC_HSE_REG); + + /* DSI Sync Package Register 2 (A31 Page 851) + * Set ECC (Bits 24 to 31) to 7 + * Set D1 (Bits 16 to 23) to 0 + * Set D0 (Bits 8 to 15) to 0 + * Set VC (Bits 6 to 7) to 0 (Virtual Channel) + * Set DT (Bits 0 to 5) to 1 (VSS) + */ + + dsi_sync_vss = SYNC_ECC(7) | + SYNC_D1(0) | + SYNC_D0(0) | + SYNC_VC(A64_MIPI_DSI_VIRTUAL_CHANNEL) | + SYNC_DT(1); + putreg32(dsi_sync_vss, DSI_SYNC_VSS_REG); + + /* DSI Sync Package Register 3 (A31 Page 851) + * Set ECC (Bits 24 to 31) to 0x14 + * Set D1 (Bits 16 to 23) to 0 + * Set D0 (Bits 8 to 15) to 0 + * Set VC (Bits 6 to 7) to 0 (Virtual Channel) + * Set DT (Bits 0 to 5) to 0x11 (VSE) + */ + + dsi_sync_vse = SYNC_ECC(0x14) | + SYNC_D1(0) | + SYNC_D0(0) | + SYNC_VC(A64_MIPI_DSI_VIRTUAL_CHANNEL) | + SYNC_DT(0x11); + putreg32(dsi_sync_vse, DSI_SYNC_VSE_REG); + + /* Set Basic Size *********************************************************/ + + ginfo("Set Basic Size\n"); + + /* DSI Line Number Register 0 (A31 Page 847) + * Set Video_VBP (Bits 16 to 27) to 17 + * Set Video_VSA (Bits 0 to 11) to 10 + */ + + dsi_basic_size0 = VIDEO_VBP(17) | VIDEO_VSA(10); + putreg32(dsi_basic_size0, DSI_BASIC_SIZE0_REG); + + /* DSI Line Number Register 1 (A31 Page 847) + * Set Video_VT (Bits 16 to 28) to 1485 + * Set Video_VACT (Bits 0 to 11) to 1440 + */ + + dsi_basic_size1 = VIDEO_VT(1485) | VIDEO_VACT(1440); + putreg32(dsi_basic_size1, DSI_BASIC_SIZE1_REG); + + /* Set Horizontal Blanking ************************************************/ + + ginfo("Set Horizontal Blanking\n"); + + /* DSI Blank Package Register 0 (A31 Page 852) + * Set HSA_PH (Bits 0 to 31) to 0x900 4a19 + */ + + putreg32(0x9004a19, DSI_BLK_HSA0_REG); + + /* DSI Blank Package Register 1 (A31 Page 852) + * Set HSA_PF (Bits 16 to 31) to 0x50b4 + * Set HSA_PD (Bits 0 to 7) to 0 + */ + + dsi_blk_hsa1 = HSA_PF(0x50b4) | HSA_PD(0); + putreg32(dsi_blk_hsa1, DSI_BLK_HSA1_REG); + + /* DSI Blank Package Register 2 (A31 Page 852) + * Set HBP_PH (Bits 0 to 31) to 0x3500 5419 + */ + + putreg32(0x35005419, DSI_BLK_HBP0_REG); + + /* DSI Blank Package Register 3 (A31 Page 852) + * Set HBP_PF (Bits 16 to 31) to 0x757a + * Set HBP_PD (Bits 0 to 7) to 0 + */ + + dsi_blk_hbp1 = HBP_PF(0x757a) | HBP_PD(0); + putreg32(dsi_blk_hbp1, DSI_BLK_HBP1_REG); + + /* DSI Blank Package Register 4 (A31 Page 852) + * Set HFP_PH (Bits 0 to 31) to 0x900 4a19 + */ + + putreg32(0x9004a19, DSI_BLK_HFP0_REG); + + /* DSI Blank Package Register 5 (A31 Page 853) + * Set HFP_PF (Bits 16 to 31) to 0x50b4 + * Set HFP_PD (Bits 0 to 7) to 0 + */ + + dsi_blk_hfp1 = HFP_PF(0x50b4) | HFP_PD(0); + putreg32(dsi_blk_hfp1, DSI_BLK_HFP1_REG); + + /* DSI Blank Package Register 6 (A31 Page 853) + * Set HBLK_PH (Bits 0 to 31) to 0xc09 1a19 + */ + + putreg32(0xc091a19, DSI_BLK_HBLK0_REG); + + /* DSI Blank Package Register 7 (A31 Page 853) + * Set HBLK_PF (Bits 16 to 31) to 0x72bd + * Set HBLK_PD (Bits 0 to 7) to 0 + */ + + dsi_blk_hblk1 = HBLK_PF(0x72bd) | HBLK_PD(0); + putreg32(dsi_blk_hblk1, DSI_BLK_HBLK1_REG); + + /* Set Vertical Blanking **************************************************/ + + ginfo("Set Vertical Blanking\n"); + + /* DSI Blank Package Register 8 (A31 Page 854) + * Set VBLK_PH (Bits 0 to 31) to 0x1a00 0019 + */ + + putreg32(0x1a000019, DSI_BLK_VBLK0_REG); + + /* DSI Blank Package Register 9 (A31 Page 854) + * Set VBLK_PF (Bits 16 to 31) to 0xffff + * Set VBLK_PD (Bits 0 to 7) to 0 + */ + + dsi_blk_vblk1 = VBLK_PF(0xffff) | VBLK_PD(0); + putreg32(dsi_blk_vblk1, DSI_BLK_VBLK1_REG); + + return OK; +} + +/**************************************************************************** + * Name: a64_mipi_dsi_start + * + * Description: + * Start the MIPI DSI Bus in High Speed Clock Mode (HSC) for High Speed + * Data Transmission (HSD). Should be called after initializing the LCD + * Controller, and before executing any Display Engine operations. + * Assumes that the MIPI DSI Block has been enabled on the SoC. + * + * Input Parameters: + * None + * + * Returned Value: + * OK is always returned at present. + * + ****************************************************************************/ + +int a64_mipi_dsi_start(void) +{ + /* Start HSC (Undocumented) ***********************************************/ + + ginfo("Start HSC\n"); + + /* DSI Instruction Jump Select Register (Undocumented) + * Set to 0xf02 + */ + + putreg32(0xf02, DSI_INST_JUMP_SEL_REG); + + /* Commit *****************************************************************/ + + ginfo("Commit\n"); + + /* DSI Configuration Register 0 (A31 Page 845) + * Set INSTRU_EN (Bit 0) to 1 + * (Enable DSI Processing from Instruction 0) + */ + + modreg32(INSTRU_EN, INSTRU_EN, DSI_BASIC_CTL0_REG); + + /* Instruction Function Lane (Undocumented) *******************************/ + + ginfo("Instruction Function Lane\n"); + + /* DSI Instruction Function Register (Undocumented) + * Set DSI_INST_FUNC_LANE_CEN (Bit 4) to 0 + */ + + modreg32(0x0, + DSI_INST_FUNC_LANE_CEN, + DSI_INST_FUNC_REG(DSI_INST_ID_LP11)); + + /* Wait 1 millisecond */ + + up_mdelay(1); + + /* Start HSD (Undocumented) ***********************************************/ + + ginfo("Start HSD\n"); + + /* DSI Instruction Jump Select Register (Undocumented) + * Set to 0x63f0 7006 + */ + + putreg32(0x63f07006, DSI_INST_JUMP_SEL_REG); + + /* Commit *****************************************************************/ + + ginfo("Commit\n"); + + /* DSI Configuration Register 0 (A31 Page 845) + * Set INSTRU_EN (Bit 0) to 1 + * (Disable DSI Processing) + */ + + modreg32(INSTRU_EN, INSTRU_EN, DSI_BASIC_CTL0_REG); + + return OK; +} diff --git a/arch/arm64/src/a64/a64_mipi_dsi.h b/arch/arm64/src/a64/a64_mipi_dsi.h new file mode 100644 index 00000000000..1b679bab3f6 --- /dev/null +++ b/arch/arm64/src/a64/a64_mipi_dsi.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * arch/arm64/src/a64/a64_mipi_dsi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_A64_A64_MIPI_DSI_H +#define __ARCH_ARM64_SRC_A64_A64_MIPI_DSI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/a64_memorymap.h" +#include "mipi_dsi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Virtual Channel to be used for data transfer on the MIPI DSI Bus */ + +#define A64_MIPI_DSI_VIRTUAL_CHANNEL 0 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: a64_mipi_dsi_enable + * + * Description: + * Enable the MIPI DSI Block on the SoC. Should be called before + * transferring data on the MIPI DSI Bus. + * + * Input Parameters: + * None + * + * Returned Value: + * OK is always returned at present. + * + ****************************************************************************/ + +int a64_mipi_dsi_enable(void); + +/**************************************************************************** + * Name: a64_mipi_dsi_write + * + * Description: + * Transmit the payload data to the MIPI DSI Bus as a MIPI DSI Short or + * Long Packet. This function is called to initialize the LCD Controller. + * Assumes that the MIPI DSI Block has been enabled on the SoC. + * + * Input Parameters: + * channel - Virtual Channel + * cmd - DCS Command (Data Type) + * txbuf - Payload data for the packet + * txlen - Length of payload data (Max 65541 bytes) + * + * Returned Value: + * Number of bytes transmitted; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +ssize_t a64_mipi_dsi_write(uint8_t channel, + enum mipi_dsi_e cmd, + FAR const uint8_t *txbuf, + size_t txlen); + +/**************************************************************************** + * Name: a64_mipi_dsi_start + * + * Description: + * Start the MIPI DSI Bus in High Speed Clock Mode (HSC) for High Speed + * Data Transmission (HSD). Should be called after initializing the LCD + * Controller, and before executing any Display Engine operations. + * Assumes that the MIPI DSI Block has been enabled on the SoC. + * + * Input Parameters: + * None + * + * Returned Value: + * OK is always returned at present. + * + ****************************************************************************/ + +int a64_mipi_dsi_start(void); + +#endif /* __ARCH_ARM64_SRC_A64_A64_MIPI_DSI_H */ diff --git a/arch/arm64/src/a64/hardware/a64_memorymap.h b/arch/arm64/src/a64/hardware/a64_memorymap.h index 72d012935af..fd7c9db88d7 100644 --- a/arch/arm64/src/a64/hardware/a64_memorymap.h +++ b/arch/arm64/src/a64/hardware/a64_memorymap.h @@ -33,7 +33,10 @@ /* Peripheral Base Addresses */ +#define A64_CCU_ADDR 0x01c20000 /* CCU 0x01c2:0000-0x01c2:03ff 1K */ #define A64_PIO_ADDR 0x01c20800 /* PIO 0x01c2:0800-0x01c2:0bff 1K */ +#define A64_DSI_ADDR 0x01ca0000 /* MIPI DSI 0x01ca:0000-0x01ca:0fff 4K */ +#define A64_DPHY_ADDR 0x01ca1000 /* MIPI DSI-PHY 0x01ca:1000-0x01ca:1fff 4K */ #define A64_RPIO_ADDR 0x01f02c00 /* R_PIO 0x01f0:2c00-0x01f0:2fff 1K */ /**************************************************************************** diff --git a/arch/arm64/src/a64/mipi_dsi.c b/arch/arm64/src/a64/mipi_dsi.c new file mode 100644 index 00000000000..f89b34f1d9c --- /dev/null +++ b/arch/arm64/src/a64/mipi_dsi.c @@ -0,0 +1,386 @@ +/**************************************************************************** + * arch/arm64/src/a64/mipi_dsi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Reference: + * + * "Understanding PinePhone's Display (MIPI DSI)" + * https://lupyuen.github.io/articles/dsi + * + * "NuttX RTOS for PinePhone: Display Driver in Zig" + * https://lupyuen.github.io/articles/dsi2 + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "mipi_dsi.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: compute_crc + * + * Description: + * Compute the MIPI DSI CRC for the data buffer. + * + * Input Parameters: + * data - Data buffer + * len - Length of data buffer + * + * Returned Value: + * MIPI DSI CRC value of the data buffer + * + ****************************************************************************/ + +static uint16_t compute_crc(const uint8_t *data, size_t len) +{ + uint16_t crc; + + /* Compute CRC-16-CCITT (x^16+x^12+x^5+1) */ + + DEBUGASSERT(data != NULL); + crc = crc16ccittpart(data, len, 0xffff); + + return crc; +} + +/**************************************************************************** + * Name: compute_ecc + * + * Description: + * Compute the MIPI DSI Error Correction Code (ECC) for the 3-byte + * Packet Header. The ECC allows single-bit errors to be corrected and + * 2-bit errors to be detected in the MIPI DSI Packet Header. + * + * Input Parameters: + * di_wc - Packet Header (Data Identifier + Word Count) + * len - Length of Packet Header (Should be 3 bytes) + * + * Returned Value: + * MIPI DSI ECC value of the Packet Header + * + ****************************************************************************/ + +static uint8_t compute_ecc(const uint8_t *di_wc, size_t len) +{ + uint32_t di_wc_word; + bool d[24]; + bool ecc[8]; + int i; + + /* Packet Header should be exactly 3 bytes */ + + DEBUGASSERT(di_wc != NULL); + if (len != 3) + { + DEBUGPANIC(); + return 0; + } + + /* Combine Data Identifier and Word Count into a 24-bit word */ + + di_wc_word = di_wc[0] | (di_wc[1] << 8) | (di_wc[2] << 16); + + /* Extract the 24 bits from the word */ + + memset(d, 0, sizeof(d)); + for (i = 0; i < 24; i++) + { + d[i] = di_wc_word & 1; + di_wc_word >>= 1; + } + + /* Compute the ECC bits */ + + memset(ecc, 0, sizeof(ecc)); + ecc[7] = 0; + ecc[6] = 0; + ecc[5] = d[10] ^ d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ + d[18] ^ d[19] ^ d[21] ^ d[22] ^ d[23]; + ecc[4] = d[4] ^ d[5] ^ d[6] ^ d[7] ^ d[8] ^ d[9] ^ d[16] ^ d[17] ^ + d[18] ^ d[19] ^ d[20] ^ d[22] ^ d[23]; + ecc[3] = d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9] ^ d[13] ^ d[14] ^ + d[15] ^ d[19] ^ d[20] ^ d[21] ^ d[23]; + ecc[2] = d[0] ^ d[2] ^ d[3] ^ d[5] ^ d[6] ^ d[9] ^ d[11] ^ d[12] ^ + d[15] ^ d[18] ^ d[20] ^ d[21] ^ d[22]; + ecc[1] = d[0] ^ d[1] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[10] ^ d[12] ^ + d[14] ^ d[17] ^ d[20] ^ d[21] ^ d[22] ^ d[23]; + ecc[0] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[5] ^ d[7] ^ d[10] ^ d[11] ^ + d[13] ^ d[16] ^ d[20] ^ d[21] ^ d[22] ^ d[23]; + + /* Merge the ECC bits */ + + return ecc[0] | (ecc[1] << 1) | (ecc[2] << 2) | (ecc[3] << 3) | + (ecc[4] << 4) | (ecc[5] << 5) | (ecc[6] << 6) | (ecc[7] << 7); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mipi_dsi_long_packet + * + * Description: + * Compose a MIPI DSI Long Packet. A Short Packet consists of Data + * Identifier (Virtual Channel + Data Type), Word Count (Payload Size), + * Error Correction Code, Payload and Checksum. Packet Length is + * Payload Size + 6 bytes. + * + * Input Parameters: + * pktbuf - Buffer for the returned packet + * pktlen - Size of the packet buffer + * channel - Virtual Channel + * cmd - DCS Command (Data Type) + * txbuf - Payload data for the packet + * txlen - Length of payload data (Max 65541 bytes) + * + * Returned Value: + * Number of bytes in the returned packet; ERROR (-1) if packet buffer is + * too small for the packet + * + ****************************************************************************/ + +ssize_t mipi_dsi_long_packet(uint8_t *pktbuf, + size_t pktlen, + uint8_t channel, + enum mipi_dsi_e cmd, + const uint8_t *txbuf, + size_t txlen) +{ + /* Data Identifier (DI) (1 byte): + * Virtual Channel Identifier (Bits 6 to 7) + * Data Type (Bits 0 to 5) + */ + + const uint8_t vc = channel; + const uint8_t dt = cmd; + const uint8_t di = (vc << 6) | dt; + + /* Word Count (WC) (2 bytes): + * Number of bytes in the Packet Payload + */ + + const uint16_t wc = txlen; + const uint8_t wcl = wc & 0xff; + const uint8_t wch = wc >> 8; + + /* Data Identifier + Word Count (3 bytes): + * For computing Error Correction Code (ECC) + */ + + const uint8_t di_wc[3] = + { + di, + wcl, + wch + }; + + /* Compute ECC for Data Identifier + Word Count */ + + const uint8_t ecc = compute_ecc(di_wc, sizeof(di_wc)); + + /* Packet Header (4 bytes): + * Data Identifier + Word Count + Error Correction Code + */ + + const uint8_t header[4] = + { + di_wc[0], + di_wc[1], + di_wc[2], + ecc + }; + + /* Checksum (CS) (2 bytes): + * 16-bit Cyclic Redundancy Check (CRC) of the Payload + * (Not the entire packet) + */ + + const uint16_t cs = compute_crc(txbuf, txlen); + const uint8_t csl = cs & 0xff; + const uint8_t csh = cs >> 8; + + /* Packet Footer (2 bytes): + * Checksum (CS) + */ + + const uint8_t footer[2] = + { + csl, + csh + }; + + /* Packet Length: + * Packet Header (4 bytes) + * Payload (txlen bytes) + * Packet Footer (2 bytes) + */ + + const size_t len = sizeof(header) + txlen + sizeof(footer); + + ginfo("channel=%d, cmd=0x%x, txlen=%ld\n", channel, cmd, txlen); + DEBUGASSERT(pktbuf != NULL && txbuf != NULL); + DEBUGASSERT(channel < 4); + DEBUGASSERT(cmd < (1 << 6)); + + if (txlen > 65541) /* Max 65,541 bytes for payload */ + { + DEBUGPANIC(); + return ERROR; + } + + if (len > pktlen) /* Packet Buffer too small */ + { + DEBUGPANIC(); + return ERROR; + } + + /* Copy Packet Header, Payload, Packet Footer to Packet Buffer */ + + memcpy(pktbuf, header, sizeof(header)); + memcpy(pktbuf + sizeof(header), txbuf, txlen); + memcpy(pktbuf + sizeof(header) + txlen, footer, sizeof(footer)); + + /* Return the Packet Length */ + + return len; +} + +/**************************************************************************** + * Name: mipi_dsi_short_packet + * + * Description: + * Compose a MIPI DSI Short Packet. A Short Packet consists of Data + * Identifier (Virtual Channel + Data Type), Data (1 or 2 bytes) and + * Error Correction Code. Packet Length is 4 bytes. + * + * Input Parameters: + * pktbuf - Buffer for the returned packet + * pktlen - Size of the packet buffer + * channel - Virtual Channel + * cmd - DCS Command (Data Type) + * txbuf - Payload data for the packet + * txlen - Length of payload data (1 or 2 bytes) + * + * Returned Value: + * Number of bytes in the returned packet; ERROR (-1) if packet buffer is + * too small for the packet + * + ****************************************************************************/ + +ssize_t mipi_dsi_short_packet(uint8_t *pktbuf, + size_t pktlen, + uint8_t channel, + enum mipi_dsi_e cmd, + const uint8_t *txbuf, + size_t txlen) +{ + /* A Short Packet consists of 8-bit Data Identifier (DI), + * 2 bytes of commands or data, and 8-bit ECC. + * The length of a short packet is 4 bytes including ECC. + * Thus a MIPI DSI Short Packet (compared with Long Packet): + * - Doesn't have Packet Payload and Packet Footer (CRC) + * - Instead of Word Count (WC), the Packet Header now has 2 bytes of data + * Everything else is the same. + */ + + /* Data Identifier (DI) (1 byte): + * Virtual Channel Identifier (Bits 6 to 7) + * Data Type (Bits 0 to 5) + */ + + const uint8_t vc = channel; + const uint8_t dt = cmd; + const uint8_t di = (vc << 6) | dt; + + /* Data (2 bytes): Fill with 0 if Second Byte is missing */ + + const uint8_t data[2] = + { + txbuf[0], /* First Byte */ + (txlen == 2) ? txbuf[1] : 0, /* Second Byte */ + }; + + /* Data Identifier + Data (3 bytes): + * For computing Error Correction Code (ECC) + */ + + const uint8_t di_data[3] = + { + di, + data[0], + data[1] + }; + + /* Compute ECC for Data Identifier + Word Count */ + + const uint8_t ecc = compute_ecc(di_data, sizeof(di_data)); + + /* Packet Header (4 bytes): + * Data Identifier + Data + Error Correction Code + */ + + const uint8_t header[4] = + { + di_data[0], + di_data[1], + di_data[2], + ecc + }; + + /* Packet Length is Packet Header Size (4 bytes) */ + + const size_t len = sizeof(header); + + ginfo("channel=%d, cmd=0x%x, txlen=%ld\n", channel, cmd, txlen); + DEBUGASSERT(pktbuf != NULL && txbuf != NULL); + DEBUGASSERT(channel < 4); + DEBUGASSERT(cmd < (1 << 6)); + + if (txlen < 1 || txlen > 2) /* Payload should be 1 or 2 bytes */ + { + DEBUGPANIC(); + return ERROR; + } + + if (len > pktlen) /* Packet Buffer too small */ + { + DEBUGPANIC(); + return ERROR; + } + + /* Copy Packet Header to Packet Buffer */ + + memcpy(pktbuf, header, sizeof(header)); /* 4 bytes */ + + /* Return the Packet Length */ + + return len; +} diff --git a/arch/arm64/src/a64/mipi_dsi.h b/arch/arm64/src/a64/mipi_dsi.h new file mode 100644 index 00000000000..913b0715cb9 --- /dev/null +++ b/arch/arm64/src/a64/mipi_dsi.h @@ -0,0 +1,108 @@ +/**************************************************************************** + * arch/arm64/src/a64/mipi_dsi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_A64_MIPI_DSI_H +#define __ARCH_ARM64_SRC_A64_MIPI_DSI_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* MIPI DSI Processor-to-Peripheral Transaction Types */ + +enum mipi_dsi_e +{ + /* DCS Short Write (Without Parameter) */ + + MIPI_DSI_DCS_SHORT_WRITE = 0x05, + + /* DCS Short Write (With Parameter) */ + + MIPI_DSI_DCS_SHORT_WRITE_PARAM = 0x15, + + /* DCS Long Write */ + + MIPI_DSI_DCS_LONG_WRITE = 0x39 +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: mipi_dsi_long_packet + * + * Description: + * Compose a MIPI DSI Long Packet. A Short Packet consists of Data + * Identifier (Virtual Channel + Data Type), Word Count (Payload Size), + * Error Correction Code, Payload and Checksum. Packet Length is + * Payload Size + 6 bytes. + * + * Input Parameters: + * pktbuf - Buffer for the returned packet + * pktlen - Size of the packet buffer + * channel - Virtual Channel + * cmd - DCS Command (Data Type) + * txbuf - Payload data for the packet + * txlen - Length of payload data (Max 65541 bytes) + * + * Returned Value: + * Number of bytes in the returned packet; ERROR (-1) if packet buffer is + * too small for the packet + * + ****************************************************************************/ + +ssize_t mipi_dsi_long_packet(uint8_t *pktbuf, + size_t pktlen, + uint8_t channel, + enum mipi_dsi_e cmd, + const uint8_t *txbuf, + size_t txlen); + +/**************************************************************************** + * Name: mipi_dsi_short_packet + * + * Description: + * Compose a MIPI DSI Short Packet. A Short Packet consists of Data + * Identifier (Virtual Channel + Data Type), Data (1 or 2 bytes) and + * Error Correction Code. Packet Length is 4 bytes. + * + * Input Parameters: + * pktbuf - Buffer for the returned packet + * pktlen - Size of the packet buffer + * channel - Virtual Channel + * cmd - DCS Command (Data Type) + * txbuf - Payload data for the packet + * txlen - Length of payload data (1 or 2 bytes) + * + * Returned Value: + * Number of bytes in the returned packet; ERROR (-1) if packet buffer is + * too small for the packet + * + ****************************************************************************/ + +ssize_t mipi_dsi_short_packet(uint8_t *pktbuf, + size_t pktlen, + uint8_t channel, + enum mipi_dsi_e cmd, + const uint8_t *txbuf, + size_t txlen); + +#endif /* __ARCH_ARM64_SRC_A64_MIPI_DSI_H */ diff --git a/include/nuttx/crc16.h b/include/nuttx/crc16.h index 2d83fd5973f..328f2b02265 100644 --- a/include/nuttx/crc16.h +++ b/include/nuttx/crc16.h @@ -68,6 +68,29 @@ uint16_t crc16part(FAR const uint8_t *src, size_t len, uint16_t crc16val); uint16_t crc16(FAR const uint8_t *src, size_t len); +/**************************************************************************** + * Name: crc16ccittpart + * + * Description: + * Continue 16-bit CRC-CCITT calculation on a part of the buffer using the + * polynomial x^16+x^12+x^5+1. + * + ****************************************************************************/ + +uint16_t crc16ccittpart(FAR const uint8_t *src, size_t len, + uint16_t crc16val); + +/**************************************************************************** + * Name: crc16ccitt + * + * Description: + * Return a 16-bit CRC-CCITT of the contents of the 'src' buffer, length + * 'len' using the polynomial x^16+x^12+x^5+1. + * + ****************************************************************************/ + +uint16_t crc16ccitt(FAR const uint8_t *src, size_t len); + #undef EXTERN #ifdef __cplusplus } diff --git a/libs/libc/misc/Make.defs b/libs/libc/misc/Make.defs index d196ddedf96..c01d1377c00 100644 --- a/libs/libc/misc/Make.defs +++ b/libs/libc/misc/Make.defs @@ -36,8 +36,9 @@ endif # Add the miscellaneous C files to the build CSRCS += lib_dumpbuffer.c lib_dumpvbuffer.c lib_fnmatch.c lib_debug.c -CSRCS += lib_crc64.c lib_crc32.c lib_crc16.c lib_crc8.c lib_crc8ccitt.c -CSRCS += lib_crc8table.c lib_glob.c lib_execinfo.c lib_ftok.c lib_err.c +CSRCS += lib_crc64.c lib_crc32.c lib_crc16.c lib_crc16ccitt.c lib_crc8.c +CSRCS += lib_crc8ccitt.c lib_crc8table.c lib_glob.c lib_execinfo.c +CSRCS += lib_ftok.c lib_err.c # Keyboard driver encoder/decoder diff --git a/libs/libc/misc/lib_crc16ccitt.c b/libs/libc/misc/lib_crc16ccitt.c new file mode 100644 index 00000000000..9612823561f --- /dev/null +++ b/libs/libc/misc/lib_crc16ccitt.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * libs/libc/misc/lib_crc16ccitt.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* From CRC-16-CCITT (x^16+x^12+x^5+1) */ + +static uint16_t crc16ccitt_tab[256] = +{ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: crc16ccittpart + * + * Description: + * Continue 16-bit CRC-CCITT calculation on a part of the buffer using the + * polynomial x^16+x^12+x^5+1. + * + ****************************************************************************/ + +uint16_t crc16ccittpart(FAR const uint8_t *src, size_t len, + uint16_t crc16val) +{ + size_t i; + uint16_t v = crc16val; + + for (i = 0; i < len; i++) + { + v = (v >> 8) ^ crc16ccitt_tab[(v ^ src[i]) & 0xff]; + } + + return v; +} + +/**************************************************************************** + * Name: crc16ccitt + * + * Description: + * Return a 16-bit CRC-CCITT of the contents of the 'src' buffer, length + * 'len' using the polynomial x^16+x^12+x^5+1. + * + ****************************************************************************/ + +uint16_t crc16ccitt(FAR const uint8_t *src, size_t len) +{ + return crc16ccittpart(src, len, 0); +}