레이블이 SoC-IMX8인 게시물을 표시합니다. 모든 게시물 표시
레이블이 SoC-IMX8인 게시물을 표시합니다. 모든 게시물 표시

1/09/2021

Android USB 설정 및 USB Type C

 1. USB Device Tree 설정분석 


USB OTG Device Tree 관련내용 


Chapter 14 Connectivity Subsystem



  • USB 분석이유 
USB Device Tree를 다시 분석하는 이유는 USB Type-C가 지원이 되면서, HW 구조가 변경이 되어 개인적으로 이 부분을 정확히 이해하려고 한다. 
i.MX8QXP의 EVM의 경우 아래와 같이 사용하고 있지만, 현재 OTG1/2만 사용하고자 하면 이 구조를 변경을 해야한다. 
  1. OTG1: OTG 사용   
  2. OTG2/OTG3: USB Type-C  (USB 2.0 과 USB 3.0 동시 필요)

USB 3.0 TypeC 의 경우 Cadence 것을 가져다 쓰며, 아래와 같이 AMBA에서 APB/AXI4로 연결하여 사용되어지고 있다. 
중간에 MUX에 의해 Host or Device 선택되어지면, 이는 OTG에 의해서 결정될 것이다. 
(참고로 USB 2.0 OTG의 경우, 대체적으로 dwc or hdrc )

14.12.2 Functional Description





변경하고자 하는 HW
OTG1 과 OTG2만 USB 2.0 사용할 경우 재미있는 것은 상위 OTG1/2만 사용할 경우 OTG가 잘동작하지 않아 이를 HW로 ID 핀으로 Device or Host 설정을 한 후 사용예정 


$ vi ./vendor/nxp-opensource/kernel_imx/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi

/*
    USB OTG일 경우  i.MX series는 /sys file에 ci_hdrc.0 만 생성되며, ci_hdrc.1 은 찾아볼수 없음 
    i.MX8은 i.MX6 다르게, OTG Hardware는 두개지만 내부적 OTG2는 USB3를 위해서으로 분할되어 있음
    
    Device Tree 주소와 같이 보자 
    
  2.2.2 Connectivity Memory Maps
     5B28_0000 : LPCG USB3           (현재 미사용 추측) 
     5B27_0000 : LPCG USB2           (현재 미사용 추측)
     5B16_0000 : USB3_PHY3P0  (OTG3/2) 
     5B12_0000 : USB3         (OTG3/2) 
     5B11_0000 : USB3_CTRL    (OTG3/2) 
     5B10_0000 : USBOH_PHY    (OTG1)
     5B0F_0000 : USBOH_PL301         (현재 미사용 추측)
     5B0D_0000 : USBOH_OTG    (OTG1) 
*/

  https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt
  
	usbotg1: usb@5b0d0000 {
		compatible = "fsl,imx8qm-usb", "fsl,imx7ulp-usb",
			"fsl,imx27-usb";
		reg = <0x5b0d0000 0x200>;
		interrupt-parent = <&gic>;
		interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
		fsl,usbphy = <&usbphy1>;
		fsl,usbmisc = <&usbmisc1 0>;
		clocks = <&usb2_lpcg 0>;
		ahb-burst-config = <0x0>;
		tx-burst-size-dword = <0x10>;
		rx-burst-size-dword = <0x10>;
		power-domains = <&pd IMX_SC_R_USB_0>;
		status = "disabled";
	};

/*
    Datasheet를 보면, OTG Hardware는 2개가 다른 곳에 있으며, 이 것을 OTG1/2 분할 해서 사용해야 할 것같다.  
    구성은 좀 재미있으며, Datasheet를 비교해봐도 i.MX6와 완전다르다 
    
OTG1의 구성을 세부적으로 Datasheet와 같이 분석 
    
  14.10.3.1.1 Configuration, Control and Status Register Set 구성 (5B0D_0000 : USBOH_OTG )  
       - UOG1 (OTG1) : 3개다 동일 offset 이며, 공통 OTG 기능 목적으로 사용되는 것으로 추측 
       - UOG2 (OTG2)
       - UH   (USB Host)
      USB Core RegisterUSB Non Core Register가 구분               
      
  14.10.4 USB Non-Core Memory Map/Register Definition        (5B0D_0000 : USBOH_OTG )
      Non Core Register들로 추가적으로 의존적인 부분이라고 하는데, 공유목적으로 분리사용하는것으로 추측
        - 5b0d0200 : USBNC_OTG1_CTRL1  Non-Core Control
        - 5b0d1200 : USBNC_OTG2_CTRL1         
        - 5b0d2200 : USBNC_UH_CTRL1        
        ** usbmisc 사용    
        
  14.10.5 USB Core Memory Map/Register Definition      (5B0D_0000 : USBOH_OTG )
       USB Core Register들은 USB Core Function Control과 독립적인 기능역할을 해서 분리 
        상위 14.10.3.1.1 Configuration, Control and Status Register Set 과 동일         
*/
  https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/usb/usbmisc-imx.txt

	usbmisc1: usbmisc@5b0d0200 {
		#index-cells = <1>;
		compatible = "fsl,imx7ulp-usbmisc", "fsl,imx6q-usbmisc";
		reg = <0x5b0d0200 0x200>;
	};

  https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt
  
	usbphy1: usbphy@5b100000 {
		compatible = "fsl,imx8qm-usbphy", "fsl,imx7ulp-usbphy",
			"fsl,imx6ul-usbphy", "fsl,imx23-usbphy";
		reg = <0x5b100000 0x1000>;
		clocks = <&usb2_lpcg 1>;
		power-domains = <&pd IMX_SC_R_USB_0_PHY>;
		status = "disabled";
	};
        
/* 
OTG3/2의 구성분석 
   
    USB OTG2는 내부적으로 보면 USB3.0 OTG Controller 위해 존재하며, 상위 OTG1 과 OTG3 Device Driver 완전 다르다. 
    EVM은 사용 상위 OTG2의 Controller가 14.12.6.33 USB2 Port Status and Control (PORTSC1USB2)  존재하는데, 
    EVM을 보면, USB-C Type에 위해서 사용되며, USB 2.0 Phy(OTG) 와 USB 3.0 Phy 때문에 사용한 것으로 파악  
    
    관련내용 14.12.1.1 Features Reference Manual
    - 전압도 12V 와 5V로 구조로 분리되어 동작 (추후 시간이되면, USB3.0 회로구성을 다시 한번 세부 분석해야겠음)
    - 현재 아래는 USB Type-C 사용할때 3.0 와 2.0을 같이 사용하기 위한 전용 Controller로 생각되며, 
      처음 OTG1/2만 사용할 경우 필요 없을 것이라고 생각했지만, 분석 후 아래의 otg3도 같이 사용할 필요할 것으로 파악. 
*/

	usb3phynop1: usb3-phy {
		compatible = "usb-nop-xceiv";
		clocks = <&usb3_lpcg 4>;
		clock-names = "main_clk";
		power-domains = <&pd IMX_SC_R_USB_2_PHY>;
		status = "disabled";
	};

/*     
OTG3/2의 구성을 세부적으로 Datasheet와 Driver 같이 분석 
   
  14.12.6.1 Core Registers Memory map   (5B12_0000 : USB3       0x5B130000,  0x5B140000)
      USB Core Register들은 USB Core Function Control과 독립적인 기능역할을 해서 분리
        - 5B120058 :  OTGCTRL1     Core Control
        - 5B12005C :  OTGCTRL2
        
        - 5B130480 :  PORTSC1USB2  xhci_regs
        - 5B130490 :  PORTSC1USB3  xhci_regs 
   
  14.12.7.1 Non-Core Registers Memory map (5B11_0000 : USB3_CTRL )     
      Non Core Register들로 추가적으로 의존적인 부분이라고 하는데, 공유목적으로 분리사용하는것으로 추측
  
  https://mjmwired.net/kernel/Documentation/devicetree/bindings/usb/cdns-usb3.txt
  
     ./drivers/usb/cdns3/core.c (현재 상위 USB3 PHY 주소는 아래 정의됨)
        /*
         * Request memory region
         * region-0: nxp wrap registers  : 0x5B110000  none_core_regs           USB3_CTRL 
         * region-1: xHCI                : 0x5B130000  xhci_regs  (core_regs)   USB3 
         * region-2: Peripheral          : 0x5B140000  dev_regs   (core_regs)   USB3 
         * region-3: PHY registers       : 0x5B160000  phy_regs                 USB3_PHY3P0 
         * region-4: OTG registers       : 0x5B120000  otg_regs   (core_regs)   USB3 
         */
         
*/

	usbotg3: usb3@5b110000 {
		compatible = "Cadence,usb3";
		reg = <0x5B110000 0x10000>,
			<0x5B130000 0x10000>,
			<0x5B140000 0x10000>,
			<0x5B160000 0x40000>,
			<0x5B120000 0x10000>;
		interrupt-parent = <&gic>;
		interrupts = <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>;
		clocks = <&usb3_lpcg 1>,
			 <&usb3_lpcg 0>,
			 <&usb3_lpcg 5>,
			 <&usb3_lpcg 2>,
			 <&usb3_lpcg 3>;
		clock-names = "usb3_lpm_clk", "usb3_bus_clk", "usb3_aclk",
			"usb3_ipg_clk", "usb3_core_pclk";
		assigned-clocks = <&clk IMX_SC_R_USB_2 IMX_SC_PM_CLK_PER>,
				  <&clk IMX_SC_R_USB_2 IMX_SC_PM_CLK_MISC>,
				  <&clk IMX_SC_R_USB_2 IMX_SC_PM_CLK_MST_BUS>;
		assigned-clock-rates = <125000000>, <12000000>, <250000000>;
		power-domains = <&pd IMX_SC_R_USB_2>;
		cdns3,usbphy = <&usb3phynop1>;
		status = "disabled";
	};


  • USB Type C 연결구조 및 USB PD 구조 
USB Type C의 경우 아래와 같이 USB2.0 (Unshielded) 과 USB3.0 (Shielded,CBTU02043) 으로 나뉘어진다. 
USB PD(Power Delivery)는 아래의 PTN5150A에 의해서 CC(Configuration Channel) 설정되며, 내부에 Current도 설정가능하므로 추후 다시 한번 살펴보자. 




OTG1/2관련내용 
Device Tree 요약하면 OTG1 설정 과 OTG3 설정(OTG2가 포함) 두개를 다 사용시 자동적으로 OTG1/2를 Switch된다고하며, OTG3를 써야 OTG2도 동작가능


OTG3 관련내용 CDNS-USB3 사용 

$ vi ./vendor/nxp-opensource/kernel_imx/arch/arm64/boot/dts/freescale/imx8x-mek.dtsi
//상위 설정에서 disable 된 것을 okay 재정의하고, USB OTG1,3 관련 세부설정 

&usbphy1 {
	status = "okay";
};

&usbotg1 {
	vbus-supply = <&reg_usb_otg1_vbus>;
	srp-disable;
	hnp-disable;
	adp-disable;
	power-active-high;
	disable-over-current;
	status = "okay";
};

&usb3phynop1 {
	status = "okay";
};

/*
  ptn5110으로 12V/5V 로 USB PD가 지원되는 것으로 보이며, USB Type C (USB3.0) 일 경우 필요 
*/

&usbotg3 {
	dr_mode = "otg";
	extcon = <&ptn5110>;
	status = "okay";
};


  • USB PD(Power Delivery) 구조 
20V 와 5V Switch로 인하여 CC1/CC2 결정과 내부 Current 결정 


PTN5110/PTN5150A (상위 그림참조) 
CC(Configuration Channel) Logic 이라고하며, 두개의 CC1/CC2를 제공 
USB PD를 위해서 12V 와 5V 선택가능한것으로 보이며, 각 Current도 조절가능 각각의 12V/5V Switch는 별도필요

반드시 참조 

기타용어 
  • OCP (Over Current Protection)
  • OPP (Over Power Protection)
  • OVP (Over Voltage Protection)
  • SCP (Short Circuit Protection)
  • OTP (Over Temperature Protection)
  • BOP (Brown Out Protection)


1.1 Kernel Config 분석방법 

Android에서 제공하는 Kernel Config 옵션이 많이 부족한것 같아 관련부분을 점검해보기로 하고, 아래와 같이 Android Config를 설정한 후 
ARM용으로 menuconfig를 실행하여 설정을 비교하기로 하였으며, menuconfig에서 빠진 내용들을 확인했다. 

$ export ARCH=arm64
//$ export CROSS_COMPILE=aarch64-linux-gnu-
//$ export AARCH64_GCC_CROSS_COMPILE=/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/aarch64-linux-gnu-
//$ export AARCH32_GCC_CROSS_COMPILE=/opt/gcc-arm-8.3-2019.03-x86_64-arm-eabi/bin/arm-eabi-
$ make imx_v8_android_defconfig      //이 설정 값 기반으로 .config을 새로 생성 
$ make menuconfig

$ cp .config org_cofig
$ make menuconfig
$ diff .config org_cofig // 비교 후 수정사항을 상위 defconfig에 추가 

$ vi out/target/product/mek_8q/obj/KERNEL_OBJ/.config
$ diff .config out/target/product/mek_8q/obj/KERNEL_OBJ/.config

$ make mrproper  // 내가 설정한 부분 전체 삭제



1.2 Kernel Config 설정 및 확인 


USB OTG 이해 및 USB Gadget의 KERNEL CONFIG 관련내용 



#
# USB Imaging devices
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
# CONFIG_USBIP_CORE is not set
CONFIG_USB_CDNS3=y
CONFIG_USB_CDNS3_GADGET=y
CONFIG_USB_CDNS3_HOST=y
CONFIG_USB_MUSB_HDRC=y
# CONFIG_USB_MUSB_HOST is not set
# CONFIG_USB_MUSB_GADGET is not set
CONFIG_USB_MUSB_DUAL_ROLE=y
......
CONFIG_USB_LIBCOMPOSITE=y
CONFIG_USB_F_ACM=y
CONFIG_USB_F_SS_LB=y
CONFIG_USB_U_SERIAL=y
CONFIG_USB_U_ETHER=y
CONFIG_USB_U_AUDIO=y
CONFIG_USB_F_SERIAL=y
CONFIG_USB_F_OBEX=y
CONFIG_USB_F_NCM=y
CONFIG_USB_F_ECM=y
CONFIG_USB_F_EEM=y
CONFIG_USB_F_SUBSET=y
CONFIG_USB_F_RNDIS=y
CONFIG_USB_F_MASS_STORAGE=y
CONFIG_USB_F_FS=y
CONFIG_USB_F_UAC1=y
CONFIG_USB_F_UAC1_LEGACY=y
CONFIG_USB_F_UAC2=y
CONFIG_USB_F_UVC=y
CONFIG_USB_F_MIDI=y
CONFIG_USB_F_HID=y
CONFIG_USB_F_ACC=y
CONFIG_USB_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_ACM=y
CONFIG_USB_CONFIGFS_OBEX=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
CONFIG_USB_CONFIGFS_ECM_SUBSET=y
CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_EEM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_LB_SS=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_F_UAC1=y
CONFIG_USB_CONFIGFS_F_UAC1_LEGACY=y
CONFIG_USB_CONFIGFS_F_UAC2=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_UVC=y
# CONFIG_USB_CONFIGFS_F_PRINTER is not set
CONFIG_USB_ZERO=m
# CONFIG_USB_ZERO_HNPTEST is not set
CONFIG_USB_AUDIO=m
# CONFIG_GADGET_UAC1 is not set
CONFIG_USB_ETH=m
CONFIG_USB_ETH_RNDIS=y
# CONFIG_USB_ETH_EEM is not set
# CONFIG_USB_G_NCM is not set
# CONFIG_USB_GADGETFS is not set            //필요할 것이라고 생각했는데, 판단미스 
# CONFIG_USB_FUNCTIONFS is not set          //필요할 것이라고 생각했는데, 판단미스
CONFIG_USB_MASS_STORAGE=m
CONFIG_USB_G_SERIAL=m
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_G_PRINTER is not set
# CONFIG_USB_CDC_COMPOSITE is not set
# CONFIG_USB_G_ACM_MS is not set
# CONFIG_USB_G_MULTI is not set
# CONFIG_USB_G_HID is not set
# CONFIG_USB_G_DBGP is not set
# CONFIG_USB_G_WEBCAM is not set
# CONFIG_USB_RAW_GADGET is not set
# CONFIG_TYPEC is not set
CONFIG_USB_ROLE_SWITCH=y


2. Android init.usb.rc (USB Gadget 수정)  


Android init.rc 문법 

Android에서는 init.rc 문법기반으로 Gadget ConfigFS 기반로 쉽게 USB Gadget들의 상태를 변경가능

  • USB Gadget(Device) 모드 설정 
Chip Vendor init.usb.rc 설정으로 실제 저장되는 곳은 /vendor/etc/init/hw/init.freescale.usb.rc 
$ vi ./device/fsl/imx8q/mek_8q/init.usb.rc
on early-boot
# USG Config FS을 이용하여 직접 init.rc에서 Gadget을 설정가능 
    mount configfs none /config
    mkdir /config/usb_gadget/g1 0770
    mkdir /config/usb_gadget/g1/strings/0x409 0770
    write /config/usb_gadget/g1/bcdUSB 0x0200
    write /config/usb_gadget/g1/idVendor 0x18d1
    write /config/usb_gadget/g1/bcdDevice 0x0440
    write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
    write /config/usb_gadget/g1/strings/0x409/manufacturer ${ro.product.manufacturer}
    write /config/usb_gadget/g1/strings/0x409/product ${ro.product.model}
    mkdir /config/usb_gadget/g1/functions/mass_storage.0
    mkdir /config/usb_gadget/g1/functions/accessory.gs2
    mkdir /config/usb_gadget/g1/functions/audio_source.gs3
    mkdir /config/usb_gadget/g1/functions/rndis.gs4
    mkdir /config/usb_gadget/g1/functions/midi.gs5
    mkdir /config/usb_gadget/g1/functions/ffs.adb
    mkdir /config/usb_gadget/g1/functions/ffs.mtp
    mkdir /config/usb_gadget/g1/functions/ffs.ptp
    mkdir /config/usb_gadget/g1/configs/b.1 0770
    mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770
    write /config/usb_gadget/g1/os_desc/b_vendor_code 0x1
    write /config/usb_gadget/g1/os_desc/qw_sign "MSFT100"
# USB adb  설정 
    mkdir /dev/usb-ffs 0775 shell shell
    mkdir /dev/usb-ffs/adb 0770 shell shell
    mount functionfs adb /dev/usb-ffs/adb rmode=0770,fmode=0660,uid=2000,gid=2000
# USB mtp/ptp device 설정         
    mkdir /dev/usb-ffs/mtp 0770 mtp mtp
    mkdir /dev/usb-ffs/ptp 0770 mtp mtp
    mount functionfs mtp /dev/usb-ffs/mtp rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1
    mount functionfs ptp /dev/usb-ffs/ptp rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1
#
# USB Android property 설정 
#   
   setprop sys.usb.mtp.device_type 3  
  
  # vendor.usb.config 설정하며, USB OTG의 주소 ( Device Tree에서 반드시 확인)   
  # ls /sys/class/udc/ 로 확인가능  
  # otg3 는 현재 Device Tree에서 별도의 Driver로 사용하며, USB3 용  (*hdrc* 가 아님)
  # gadget-cdns3 or 5b110000.usb3 (otg3)
    #setprop vendor.usb.config "5b110000.usb3"  
  #   
  # vendor.usb.config 설정하며, USB OTG의 주소 ( Device Tree에서 반드시 확인)   
  # ls /sys/class/udc/ 로 확인가능  
  # ci_hdrc.0 or 5b0d0000.usb (otg1 ,OTG1/2로 동시사용가능)
  #          
    setprop vendor.usb.config "5b0d0000.usb"
     or
    setprop vendor.usb.config "ci_hdrc.0"      
# Kernel의 libcomposite 관련부분 미사용     
    write /sys/module/libcomposite/parameters/disable_l1_for_hs "y"
# 최종 adb    
    symlink /config/usb_gadget/g1/configs/b.1 /config/usb_gadget/g1/os_desc/b.1

on boot
    setprop sys.usb.configfs 2
    #jhlee (추가후 RNDIS Window 10 존재하나, Window 10에서 미인식 )
    #setprop sys.usb.controller "ci_hdrc.0"
    #setprop sys.usb.config rndis,adb
    #setprop sys.usb.configfs 1    
    #setprop sys.usb.configfs 2

  • Android system/core의 init*.rc 내용 
Android에서제공하는 property 상태에 따라 USB Gadget 설정이 변경되며, 이를 확인 
$ vi system/core/rootdir/init.usb.configfs.rc
  https://android.googlesource.com/platform/system/core/+/master/rootdir/init.usb.configfs.rc
  
//sys.usb.config=adb && property:sys.usb.configfs=0 값에 따라 변경   
$ vi system/core/rootdir/init.usb.rc 
  https://android.googlesource.com/platform/system/core/+/master/rootdir/init.usb.rc

현재 /sys/class/android_usb/android0/enable를 이용하여 방법은 이용을 해보지 못했는데, 
/sys/class/android_usb/android0은 존재하지만, 내부에 enable이 현재 생성되지 않음 



  • USB Gadget TEST 방법 
  https://www.kernel.org/doc/html/latest/usb/gadget-testing.html


  • USB Gadget RNDIS 설정시 ip route 와 iptable 설정 


2.1 Android USB Gadget 설정확인 


  • USB Gadget ConfigFS 관련부분 확인 
Android Board에서 Gadget ConfigFS와 설정된 기능 
$ ls -l /config/usb_gadget/g1/
total 0
-rw-r--r--  1 root root 4096 2021-01-05 07:12 UDC
-rw-r--r--  1 root root 4096 1970-01-01 00:00 bDeviceClass
-rw-r--r--  1 root root 4096 1970-01-01 00:00 bDeviceProtocol
-rw-r--r--  1 root root 4096 1970-01-01 00:00 bDeviceSubClass
-rw-r--r--  1 root root 4096 2021-01-01 07:26 bMaxPacketSize0
-rw-r--r--  1 root root 4096 1970-01-01 00:00 bcdDevice
-rw-r--r--  1 root root 4096 1970-01-01 00:00 bcdUSB
drwxr-xr-x  3 root root    0 1970-01-01 00:00 configs
-rw-r--r--  1 root root 4096 2021-01-01 07:26 driver_match_existing_only
drwxr-xr-x 10 root root    0 2021-01-01 05:16 functions
-rw-r--r--  1 root root 4096 1970-01-01 00:00 idProduct
-rw-r--r--  1 root root 4096 1970-01-01 00:00 idVendor
drwxr-xr-x  2 root root    0 1970-01-01 00:00 os_desc
drwxr-xr-x  3 root root    0 1970-01-01 00:00 strings

//상위 RNDIS 설정된 부분이 나오지 않아 Kernel Config 수정  
$ ls /config/usb_gadget/g1/functions/  
accessory.gs2    ffs.adb ffs.ptp        midi.gs5
audio_source.gs3 ffs.mtp mass_storage.0

//KERNEL CONFIG 추가설정
CONFIG_USB_NET_DRIVERS=y
CONFIG_USB_ETH_RNDIS=y

//Kernel Config 수정 후 USB Gadget RNDIS 확인 
$ ls /config/usb_gadget/g1/functions/ 
accessory.gs2    ffs.adb ffs.ptp        midi.gs5
audio_source.gs3 ffs.mtp mass_storage.0 rndis.gs4 

$ ls /sys/module/libcomposite  //현재 미존재하지만, RNDIS 동작확인 


Window 10 RNDIS 미인식문제 (Window 7은 문제없음)

  • Android Property 관련사항 확인 
getprop를 이용하여 현재 설정된 값들을 확인하고 강제로 변경하여 테스트 
$ getprop | grep usb
[init.svc.usb-hal-1-1]: [running]
[init.svc.usbd]: [stopped]
[persist.sys.usb.config]: [adb]
[ro.audio.usb.period_us]: [20000]
[ro.boottime.usb-hal-1-1]: [13786733000]
[ro.boottime.usbd]: [14657327000]
[sys.usb.config]: [adb]
[sys.usb.configfs]: [2]
[sys.usb.controller]: [ci_hdrc.0]
[sys.usb.ffs.ready]: [1]
[sys.usb.mtp.device_type]: [3]
[vendor.usb.config]: [ci_hdrc.0]

//상위의 init.usb.configfs.rc 중 adbd stop  
$ setprop sys.usb.configfs 1
$ setprop sys.usb.config none
$ setprop sys.usb.configfs 2

//상위의 init.usb.rc 중 rndis,adb 이용을 위해서 강제 기능 테스트 
$ setprop sys.usb.configfs 1
$ setprop sys.usb.config rndis,adb
$ setprop sys.usb.configfs 2

//상위의 init.usb.rc 중 midi,adb 이용을 위해서 강제 기능 테스트 
$ setprop sys.usb.configfs 1
$ setprop sys.usb.config midi,adb
$ setprop sys.usb.configfs 2

//상위와 같이 직접 변경하면 아래와 같이 Error 발생하여, init.usb.rc 반영하기로 결정   
init: processing action (sys.usb.config=rndis,adb && sys.usb.configfs=1) from (/init.usb.configfs.rc:131)
init: processing action (sys.usb.config=rndis,adb && sys.usb.configfs=1 && sys.usb.ffs.ready=1) from (/init.usb.configfs.rc:134)
init: Command 'write /config/usb_gadget/g1/UDC ${sys.usb.controller}' action=sys.usb.config=rndis,adb && sys.usb.configfs=1 && sys.usb.ffs.ready=1 (/init.usb.configfs.rc:139) took 0ms and failed: Unable to write to file '/config/usb_gadget/g1/UDC': Unable to write file contents: Device or resource busy

  • Android i.MX USB 관련사항 점검
i.MX8QXP 와 i.MX6를 비교를 하면 차이나며, 관련부분을 좀 더 분석해야할 것으로 생각됨
// OTG1 관련부분의 hdrc가 1개 확인
$ su
# find /sys -name  *hdrc*     
/sys/class/udc/ci_hdrc.0
/sys/devices/platform/bus@5b000000/5b0d0000.usb/ci_hdrc.0
/sys/devices/platform/bus@5b000000/5b0d0000.usb/ci_hdrc.0/udc/ci_hdrc.0
/sys/bus/platform/devices/ci_hdrc.0
/sys/bus/platform/drivers/musb-hdrc
/sys/bus/platform/drivers/ci_hdrc
/sys/bus/platform/drivers/ci_hdrc/ci_hdrc.0
/sys/bus/pci/drivers/ci_hdrc_pci
/sys/module/musb_hdrc

// OTG3,2 cdns 관련부분확인 
# find /sys -name  *cdn*
/sys/devices/platform/bus@5b000000/5b110000.usb3/xhci-cdns3
/sys/bus/platform/drivers/cdns-mhdp-imx
/sys/bus/platform/drivers/sdhci-cdns
/sys/bus/platform/drivers/cdns-usb3
/sys/bus/platform/drivers/imx-cdnhdmi
/sys/firmware/devicetree/base/bus@5b000000/usb3@5b110000/cdns3,usbphy
/sys/module/cdns3

# lsusb -t
Bus 001 Device 001: ID 1d6b:0002
Bus 001 Device 003: ID 0525:a4a1
Bus 002 Device 001: ID 1d6b:0003

// USB Host에 연결된 Device 확인 (lsusb의 옵션이 제대로 안됨) 
# ls /sys/bus/usb/devices/  
1-0:1.0 1-1 1-1:1.0 1-1:1.1 2-0:1.0 usb1 usb2

# cat /sys/bus/usb/devices/1-1/idProduct
a4a1

# cat /sys/bus/usb/devices/usb1/uevent //usb1이 OTG1 일것이라고 생각했는데, OTG3 이 Host 역할 
MAJOR=189
MINOR=0
DEVNAME=bus/usb/001/001
DEVTYPE=usb_device
DRIVER=usb
OF_NAME=usb3
OF_FULLNAME=/bus@5b000000/usb3@5b110000
OF_COMPATIBLE_0=Cadence,usb3
OF_COMPATIBLE_N=1
PRODUCT=1d6b/2/504
TYPE=9/0/1
BUSNUM=001
DEVNUM=001

# exit
$


1/03/2021

Android System App 권한

1. Android App Signature

Android App에 Signature 기능이 있는 것을 알아본게 된 이유가 System 권한을 가지고 실행하기 위해서 이를 알아보게되었다. 
왜냐하면, 일반적으로 만든 App들은 untrusted_app domain으로 SELinux에서 제한이 있어 매번 제대로 실행이 되지 않는 것을 해결해볼까 하고 생각이였다.
물론 SELinux를 허용모드로 하면 이문제는 이 부분이 다 필요가 없지만, 개발환경이 아닌 실제에서는 다르기때문에 이를 다시 생각하게되었다. 

물론 이 문제이외에도 permission에 관련된 문제가 있었으나, 그부분은 init.xxx.rc에서 강제로 했다. 

이부분은 OpenSSL의 인증서 Certificate(X.509)부분을 보면 쉽게이해가 가며, 간단히 보면, private key 와 public key의 사용으로 동작되는 것을 알 수 있다. 

암호화 기본개념 과 Cipher Suite

Android에서는 아래의 4종류의 Key가 있다고 하며 역할은 아래와 같다. 
  1. platform: a key for packages that are part of the core platform.
  2. shared: a key for things that are shared in the home/contacts process.
  3. media: a key for packages that are part of the media/download system.
  4. testkey: the default key to sign with if not otherwise specified.

https://boundarydevices.com/android-security-part-1-application-signatures-permissions/

상위과 같이 동작원리는 간단하다. 
Signing/Verfify 로 이를 쉽고 빠르게 검증하는 것이다. 


AOSP Source 기준으로 살펴보면 각 Key 위치와 Certificate 위치확인 

  • Default build system signs package 들과 testkey 아래 위치에 존재
$ ls build/target/product/security/
Android.mk  media.x509.pem    networkstack.x509.pem  platform.x509.pem  shared.pk8       testkey.pk8       verity_key  verity.x509.pem
media.pk8   networkstack.pk8  platform.pk8           README             shared.x509.pem  testkey.x509.pem  verity.pk8

  • Vendor NXP(Freescale)용 signs package 
$ ls device/fsl/common/security/
media.pk8       networkstack.pk8       platform.pk8       README             shared.pk8       testkey.pk8                 testkey_rsa4096.pem
media.x509.pem  networkstack.x509.pem  platform.x509.pem  rpmb_key_test.bin  shared.x509.pem  testkey_public_rsa4096.bin  testkey.x509.pem

$ grep -r  PRODUCT_DEFAULT_DEV_CERTIFICATE. .
./device/fsl/imx6sl/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx7d/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx6sx/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx6dq/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx7ulp/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx8m/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx8q/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \

$ cat ./device/fsl/imx8q/ProductConfigCommon.mk  // OVERWRITE 
...
PRODUCT_DEFAULT_DEV_CERTIFICATE := \
	device/fsl/common/security/testkey
...

$ cat ./device/fsl/imx8q/BoardConfig.mk  // AVB를 위한 RSA 비대칭키사용
.....
BOARD_AVB_ENABLE := true

BOARD_AVB_ALGORITHM := SHA256_RSA4096
# The testkey_rsa4096.pem is copied from external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_KEY_PATH := device/fsl/common/security/testkey_rsa4096.pem
.......

$ cat ./device/fsl/imx8q/mek_8q.mk  
.....
# Copy rpmb test key and AVB test public key
ifeq ($(PRODUCT_IMX_TRUSTY),true)
PRODUCT_COPY_FILES += \
    device/fsl/common/security/rpmb_key_test.bin:rpmb_key_test.bin \
    device/fsl/common/security/testkey_public_rsa4096.bin:testkey_public_rsa4096.bin
endif
.....

PRODUCT_DEFAULT_DEV_CERTIFICATE 에 의해 overwrite가 가능하다고 하니, 상위와 같이 검색  

platform/shared/media/testkey 생성부터 인증관련내용

1.1 ASOP Source에서 platform Key 추출 

  • ASOP Default Platform Key 추출 
두개의 password는 android로 설정 했으며, key alias는 androiddebugkey로 설정 
$ mkdir mytest1
$ cp build/target/product/security/platform.pk8 mytest1/
$ cp build/target/product/security/platform.x509.pem mytest1/

$ cd mytest1

//PKCS#08:  Private-Key Information Syntax Standard 로 아래와 같이 변경 (DER) platform.pem로 생성 
//PKCS#12:  Personal Information Exchange Syntax Standard 로 platform.x509.pem을 platform.p12로 변경  Private KEY는 platform.pem이용하고 설정값  

$ openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem 
$ openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.p12 -password pass:android -name androiddebugkey 
$ keytool -importkeystore -deststorepass android -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass android  

$ ls 
platform.jks  platform.p12  platform.pem  platform.pk8  platform.x509.pem

PKCSx(Public Key Cryptography Standards)
  1. PKCS_12:공개키 인증서 교환문법 표준
  2. PKCS_08:개인키 정보 문법 표준 


  • NXP용 Platform Key 추출 
두개의 password는 android로 설정 했으며, key alias는 androiddebugkey로 설정 
$ mkdir mytest2
$ cp device/fsl/common/security/platform.pk8 mytest2/
$ cp device/fsl/common/security/platform.x509.pem mytest2/

$ cd mytest2

$ openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem 
$ openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.p12 -password pass:android -name androiddebugkey 
$ keytool -importkeystore -deststorepass android -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass android 

$ ls 
platform.jks  platform.p12  platform.pem  platform.pk8  platform.x509.pem

Platform Key 추출


Platform Key 관련링크들  

2. App 에 System App 권한부여  

상위에서도 설명했지만, 기본 App은 untruested_app으로 실행되기 때문에 SELinux와 Permission 문제가 발생해서 이부분을 system 권한으로 변경하도록 실행 

  • Androidmanifest.XML 에서 system 권한 부여
Java에서 현재 root는 안된다고 하는데, 과거에는 된 것 같음 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.beep"
    android:sharedUserId="android.uid.system" >

  • ASOP에서 NXP platform.jks 추출 후 Android Studio 에서 Sign 방법 
Android Studio -> File -> Project Structure -> Signing Config


or 

Android Studio -> Build -> Generate Signed Bundle/APK -> APK

상위처럼 하면, 구지 build.gradle를 직접 수정하지 하지 않해도 되지만, debug 와 release를 구분해서 넣어주자.  


기본 SELinux Domain untrusted_app
[12387.628007] type=1400 audit(1611554077.764:163): avc: denied { read } for comm="om.example.beep" name="duty_cycle" dev="sysfs" ino=37724 scontext=u:r:untrusted_app:s0:c101,c256,c512,c768 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1 app=com.example.beep
바뀔 SELInux Domain system_app
[14697.359731] type=1400 audit(1611556387.500:167): avc: denied { read } for comm="om.example.beep" name="duty_cycle" dev="sysfs" ino=37724 scontext=u:r:system_app:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1

현재 permission 과 권한도 system으로 변경했지만 SELinux에서 거부되는 것은 현재 sysfs 때문이라고 생각이 된다. 

매번 Build Clean 후 다시 실행했으며, 만약 INSTALL_FAILED_SHARED_USER_INCOMPATIBLE 에러가 계속나면, 나의 경우, 상위 system 설정 후 Sign이 맞지않아 생겼다.
NXP용 platform key를 사용해야 문제가 없었음  

  • adb shell or serial 에서 package 설치확인 
Terminal에서  package 설치확인 
$ su
#
# pm list packages | grep <package>

# pm uninstall <package>


2.1 signapk.jar를 이용한 Sign 방법 

아직 해보지 못했으며, 관련부분만 현재 검색했음 

  • Android App Sign 
apk 생성후 이를 ASOP에서 직접 signapk.jar를 이용하여 sign하는 방법 
$ find . -name signapk.jar
./out/host/linux-x86/framework/signapk.jar
./out/soong/host/linux-x86/framework/signapk.jar
./out/soong/.intermediates/build/make/tools/signapk/signapk/linux_glibc_common/combined/signapk.jar
./out/soong/.intermediates/build/make/tools/signapk/signapk/linux_glibc_common/javac/signapk.jar
./prebuilts/sdk/tools/lib/signapk.jar

$ mkdir mytest
$ cp my_nosign.apk   mytest/              // my app 
$ cp build/target/product/security/platform.x509.pem  mytest/
$ cp build/target/product/security/platform.pk8   mytest/
$ cp out/host/linux-x86/framework/signapk.jar  mytest/
$ cd mytest

$ java -jar signapk.jar platform.x509.pem platform.pk8 my_nosign.apk my_sign.apk        // signing apk 
$ ls my_sign.apk


12/30/2020

Android PWM 과 GPIO 설정 및 Control Test App

1. Device Tree 관련설정 
 

Device Tree 기본문법이해 

Device Tree 기반 부팅방법

아래설정은 i.MX8에서 BSP에서 LSIO PWM 관련설정이 없어 어쩔수 없이 Datasheet를 보고 직접 만들어서 추가하였으며, MIPI에서 사용하는 PWM과 같이 i.mx27로 사용결정

$ vi *dts


/* PWM 사용을 위해서 PWM 사용과 GPIO PINMUX 설정 
iomuxc가 label 이므로  &iomuxc 사용 (iomuxc: pinctrl)  
*/

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_hog>;

	/* PINMUX 를 PWM과 GPIO 변경 
	*  IMX8QXP_UART1_RX  : PWM1
	*  IMX8QXP_UART1_TX  : GPIO 
	*/
	pinctrl_lppwm1: lppwm1grp {
		fsl,pins = <
			IMX8QXP_UART1_RX_LSIO_PWM1_OUT					0x00000020
			IMX8QXP_UART1_TX_LSIO_GPIO0_IO21				0x00000020		
		>;
	};
	/* PINMUX 를 PWM과 GPIO 변경 
	*  IMX8QXP_UART1_RTS_B  : PWM2 
	*  IMX8QXP_UART1_CTS_B  : GPIO
	*/
	pinctrl_lppwm2: lppwm2grp {
		fsl,pins = <
			IMX8QXP_UART1_RTS_B_LSIO_PWM2_OUT	0x00000020		
			IMX8QXP_UART1_CTS_B_LSIO_GPIO0_IO24	0x00000020	
		>;
	};	

};

/* MIPI의 PWM 부분 삭제 전부 label이므로 &적용  */

/delete-node/ &pwm_mipi_lvds0;
/delete-node/ &pwm_mipi_lvds1;

/delete-node/ &lvds_backlight0;
/delete-node/ &lvds_backlight1;

/* UART1 과 PWM PINMUX 충돌하여 미사용로 변경  */
&lpuart1 {
    status = "disabled";
};


/* 
    LSIO PWM 관련정의가 없어서 Datasheet를 보고 각 Address에 맞춰 정의
    MIPI도 i.MX6도 PWM을 im27-pwm 사용하여 나 또한 이것으로 사용하기로 결정 
    lsio_subsys를 main으로 넣기로함 

    / { 
    .....
     }
*/

/ {
	
	lsio_subsys: bus@5d000000 {
		compatible = "simple-bus";
		#address-cells = <1>;
		#size-cells = <1>;
		ranges = <0x5d000000 0x0 0x5d000000 0x1000000>,
			<0x08000000 0x0 0x08000000 0x10000000>;

/* 
i.MXQXP의 LSIO Datasheet 관련부분을 보면 상위 Memory Map Range 영역을 설정  
현재 child's address 1 , size 1만 존재 parent address가 없음 총 4개로 memory mapped io로 하는 것으로 생각됨 (추측)
- Physical Start 0x5d000000 0x0 
- Physical End   0x5d000000+0x1000000
- Virtual  Start 0x08000000 0x0
- Virtual  End   0x08000000+0x10000000
*/

		pwm1_lsio: pwm@5d010000 {
			compatible = "fsl,imx8qxp-pwm", "fsl,imx27-pwm";
			reg = <0x5d010000 0x1000>;
			clocks = <&pwm1_lpcg 0>,
				 <&pwm1_lpcg 1>,
				 <&pwm1_lpcg 2>;				
			pinctrl-names = "default";
			pinctrl-0 = <&pinctrl_lppwm1>;					 
			clock-names = "per", "ipg","32k";
			assigned-clocks = <&clk IMX_SC_R_PWM_1 IMX_SC_PM_CLK_PER>;
			assigned-clock-rates = <24000000>
			#pwm-cells = <2>
			power-domains = <&pd IMX_SC_R_PWM_1>;
			status = "okay";
		};	

		pwm2_lsio: pwm@5d020000 {
			compatible = "fsl,imx8qxp-pwm", "fsl,imx27-pwm";
			reg = <0x5d020000 0x1000>;
			clocks = <&pwm2_lpcg 0>,
				 <&pwm2_lpcg 1>,
				 <&pwm2_lpcg 2>;				
			pinctrl-names = "default";
			pinctrl-0 = <&pinctrl_lppwm2>;					 
			clock-names = "per", "ipg","32k";
			assigned-clocks = <&clk IMX_SC_R_PWM_2 IMX_SC_PM_CLK_PER>;
			assigned-clock-rates = <24000000>;
			#pwm-cells = <2>;
			power-domains = <&pd IMX_SC_R_PWM_2>;
			status = "okay";
		};	

	};

//#pwm-cells   pwm 기반으로 사용하는 다른 driver에서 이를 사용  (backlight) 
https://www.kernel.org/doc/Documentation/devicetree/bindings/pwm/pwm.txt
https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/pwm/pwm.txt

};


2. PWM Driver 기본구조분석

PWM Driver 기본구조 및 sys filesystem 사용법

  • PWM Driver (imx27)
  1. pwmchip_add()
  2. pwmchip_remove()

i.MX27 PWM Driver 


  • PWM 기반의 Driver (Back light)
  pwm_request()  기반으로 구현


2.1 sys filesystem PWM-TEST 

상위 imx27 Driver가 설정과 Clock 설정한 후 아래와 같이 설정가능하지만, 권한이 문제발생하여 아래와 같이 su 를 이용하여 root로 테스트 

  • PWM0 생성 및 기본제어방법
GPIO와 유사하게 export로 설정후 pwm0을 생성되어 자동마운트 된후 실제적인 설정진행 
  1. period : 주기를 설정 ( ns 단위) 
  2. duty_cycle: positive pulse width  (ns 단위) 
$ su 
# id
uid=0(root) gid=0(root) groups=0(root),1007(log),3009(readproc) context=u:r:su:s0

$ echo 0 > /sys/class/pwm/pwmchip0/export   // pwm0 생성됨 
$ echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period
$ echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
$ echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
상위 설정은 1KHz의 주기를 가지고 Duty 즉, High Pulse는 반으로 설정 

아래와 같이 50Hz 주기 설정 후 half duty로 변경 및 다양한 duty 테스트 
//50Hz 20ms 주기 설정  
$ echo 20000000 > /sys/class/pwm/pwmchip0/pwm0/period 

//10000us (10ms) (half) Positive Pulse 
$ echo 10000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 

//1000 us (1ms)
$ echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 

//1250 us (1.25ms) 
$ echo 1250000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 

//1500 us (1.5ms)
$ echo 1500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 

//1750 us (1.75ms) 
$ echo 1750000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 

//2000 us (2.ms)
$ echo 2000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 

PWM 관련설정 사항 

상위는 Android의 기본 shell에서 동작않아, 이를 해결하기 위해서 init.rc 에서 export 와 권한설정하기로 결정. 



2.2 Android init.hardware.rc 문법 수정  

Linux로 말하면, init script 이며, 이는 이부분 각 service와 초기화 관련부분을 담당  
  1. init.rc 
  2. init.%hardware%.rc

  • Android Init 관련문법 복습
Init 문법을 보면 크게 Action 과 Service 와 command 나누어지며, 다음과 같이 동작한다. 
//Action 기능 이며, trigger 와 command를 다양하게 지원
on <trigger> [&& <trigger>]*
   <command>
   <command>
   <command>
   
//Service 기능이며 관련 option은 아래 링크 참조      
service <name> <pathname> [ <argument> ]*
   <option>
   <option>
   ...     

Android init 문법의 세부내용 Manual 

  • Android의 기본 init.rc 확인 
기본 init.rc 위치 및 설정확인하였지만, 직접수정하지 않는 것이 좋을 것 같아 이부분은 그대로 유지 
$ vi system/core/rootdir/init.rc  // 
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc

# Cgroups are mounted right before early-init using list from /etc/cgroups.json
on early-init
    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0

    # Set the security context of /adb_keys if present.
    restorecon /adb_keys

    # Set the security context of /postinstall if present.
    restorecon /postinstall

    mkdir /acct/uid
.........    

$ cat out/target/product/mek_8q/root/init.rc   

  • i.MX8을 위한 init.hardware.rc 에 수정
각 hardware를 위한 init.rc 부분에 아래와 pwm관련설정부분을 추가를 해준다. 
상위 문법을 보면 trigger 로 조건이 맞을 경우 command로 action이 되어진다. 
$ vi ./device/fsl/imx8q/mek_8q/init.imx8qxp.rc
......
    # jhlee /sys filesystem mount가 된 경우 실행 
on property:sys.boot_completed=1
    #jhlee for PWM1/2  root 권한으로 실행됨  
    chmod 0777 /sys/class/pwm/pwmchip0
    chmod 0222 /sys/class/pwm/pwmchip0/export
    chmod 0222 /sys/class/pwm/pwmchip0/unexport
    chmod 0777 /sys/class/pwm/pwmchip1
    chmod 0222 /sys/class/pwm/pwmchip1/export
    chmod 0222 /sys/class/pwm/pwmchip1/unexport

    # PWM1 50Hz 20ms / 10ms (half)
    write /sys/class/pwm/pwmchip0/export 0
    write /sys/class/pwm/pwmchip0/pwm0/enable 1
    write /sys/class/pwm/pwmchip0/pwm0/period 20000000
    write /sys/class/pwm/pwmchip0/pwm0/duty_cycle 10000000

    # PWM2 50Hz 20ms / 10ms (half)
    write /sys/class/pwm/pwmchip1/export 0
    write /sys/class/pwm/pwmchip1/pwm0/enable 1
    write /sys/class/pwm/pwmchip1/pwm0/period 20000000
    write /sys/class/pwm/pwmchip1/pwm0/duty_cycle 10000000

    chmod 0666 /sys/class/pwm/pwmchip0/pwm0/period
    chmod 0666 /sys/class/pwm/pwmchip0/pwm0/duty_cycle
    chmod 0666 /sys/class/pwm/pwmchip0/pwm0/enable

    chmod 0666 /sys/class/pwm/pwmchip1/pwm0/period
    chmod 0666 /sys/class/pwm/pwmchip1/pwm0/duty_cycle
    chmod 0666 /sys/class/pwm/pwmchip1/pwm0/enable

    # GPIO UART1_TX 21
    write /sys/class/gpio/export 21
    write /sys/class/gpio/gpio21/direction "out"
    write /sys/class/gpio/gpio21/value 1

    # GPIO UART1_CTS_B 24
    write /sys/class/gpio/export 24
    write /sys/class/gpio/gpio24/direction "out"
    write /sys/class/gpio/gpio24/value 1

    chmod 0666 /sys/class/gpio/export
    chmod 0666 /sys/class/gpio/unexport
    chmod 0666 /sys/class/gpio/gpio21/direction
    chmod 0666 /sys/class/gpio/gpio21/value
    chmod 0666 /sys/class/gpio/gpio24/direction
    chmod 0666 /sys/class/gpio/gpio24/value
....    

$ cat out/target/product/mek_8q/vendor/etc/init/hw/init.freescale.imx8qxp.rc   // 빌드 후 실제 적용되어되었는지확인 

init.rc script이 root기반으로 동작되기 때문에 초반에 chmod를 하는것은 의미가 없다 

2.3 PWM ueventd.rc 문법 수정  

처음 착각했던 것이 export를  값을 넣어주면, uevent가 발생하여 관련부분이 pwm이 생기면서 이 script를 이용하여 permission을 변경할 줄 알았다. 

  1. ueventd.rc 
  2. ueventd.%hardware%.rc 



  • ueventd.rc 설정 
아래설정으로 하면 될 줄 알았는데, 실패했지만, 될 것이라고 생각되어 이곳에 기록하며 추후 재확인 
$ vi ./device/fsl/imx8q/mek_8q/ueventd.freescale.rc
# /sys file은 entry 5개 (주의)
# /dev file은 entry 4개 
# jhlee for pwmchip0 pwm0
/sys/devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0/pwm0  enable 0666 system system
/sys/devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0/pwm0  period 0666 system system
/sys/devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0/pwm0  duty_cycle 0666 system system
/sys/devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0/pwm0  polarity   0666 system system

# jhlee for pwmchip1 pwm0
/sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1/pwm0  enable 0666 system system
/sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1/pwm0  period 0666 system system
/sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1/pwm0  duty_cycle 0666 system system
/sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1/pwm0  polarity   0666 system system

# jhlee for pwm (0/1/2/3)
/sys/class/pwm/pwmchip*      export     0666 system system
/sys/class/pwm/pwmchip*      unexport   0666 system system
/sys/class/pwm/pwmchip*      enable     0666 system system
/sys/class/pwm/pwmchip*      period     0666 system system
/sys/class/pwm/pwmchip*      duty_cycle 0666 system system
/sys/class/pwm/pwmchip*      polarity   0666 system system
$ cat out/target/product/mek_8q/vendor/ueventd.rc  // /sys file은 entry 5개 사용 주의 
[    5.133113] ueventd: /vendor/ueventd.rc: 44: /sys/ lines must have 5 entries
[    5.140349] ueventd: /vendor/ueventd.rc: 45: /sys/ lines must have 5 entries
[    5.147472] ueventd: /vendor/ueventd.rc: 46: /sys/ lines must have 5 entries
[    5.154572] ueventd: /vendor/ueventd.rc: 47: /sys/ lines must have 5 entries

ueventd.rc pwm 과 gpio 관련예제 


ueventd 별도정리 필요 

  • android ueventd Main 소스 

  • ueventd.rc Parser 소스 
ParseConfig (ueventd.rc ) -> AddSingleLineParser->ParsePermissionsLine (각 sys or dev parsing 후 permision 설정 )
(sys 와 dev는 entry 갯수가 다르며, 이는 Cold boot를 위한 것이므로, Kernel에서 미리 설정되어야 한다)

  • ueventd의 handler 소스 
실제동작을 LOG_UEVENTS로 DEBUG 가능 

  • ueventd debug 방법 
상위 ueventd 소스를 보면 LOG_UEVENTS 설정에 따라 LOG를 볼 수 있으며 이를 강제로 선언하여 Debug를 한다. 

$ vi ./system/core/init/Android.mk 
.......
init_options += -DLOG_UEVENTS=1 \
    -DSEPOLICY_VERSION=$(POLICYVERS)
.......      


ueventd의 selinux 설정 


PWM의 sysfs의 구조 


  • root 권한으로  shell 에서 pwm 위치 찾기 

$ for i in /sys/class/pwm*/pwmchip*/pwm* ; do ls -l $i; cat $i; done
total 0
-r--r--r-- 1 root root 4096 2021-01-20 07:16 capture
-r--r--r-- 1 root root 4096 2021-01-20 07:16 consumers
-rw-rw-rw- 1 root root 4096 2021-01-20 03:33 duty_cycle
-rw-rw-rw- 1 root root 4096 2021-01-20 03:33 enable
-r--r--r-- 1 root root 4096 2021-01-20 07:16 output_type
-rw-rw-rw- 1 root root 4096 2021-01-20 03:33 period
-rw-r--r-- 1 root root 4096 2021-01-20 07:16 polarity
drwxr-xr-x 2 root root    0 2021-01-20 07:16 power
-r--r--r-- 1 root root 4096 2021-01-20 07:16 suppliers
-rw-r--r-- 1 root root 4096 2021-01-20 07:16 uevent
cat: /sys/class/pwm/pwmchip0/pwm0: Is a directory
total 0
-r--r--r-- 1 root root 4096 2021-01-20 07:17 capture
-r--r--r-- 1 root root 4096 2021-01-20 07:17 consumers
-rw-rw-rw- 1 root root 4096 2021-01-20 03:33 duty_cycle
-rw-rw-rw- 1 root root 4096 2021-01-20 03:33 enable
-r--r--r-- 1 root root 4096 2021-01-20 07:17 output_type
-rw-rw-rw- 1 root root 4096 2021-01-20 03:33 period
-rw-r--r-- 1 root root 4096 2021-01-20 07:17 polarity
drwxr-xr-x 2 root root    0 2021-01-20 07:17 power
-r--r--r-- 1 root root 4096 2021-01-20 07:17 suppliers
-rw-r--r-- 1 root root 4096 2021-01-20 07:17 uevent
cat: /sys/class/pwm/pwmchip1/pwm0: Is a directory

$ ls -alh /sys/class/pwm/          //ueventd.*.rc에 추가하 위해서 정확한 PATH 알기 (아래는 강제로 권한변경된 상태)
...
lrwxrwxrwx  1 root root 0 2020-12-30 06:06 pwmchip0 -> ../../devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0
lrwxrwxrwx  1 root root 0 2020-12-30 06:06 pwmchip1 -> ../../devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1


2.4 SELinux 

  • i.MX8의 의 SElinux 문제발생 (동작안됨)
상위에서 write /sys/class/pwm/pwmchip0/export 0 할 경우 uevent가 발생할것이며, 아래와 같이 ls를 했을 경우 access 문제발생 

mek_8q:/sys/class/pwm/pwmchip0 $ ls -alh
drwxr-xr-x 3 root root    0 1970-01-01 00:00 .[  175.487816] type=1400 audit(1609308473.916:27): avc: denied { getattr } for comm="ls" path="/sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip0/uevent" dev="sysfs" ino=34845 scontext=u:r:shell:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1

  • BoardConfig.mk 관련수정
SElinux 를 허용모드(permissive) 강제로 변경후 별도의 추가 *.te를 할 필요가 없으므로 이를 간단히 해결 
$ find . -name BoardConfig.mk  // 기본위치파악 
device/Vendor/ARCH/BoardName/BoardConfig.mk

$ vi ./device/fsl/imx8q/mek_8q/BoardConfig.mk    // i.MX8 관련수정 

# NXP의 기본 Hardware 설정 
# NXP default config
BOARD_KERNEL_CMDLINE := init=/init androidboot.hardware=freescale firmware_class.path=/vendor/firmware loop.max_part=7

#
# permissive 추가 
BOARD_KERNEL_CMDLINE += androidboot.selinux=permissive

상위와 같이 permissive 로 변경할 경우, 상위와 같이 error는 발생하며, 경고는 하지만, 문제가 되지 않음 
하지만, 이는 개발시에는 사용해야하면, 제품 출하시에는 반드시 관련부분을 수정해야한다. 

Android SELinux (일반 Linux의 SELinux의 사용법과 좀 다름)

SELinux 관련부분 정리 

3. Android SDK/NDK/PDK 구분 

  • SDK
Software Development Kit 로 순수 Application 입장이라고 생각하면 되겠으며, Java기반으로 Android Studio에서 제작가능하며, Google 제공하는 SDK에서 개발가능 

Google에서 공식적인 제공하는 SDK 설치 한 후 이와 관련된 API 를 이용하여 사용자가 원할 경우 Custom으로 제작도 가능한 것으로 파악된다. 

  • NDK
Native Development Kit로 주로 C/C++로 기반으로 구현하며, JNI /HAL 을 제공하며,  Library만 구성을 하여도 Application에서 이를 가져다가 사용가능하다. 
Google에서 제공하는 NDK를 설치 한 후 이를 Build를 진행해야한다. 
 
  • PDK
Product(Platform) Development Kit로  SDK 와 NDK 의 동시에 사용할 경우를 말한다. 
가장 쉬운예제가 JNI기능을 포함 SDK Program이며, 이는 PDK라고 불리운다. 
상위에서 제공한 SDK 와 NDK를 설치한 후 이를 기반으로 작성가능하다. 


NDK/PDK기반의 예제 

상위를 간단히 분석을하면, Target의 /system/lib 에 본인이 구현한 library를 넣고 , 이를 기반으로 SDK에서 Class를 Loading하여 사용하면된다. 

Android Studio를 이용하거나, ASOP에서 직접 빌드를 하면된다. 


3.1 PWM PDK 작성방법 

Android Studio에서 Native C++ 로 기반으로 PDK 구현할 경우 문제는 SELinux의 domain 이 untrusted_app로 생성되며, 이를 허용하지 않아 
상위처럼 강제로 허용모드로 변경해야 했지만, Vendor입장에서 상위 untruested_app의 domain을 변경해서 사용해야 할 것 같다. 

  • Android Source 소스 수정 
  1. ASOP_SETTING : ASOP에서 직접 수정(Access 문제) 후 이를 Build 후 관련 Image 생성 
    상위 2.2 init.hardware.rc 관련부분 수정 (init.xxxx.rc 상위 이름 참조 chmod로 변경)
    상위 2.4 SELinux 의 Permissive , 즉 허용모드 변경   ( 접근허용으로 변경)

  • Android Studio 기반으로  Native C++  생성 
  1. Android Studio-> New -> Native C++ 선택 후 기본 생성 
  2. cpp -> CMakeLists.txt  변경 (기존 예제인 C++ 삭제)
  3. cpp -> GpioCtr.c / GpioCtr.h 추가 
  4. cpp -> PWMCtr.c / PWMCtr.h 추가 (예제인 C++ 삭제)
  5. java -> com.example.jhlee -> GpioCtr.java
  6. java -> com.example.jhlee -> PWMCtr.java
  7. java -> com.example.jhlee -> MainActivity.java

  • 관련 Sample 소스 



3.3 기타사항 


Android Application의 경우 AndroidManifest.xml 까지 추후에 봐야한다.

아래의 소스는 NDK 기반에서 /system/lib 에 넣고 SDK에서 이를 호출하여 동작하는 방식 



Anroid Thing Native

Android Thing 상용화 무료가 아님



상위 /sys/class/pwm/pwmchip0 권한문제

PWM- Back light 

12/19/2020

MIPI DSI(Display Serial Interface) 와 SW 구조

1. MIPI  Data 전송방식  

MIPI-DSI Hardware 구조 

ST MIPI-DSI 구조 (필독 자세한 설명이 나옴)

MIPI 관련내용


MIPI의 기본전송방식은 크게 Long Packet/ Short Packet 구조로 두개로 나누어지며, 세부적으로 Data ID에 따라 변경이 된다.  

https://www.st.com/resource/en/application_note/dm00287601-dsi-host-on-stm32f469-479-stm32f7x8-x9-and-stm32l4r9-s9-mcus-stmicroelectronics.pdf

  1. PH(Packet Header):  Header는 ECC로 검증이가능
  2. Data Paylod 
  3. PF(Packet Footer): Checksum으로 전체 Data가 검증가능 

만약 S/W에서 MIPI 전송오류가 발생한다면, ECC or Checksum Error가 발생할 것이며, 이는 곳 MIPI가 고속 Serial 통신이므로, 
HW 관련부분을 점검해봐야 할 것이다. 


  • 일반적인 HS(High Speed )모드 전송 방식 


  • Short Packet 전송 HS Mode 


  • Long Packet 전송 HS Mode (2 Lane)


1.1  Long Packet 과 Short Packet 

MIPI에서 알아야 할 기본구조 전송방식이며, DataID 값도 같이 알아야 정확한 이해가 가능하다. 

  • Long Packet 
  1. SoT(Start Of Transmission)
  2. Data ID(Virtual Channel ID) : 1byte
  3. Word Count: 2 bytes (Payload Size)
  4. ECC: 1 byte
  5. Data: Payload
  6. CheckSum: 2bytes 
  7. EoT(End Of Transmission)











Kernel(drivers/gpu/drm/drm_mipi_dsi.c)
mipi_dsi_packet_format_is_long  ( 이 함수를 보면 long packet의 종류를 파악)

  • Short Packet 
  1. SoT(Start Of Transmission)
  2. Data ID(Virtual Channel ID) : 1 byte
  3. Data 1/2: 2 bytes
  4. ECC: 1byte
  5. EoT(End Of Transmission)








Kernel (drivers/gpu/drm/drm_mipi_dsi.c)
mipi_dsi_packet_format_is_short  ( 이 함수를 보면 short packet의 종류를 파악)
  https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_mipi_dsi.c#L369

long/short packet (mipi_dsi_msg *msg ) 자체가 packet header 와 payload 가 포함됨 


1.2 Packet 의 Data ID의 구조 


  • DI(Data ID) 에서 Virtual Channel ID 사용 



  • Virtual ID로 Logical Channel 구분 


  • Virtual Channel로 구성 









1.2.1  Data ID->Data Type 의 값 


  • Data ID-> Data Type Class 
아래와 같이 Data Type의 종류를 간단히 보고 세부 값들을 보자. 


  • Data Type 의 다양한 값의 의미  
Packet 이 Short 과 Long으로 구분이 되며, 아래의 Data Type은 Data ID 값이며, DSI Mode에서 Both인 EOT를 반드시 기억하자.
  1. Video: Display 관련 Video Signal 
  2. Both: Master /Slave 동시사용
  3. Command: Master에서 주로 Command를 주는 것 


  1. DCS: DCI 기반으로 DCS로 Display Command 가능 
  2. VD(Video Display Packet)
  3. GN(General Packet)



상위 Data ID (DI) 값과 동일하며, Linux Source에서  동일하며, 상위 값 이외에도 다양하게 확장중이며, 아래와 같이 각 함수마다 호출되는 곳이 다르다. (주의)


  • Linux Kernel 의 Data Type 값 

//include/video/mipi_display.h
/* MIPI DSI Processor-to-Peripheral transaction types */
enum {
	MIPI_DSI_V_SYNC_START                         = 0x01,
	MIPI_DSI_V_SYNC_END                           = 0x11,
	MIPI_DSI_H_SYNC_START                         = 0x21,
	MIPI_DSI_H_SYNC_END                           = 0x31,

	MIPI_DSI_COMPRESSION_MODE                     = 0x07,  //mipi_dsi_compression_mode()
	MIPI_DSI_END_OF_TRANSMISSION            = 0x08,  //주의 SOT는 없어도 EOT는 별도로 존재

	MIPI_DSI_COLOR_MODE_OFF                       = 0x02,
	MIPI_DSI_COLOR_MODE_ON				          = 0x12,
	MIPI_DSI_SHUTDOWN_PERIPHERAL                  = 0x22,   //mipi_dsi_shutdown_peripheral()
	MIPI_DSI_TURN_ON_PERIPHERAL                   = 0x32,   //mipi_dsi_turn_on_peripheral()

	MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM    = 0x03,     //mipi_dsi_generic_write -> mipi_dsi_device_transfer()
	MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM 	= 0x13,    //mipi_dsi_generic_write -> mipi_dsi_device_transfer()
	MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM		= 0x23,     //mipi_dsi_generic_write -> mipi_dsi_device_transfer()

	MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM     = 0x04,     //mipi_dsi_generic_read -> mipi_dsi_device_transfer()
	MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 	= 0x14,     //mipi_dsi_generic_read -> mipi_dsi_device_transfer()
	MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 	= 0x24,     //mipi_dsi_generic_read -> mipi_dsi_device_transfer()

	MIPI_DSI_DCS_SHORT_WRITE 		= 0x05,       //mipi_dsi_dcs_write_buffer->mipi_dsi_device_transfer()
	MIPI_DSI_DCS_SHORT_WRITE_PARAM		= 0x15,        //mipi_dsi_dcs_write_buffer->mipi_dsi_device_transfer()

	MIPI_DSI_DCS_READ				= 0x06,
	MIPI_DSI_EXECUTE_QUEUE				= 0x16,

	MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE		= 0x37,  //mipi_dsi_set_maximum_return_packet_size()

	MIPI_DSI_NULL_PACKET				= 0x09,
	MIPI_DSI_BLANKING_PACKET			= 0x19,
	MIPI_DSI_GENERIC_LONG_WRITE		= 0x29,          //mipi_dsi_generic_write
	MIPI_DSI_DCS_LONG_WRITE			= 0x39,         // mipi_dsi_dcs_write_buffer

	MIPI_DSI_PICTURE_PARAMETER_SET            = 0x0a,  //mipi_dsi_picture_parameter_set()->pps정의 
	MIPI_DSI_COMPRESSED_PIXEL_STREAM		= 0x0b,

	MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20	= 0x0c,
	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24		= 0x1c,
	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16		= 0x2c,

	MIPI_DSI_PACKED_PIXEL_STREAM_30			= 0x0d,
	MIPI_DSI_PACKED_PIXEL_STREAM_36			= 0x1d,
	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12		= 0x3d,

	MIPI_DSI_PACKED_PIXEL_STREAM_16			= 0x0e,
	MIPI_DSI_PACKED_PIXEL_STREAM_18			= 0x1e,
	MIPI_DSI_PIXEL_STREAM_3BYTE_18			= 0x2e,
	MIPI_DSI_PACKED_PIXEL_STREAM_24			= 0x3e,
};
Kernel (include/video/mipi_display.h)
상위값으로 Data ID 값을 확인 


1.3  DSI-DCS(Display Command Set) 

DCS를 비롯하여, 모든 Data는 상위 Long Packet 과 Short Packet 구조를 가지고 있으며, DCS도 아래와 같이 Long Packet / Short Packet으로 구분 

  • DCS(Display Command Set)
Data ID만 변경하면 Long Packet/ Short Packet 구분되어 Header 구성되며, Payload에 DCS가 전달되는 구조임  (아래그림참조)



  • DCS Command는 아래 참조 (Linux Kernel)
//include/video/mipi_display.h
/* MIPI DCS commands */
enum {
	MIPI_DCS_NOP			= 0x00,
	MIPI_DCS_SOFT_RESET		= 0x01,
	MIPI_DCS_GET_COMPRESSION_MODE	= 0x03,
	MIPI_DCS_GET_DISPLAY_ID		= 0x04,
	MIPI_DCS_GET_ERROR_COUNT_ON_DSI	= 0x05,
	MIPI_DCS_GET_RED_CHANNEL	= 0x06,
	MIPI_DCS_GET_GREEN_CHANNEL	= 0x07,
	MIPI_DCS_GET_BLUE_CHANNEL	= 0x08,
	MIPI_DCS_GET_DISPLAY_STATUS	= 0x09,
	MIPI_DCS_GET_POWER_MODE		= 0x0A,
	MIPI_DCS_GET_ADDRESS_MODE	= 0x0B,
	MIPI_DCS_GET_PIXEL_FORMAT	= 0x0C,
	MIPI_DCS_GET_DISPLAY_MODE	= 0x0D,
	MIPI_DCS_GET_SIGNAL_MODE	= 0x0E,
	MIPI_DCS_GET_DIAGNOSTIC_RESULT	= 0x0F,
	MIPI_DCS_ENTER_SLEEP_MODE	= 0x10,
	MIPI_DCS_EXIT_SLEEP_MODE	= 0x11,
	MIPI_DCS_ENTER_PARTIAL_MODE	= 0x12,
	MIPI_DCS_ENTER_NORMAL_MODE	= 0x13,
	MIPI_DCS_GET_IMAGE_CHECKSUM_RGB	= 0x14,
	MIPI_DCS_GET_IMAGE_CHECKSUM_CT	= 0x15,
	MIPI_DCS_EXIT_INVERT_MODE	= 0x20,
	MIPI_DCS_ENTER_INVERT_MODE	= 0x21,
	MIPI_DCS_SET_GAMMA_CURVE	= 0x26,
	MIPI_DCS_SET_DISPLAY_OFF	= 0x28,
	MIPI_DCS_SET_DISPLAY_ON		= 0x29,
	MIPI_DCS_SET_COLUMN_ADDRESS	= 0x2A,
	MIPI_DCS_SET_PAGE_ADDRESS	= 0x2B,
	MIPI_DCS_WRITE_MEMORY_START	= 0x2C,
	MIPI_DCS_WRITE_LUT		= 0x2D,
	MIPI_DCS_READ_MEMORY_START	= 0x2E,
	MIPI_DCS_SET_PARTIAL_ROWS	= 0x30,		/* MIPI DCS 1.02 - MIPI_DCS_SET_PARTIAL_AREA before that */
	MIPI_DCS_SET_PARTIAL_COLUMNS	= 0x31,
	MIPI_DCS_SET_SCROLL_AREA	= 0x33,
	MIPI_DCS_SET_TEAR_OFF		= 0x34,
	MIPI_DCS_SET_TEAR_ON		= 0x35,
	MIPI_DCS_SET_ADDRESS_MODE	= 0x36,
	MIPI_DCS_SET_SCROLL_START	= 0x37,
	MIPI_DCS_EXIT_IDLE_MODE		= 0x38,
	MIPI_DCS_ENTER_IDLE_MODE	= 0x39,
	MIPI_DCS_SET_PIXEL_FORMAT	= 0x3A,
	MIPI_DCS_WRITE_MEMORY_CONTINUE	= 0x3C,
	MIPI_DCS_SET_3D_CONTROL		= 0x3D,
	MIPI_DCS_READ_MEMORY_CONTINUE	= 0x3E,
	MIPI_DCS_GET_3D_CONTROL		= 0x3F,
	MIPI_DCS_SET_VSYNC_TIMING	= 0x40,
	MIPI_DCS_SET_TEAR_SCANLINE	= 0x44,
	MIPI_DCS_GET_SCANLINE		= 0x45,
	MIPI_DCS_SET_DISPLAY_BRIGHTNESS = 0x51,		/* MIPI DCS 1.3 */
	MIPI_DCS_GET_DISPLAY_BRIGHTNESS = 0x52,		/* MIPI DCS 1.3 */
	MIPI_DCS_WRITE_CONTROL_DISPLAY  = 0x53,		/* MIPI DCS 1.3 */
	MIPI_DCS_GET_CONTROL_DISPLAY	= 0x54,		/* MIPI DCS 1.3 */
	MIPI_DCS_WRITE_POWER_SAVE	= 0x55,		/* MIPI DCS 1.3 */
	MIPI_DCS_GET_POWER_SAVE		= 0x56,		/* MIPI DCS 1.3 */
	MIPI_DCS_SET_CABC_MIN_BRIGHTNESS = 0x5E,	/* MIPI DCS 1.3 */
	MIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 0x5F,	/* MIPI DCS 1.3 */
	MIPI_DCS_READ_DDB_START		= 0xA1,
	MIPI_DCS_READ_PPS_START		= 0xA2,
	MIPI_DCS_READ_DDB_CONTINUE	= 0xA8,
	MIPI_DCS_READ_PPS_CONTINUE	= 0xA9,
};
  
  


  • DCS 로 제어는 아래의 함수이용  
  1. mipi_dsi_dcs_write
  2. mipi_dsi_dcs_write_buffer

 

1.4  일반적인 DSI Write

우선 LCD Initial Code는 이전에 병렬에서 맞춰주던 Hsync/Vsync를 비롯하여, LCD의 Data Format 및 기타 설정을 위해서 MIPI Interface로 설정을 해준다. 

  • 일반적인으로  DSI 사용되는 함수 
  1. mipi_dsi_generic_write
  2. mipi_dsi_generic_read 
상위 함수를 이용하여  자동으로 Long or Short 선택되어 Header가 구성되어 read/write 되지만, 상위 Data ID는 상위에 정해짐 


반드시 LCD Datasheet를 참조하여, Payload에 들어가는 Header에 Data ID도 확인가능하다며 확인하자.

본인이 LCD Spec에서 DCS Command 사용여부에  맞게 선택해서 함수도 맞게 넣어 개발하는 것이 맞을 것이라고 본다. 

  • 기타 MIPI-DSI Debug 관련내용 


2. GPU의 DRM (Direct Rendering Manager)

처음 DRM의 약자를 Digital Right Management로 착각했으며, 예전에 HDMI Device Driver 개발당시 HDCP와 유사한 기능이라고 착각했다.
DRM은 GPU기반으로 빠른 Rendering을 지원하기 위해서 제공해주는 기능이며, 이전에 Frame buffer Driver만 개발했던 나에게 다소 생소했는데, 
각 여러 Layer들을 쉽게 Rotate/Scale/Crop/Overlay되는 것을 보고 이 기능에 조금 놀라웠다. 

이전에 TI DSP기반으로했던, Davinci의 경우 Scale 과 Crop은 가능했던걸로 기억하지만, 많은 Layer들은 제어하지는 못했는데, DRM은 GPU를 통해서 다양한 기능을 제공한다.
한마디로 GPU에서 확장된 Frame Buffer라고 생각하면 될 것 같으며, Overlay 기능역시 GPU에 따라 다른 것 같다. 

  • FrameBuffer 와 DRM(Direct Rendering Manager) 비교 


Kernel DRM Driver 기본구조

Kernel GPU DRM-KMS(Kernel Mode Setting) 
상위 MIPI-DSI의 HW Dispaly 관련 출력설정 

TI사의 DSS와 DRM 부분 


2.2  Frame Buffer vs DRM 기반의 Pannel 

  • Frame Buffer LCD Initial Code 
Frame Buffer 기반으로 DCS Command 입력 후 Initial Code 입력 SPI/GPIO 기반으로 입력 

  • DRM 기반의 LCD Initial Code
DRM기반의 실제 Panel Driver들의 다양한 예제이며, SPI와 I2C 및 GPIO와도 연결되어 구성되므로 참고

DRM(Direct Rendering Manager)로 GPU기반으로 DBI (이전의 ST 칩의 DBI라고 생각하면됨)

mipi_dsi_dcs_xxx 함수들은 내부적으로 dcs command를 호출


  • i.MX 의 경우 i.MX6는 Framebuffer Driver
Table 64. MIPI DSI Driver Files  // Frame buffer 기반 Driver 와 DRM 기반 Driver들 
File Description
drveirs/video/fbdev/mxc/mipi_dsi.c                                        MIPI DSI IP Frame buffer driver source file
drivers/video/fbdev/mxc/mipi_dsi.h                                        MIPI DSI IP Frame bufferdriver header file
drivers/video/fbdev/mxc/mxcfb_hx8369_wvga.c                   MIPI DSI Frame bufferDisplay Panel driver source file
drivers/video/fbdev/mxc/mipi_dsi_samsung.c                       MIPI DSI Frame buffer Samsung source file
drivers/video/fbdev/mxc/mipi_dsi_northwest.c                      MIPI DSI Frame buffer Northwest source file
drivers/video/fbdev/mxc/mxcfb_hx8363_wvga.c                   i.MX 7 Frame buffer Truly WVGA Panel TFT3P5581E
drivers/video/fbdev/mxc/mxcfb_hx8369_wvga.c                   i.MX 6 Frame buffer Truly WVGA sync panel
drivers/video/fbdev/mxc/mxcfb_otm808b_wvga.c                 Truly Frame buffer WVGA Panel TFT3P5079E
  •  i.MX의 경우 i.MX 8은 DRM Driver  
drivers/gpu/drm/imx/sec_mipi_dsmi-imx.c Samsung            DRM driver
drivers/gpu/drm/imx/nwl_dsi-imx.c Northwest                        DRM driver



Device Tree