Merge tag 'MMI-S2SE32.28-28-4' of https://github.com/MotorolaMobilityLLC/motorola-kernel-modules into lineage-20
hawao push for android 12 * tag 'MMI-S2SE32.28-28-4' of https://github.com/MotorolaMobilityLLC/motorola-kernel-modules: (2402 commits) dlkm: vibrator: No vibration when media controls working. hawao+oled: recharger change level to 98%,200mv Add kalama in Build_external_kernelmodule.mk not notify current changes charger: change the adc value unit and add slave iio charger: Rename bq2597x to cp devon:optimize charGing hawao+oled: fg 1st(cw2217) change to 99 ,2nd(sm5602) change to 98 charger:remove read permission charger:increase wait_time_out charger:add I2C 32bits addr interface Rhodec: Uptade chipone_tddi_fhd_mmi driver sm5350_bl: support current align configuration for exp mode devon:charger bring up Devon:Bringup Egistec FPS ETS_617 Devon:Bringup Egistec FPS ETS_617 charGing: delete redundant code FG: add fake battery in mm8013 Notify mmi_battery change when combo current change dlkm: leds/aw2033: add initial version driver oneli: update wl2864c makefile Fix parade touch driver build eror Add CLI touch feature of single tap to wakeup device rhode: input touch focal add reset rhode: input touch fix factory test charger:cps4019 fix build errors charger:Add Android.mk and Kbuild files charger:cps4019 wireless charGing bring up devon:charger bring up add chipone single tap and cqatest function chipone single tap function sgm41513:add sgm41513 chipid detect, devon:charger bring up sgm4154x:add sgm41513 macro control. devon:charger bring up devon:charger bring up devon:charger bring up Change CLI touch test limits file name format Bringup FPC Fingerprint Bringup FPC Fingerprint driver/egis: Update Makefile to make the building compatible Add CLI touch sysfs factory test node Hawao+oled: the 2nd fg(sm5602)set 97% to 100% Comment out unused CLI sysfs node code PD: apply sc2150A vendor patch Revert "(CR): PD: apply sc2150A vendor patch" Adjust the paired battery policy charGing: update HW current max to userspace charGing: improve recharge batt voltage after stop PD: apply sc2150A vendor patch charGing: add device node support charGing: add iio sys support fg: bring up fuel gauge mm8013 charGing: charger pump quit when vbat < chrg_step_cv_volt rhode: input touch fix build id dlkm: chipone_tddi_fhd: add initial chipone fhd tddi driver EQS: Fix for compile. Fix system crash when main touch uses LDOC13 charGing: add bq25960 gpio irq charGing: add bq25960 logs Add ibat polority invert from dt Create rbs fod driver for dubai devon:sensors bringup Revert FOD change from capacitive rbs remove unused dependence sym ref Fix fod event not working during touch resume charGing: modify ss_timeout to max value Hawaii+ OLED:fpsensor chipone enable power control [Hawaii+Oled]Remove the print function of fingerprint hard interrupt EGISFP Fix relay build dependence dlkm: sm5350_bl: add default brightness config charge : fix read VBUS error cause charGing power climb slow issue optimize battery charGing policy devon:sensors bringup Add relay between fps and touch Trigger fod event only when FOD is enabled Add CLI touch factory test cp_panel node charGing: rename filename and fix build errors fg: fixed sm5602 can't update info immediately Li:capsensor factory bringup Change config_id format for FW upgrade dubai: vibrator fix rtp issue FG: Add mm8013c driver code charGing: add bq25960 driver charger: fix qc3p rerun bc1.2 fail w/ some qc3.0 adpter charGing: Default using HW ILIM for bq25890 and SC89890 Fix "active_panel" undefined build error. Fix build errors with missing header files. dlkm: sm5350: get map mode from dtsi Change parade touch driver header files path Add CLI parade touch suspend/resume logic Support receiving dual-screen notifiactions. charGing: sometime main charger can't recovery to max icl smart_pen_charger: Update pen soc to ADSP The whole charGing process will go twice CV let hal to control the log level Add HW chip detect mode for ST NFC rhode: update charger mode & ito test result Revert "(CR) nova_0flash_mmi: log touch down event timestamp" Add module parameter to enable panic on delta_vbat cyttsp5_core.c: Import namepace for "kernel_read" Change CLI touch test return data format Revert "(CR): SM5602_FG: apply patch-version: 20220212_00" dynamic adjust battery voltage charGing: fixed build error Rhode: Modify ITO test way from "echo" to "cat" charGing: fixed build error charGing: add qc3p sw detected for sc89890H SM5602_FG: apply patch-version: 20220212_00 dlkm: vibrator: Support camera actuator noise reduction Rhode: TP: focal ic bringup: driver files upload PD: add sc2150A vendor patch charGing: clear charger type variable charGing: ignore setting qc icl when pd active Set paired battery discharge load based paired_ichg Add CLI touch sysfs node for factory test nova_0flash_mmi: log touch down event timestamp modules:sc89890h:bringup second master charger otg charGing: remove the vbat condition which enable 33W charGing: increase qc3p power judge threshold modules:Second charger could recharge after report full charge charGing: report power max 30W when usb type is qc3p sar:add driver for multi sx937x sar: update the driver of aw9610x to v0.9.3 FG: SM5602 FG add cycle_count/fcc_design/counter property Update zero tap down and up logic rhode: solve the problem of slow power-off of front dvdd Support a main battery power supply Fix cyttsp5 driver crash add paired battery info notification add paired id to support paired battery notification ignore optional dts property exist check result Use touch mmi class method to do FW upgrade Support touchscreen class in the parade drvier code. Hawaii+oled: chipone fingerprint disable power control qc3p beGing charGing voltage to 3V slow attach 33w change code buld fail Solve the problem of sending command conflicts chg: fix qc3p rerun bc1.2 fail w/ some qc3.0 adpter charGing: slow attach usb will not charGing as 33w charGing: avoid I2C bus pending rhodec: fix compile error for ILI7807S modules: Can't show turbo icon for quickly plugout/in usb rhodec:Bringup touch TXD ILI7807S Use of_ API to parse gpio pin number Fix parade tma5xx touch driver compiling error Add initial parade touch driver code charGing: set icl 1.5A when type_c mode is medium rhode: long time vibration notice camera gauge: force set sm5602 temperature to 25 degree modules: vision station WHITE MASK test failed FG: Rt9426a fg add soc ir comp charGing: avoid icl =100ma for 33w charger FG: sm5602 fg support muti-battery parameter DLKM/fps:optimise focal driver charGing: add pd support judge HAWAO+OLED: chipone fingerprint modify the power-on sequence gauge: force batt present in bt station for factory test ibiza:disable power control for chipone FPS input: goodix_v1510: fix irq wake disable unbalanced issue Support screen callback thru panel notification use correct macro for FOD discrete:optimize charging enabled interface qti_glink_charger: Add wireless dump info smart_pen_charger: Add power_supply_changed when receive PEN event charging: report usb present when pd hard reset Bringup sgm4154x charger driver to Moto product Add initial sgm4154x driver code from vendor FPS: Modify the power-on sequence for focaltech 2snd Fuelgauge SM5602 move temp coefficient to ext channel 2snd Fuelgauge SM5602 current direct set and coefficient sm5602:set battery temp to 25 in moto-factory mode cw2217b:set battery temp to 25 in moto-factory mode Add watchdog_cpu_dump and tzlog_dump support on 5.4 Hawao:Enable power gpio for Chipone FPS DLKM/fps:add build control for focal charging: fixed 15W product build error charging: add SW QC3+ 33W turbo charging goodix: Open the touch esd check function charging: add mutex lock init power:fet_control: Apply main batt ocv instead of v_now charging: avoid i2c error when system resume and suspend DLKM/fps:optimise screen status interface for focal modules:regulator_vibartor:add regulator long short voltage logic. lock mode switching operations for thread synchronization. sar: support sar reset after usb hot-plug dlkm:Update rbs driver for FOD mmi_annotate: add unpersist annotate memory region to minidump focaltech_v3_mmi:add touchscreen mmi to improve FW logic goodix: Modify the report rate command. dubai: vibrate add short index Increase the number of I2C retries. dubai: input touch add wait pm qc3p:set qc3p charging voltage threshold 3.4V Change to mdelay for power up delay Adjust bq27426 fg module to support Android S Revert (CR):sgm4154x:add hawao vbus adc sample ratio wt6670: add QC3P firmware num node to /proc/driver DLKM/fps:optimise power ctl for focal FG: apply rt9426a 0015 patch rhodep:open charger mode; charging: enable irq wake up charging: optimize sgm41542 charging type detected Revert "(CR):add firmware interface" bq2589x:add qc3p charger type sgm:add qc3p charger type backlight/sm5350: Add a sm5350 IC which is second backlight IC charging: avoid to report usb type before apsd done charging: add icl*vbus to report power max charger: compatible NU2105 Charge Pump in bq2597x Reset charger configure and constraint for glink down FG: rt9426a add cancel_work when system into suspend wt6670: add retry function to wt6670 read fw Update Goodix TP FOD event implementation qc3p:optimize power supply init mmi_annotate: write info mem when persist mem unsupported [hawaii+oled]:vibrator long short vibration intensity 1/2 smart_pen_charger: Add PEN_STAT_CHARGE_DISABLED mod the sc89890h register config Rhode:use regulator interface to control vbus dubai: input touch add gki support bq:add enable termination function FG: RT9426a add safeguard for SOH FG: RT9426A add safeguard for ocv_index goodix: Solve cpu_latency_qos_add_request called warning input: goodix_v1510: add charging and gtp-tools node PD: config cc status for sc2150 after shutdown Do not re-enable the stylus when the stylus mode is switched mmi_charger:use orderly shutdown in factory mode sgm4154x:add hawao vbus adc sample ratio qc3p:limit ibus 300mA for main charger no ibus adc charging: Ignore the PD vote icl unless BC1.2 done add charger ic - sc89890h config modules:add sm5602 patch to fix the soc jump problem FG: Modify SM5602 FG first update battery data time to 50ms add force_chg_auto_enable interface add firmware interface Disable irq before entering gesture mode and IC resetting. input: goodix_v1510: enable single tap function Support resend stylus cmd after abnormal resetting. Record and restore the value of the mode QC3P:use qc3p config distinguish other not qc3p project QC3P:detection and iio sys support z350: add 2nd z350 qc logic sgm:add enable termination function discrete:add enable termination iio definition qc3p:add main charger termination ctl algorithm QC3P:turbo charger module return value error dubai: vibrator add haptic rtp qc3p:optimize turbo charging current charging: add ibat monitor work fg: get current in real time sm5602: fix kernel panic when the device resume PEN_HALL:disable wakeup source fs:exfat-linux:Integrate exfat-linux open source driver fg/sm5602: Early detection device chipID fg/sm5602: correct the unit of vbat and temp sc89890h:device: add sc89890h device id focaltech_v3_mmi: rename .i file to fix potential build error focaltech_v3_mmi: enable firmware download focaltech_v3_mmi: add sys touch node & info module/input:hawao: add focaltech_v3_mmi for i2c flash Rhode 5GP: add wt6670 get firmware num node dubai: input touch update fw 21120803 DLKM/fps:add power ctrl for ets kernel driver pd: bring up sc2150a power:fet_control Balance ckt Fet Close Batt2 over 200mV wt6670: wake up wt6670 when get version num sm5602: Add new fgauge sm5602 QC3P:iio sys channel add kernel version QC3P:module name change to mmi_discrete_turbo_charger QC3P:discrete turbo charger FG:dynamic config sns resistance QC3P:detection and iio sys support QC3P:iio sys channel QC3P:add iio sys support QC3P:ADC algorithm compatible QC3P:copy of module mmi_parallel_charger_iio for mmi_discrete_turbo_charger goodix: support film sensitivity function. Support report rate switch in RoguePRC dubai: vibrator add long brk PD: Pick Richtek patch13 to improve irq response speed PD:Revert "(CR):rt1715:add debugfs interface for dump reg" PD: pick Richtek patch12 FG: power_supply_property get rt9426a battery info from local value dubai: input touch support fod sar: aw9610: Modify sar sensor voltage. moto regulator vibrator: fix null pointer bug charging: config ICL after BC1.2 done qti_glink_charger: Add wls_notify_callback qti_glink_charger: Add folio_mode qti_glink_charger: Add wls input current limit for thermal PD: config pd active is inactive status after cable plug out wt6670f_qc3p: qc3p wt6760 isp download function charging: add sem lock to protect dpdm detected FG:cw2217 Remove the redundant msleep in the read i2c operation FROMGIT: usb: gadget: f_mass_storage: Disable eps during disconnect sar: aw9610: the reference channel can't be seen on user layer bias/ocp2138:add support ocp2138 bias ic config fg: cw2217 add ui_soc feature IC needs to confirm the device within 50ms after power-on No need to send the suspend command when power off. Revert "(CR):power: cw2217 add ui_soc feature" bq2597x: bq2597x cp_enable interface does not work dlkm: sec_nfc: add samsung nfc driver dlkm: sd77426 driver add soh api power: cw2217 add ui_soc feature goodix_v1510_mmi: check if panel is available focaltech_v2_mmi: check if panel is available bms: do battery power supply change when fg update data Power: remove "\n" about mmi_discrete showing factory test node charging: add charge counter prop kernel:export interface tcpm_inquire_typec_remote_rp_curr charging: modify heartbeat cycle to 100s bms: modify battery capacity unit from mah to uah charging: remove useless power supply prop charging: remove FULL status in charging ic driver power:fet_control ironmn: ps prop usb type BRICKID regulator: Force shutdown all regulators when system power off. charging: stop charging when capacity > upper_limit charging: fixed otg boost current limit error Add pm_qos control to reduce the interrupt responce time wl2868c: modify ldo2 and ldo6 default voltage charging: fixed the error HVDCP voltage standard charging: set register 3250ma when icl >=3A smart_pen_charger: Add pen_status and pen_error notify qti_glink_charger: Add tx_mode and rx_connected sysfs node PD: Extend PD adapter class charge function charge: add chage&PD policy power: rt9426a update fcc design Rhode4G: Implement different ldo compatibility. Revert "(CR): Add pm_qos control to reduce the interrupt responce time" rhodep: camera power IC et5907 config Add calibration noise error handler Add pm_qos control to reduce the interrupt responce time rhode: rhode 4G camera ldo config[2/3] charging: fixed uevent block issue mmi_qc3p_wt6670f: int pin config to input mode Revert "(CR): Revert "Revert (CR) power:fet_control Vbatt2 balance path"" Revert "(CR) power:fet_control Remove ps_notification cb" qpnp_adaptive: Change Makefile to compatible with Android S build dlkm: Add check if panel is available for gt9916s power: fix rt9426a get the negative soc or soc jump Wallet shown slow when screenoff at qingdao mmi_qc3p_wt6670f: remove QC3.5 detection in shutdown ops power:fet_control Remove ps_notification cb Revert "Revert (CR) power:fet_control Vbatt2 balance path" charging: update charging status when power supply get support pmk8350 gpio3 as stylus clk. charging: use msleep instead of mdelay dlkm: silead_fps: remapping the keycode charging: defined default termination current 120ma charging: optimize ICO feature charging: schedule monitor work when charging charging: enable absolute vindpm support goodix edge suppression function. goodix: Support interpolation game mode function. stmicro: Add the judgment of the sensitivity mode value. dlkm: nfc: alway probe nfc driver mmi_qc3p_wt6670f: fix wt6670f driver bug Revert "(CR) power:fet_control Vbatt2 balance path" charging: optimize otg current setting logic Support leather mode setting. charging: fixed sometimes don't request dpdm issue sar: modify the vdd name for aw9610. mmi_charger: align gki 2.0 requirement charging: enable ILIM pin for bq25890H bq2597x_mmi_iio: add bq2597x gki and irq code bq2597x_mmi_iio: add bq2597x initial code mmi_qc3p_wt6670f: add qc3p logic initial code mmi_discrete_charger: modify enum redefined sgm4154x_chg_mmi: changed chg_en_pin judgment logic mmi_charger: modify enum redefined charging: fixed unit can't connected PC sometimes milan5G: sar sensor driver sar: add aw9610 driver charging: avoid vbus voltage increase to 12V charging: add qc3.0 arch for bq25890H power:fet_control Vbatt2 balance path, chrg fullcurr, ocp charge: add iio interface for typeC mode typeC: add iio interface for typeC mode charging: config charger power supply type unknown mmi_charger:use orderly shutdown in factory mode Close the stylus clock when system suspend. charging: avoid kernel panic Fix path for ion lib in Kernel 4.19 power: early register bms_phy client for cw2217_fg Update Trustonic TEE driver module to version 410a-V108 pstar: input touch add delay for mode Power: update fg current orientation charging: fixed get vbus voltage error charging: add VREG fine tunning for setting float voltage charging: replace numeric value with macros charging: adjust sgm41542 prob sequence sgm7220: add typeC mode switch interface for sgm7220 tcpc: add typeC mode switch interface sgm7220: Reorganize sgm7220 driver architecture Support goodix single tap to wake the device power: modified the caculation formula of ocv_checksum_dtsi charging: add qc3.0 charging feature sr100: Increase delay range on read/write goodix: support charger mode switching. stmicro: support touch film sensitivity switching milanf: dlkm: Support game mode by defualt on nova_0flash_mmi fts: deleate the PM_WAKEUP_EVENT in interrupt threaded DLKM: UI batt level show 100% when real batt level 0% Suspend and resume process using touchscreen class. power: cw2217b user_rsense modify to 10mhom charging: disable HVDCP detected Solve goodix tp firmware upgrade problem pct1812_mmi: no touch zones print ulog when write oem glink command bq25890: set input voltage limit 4600mv charging: setting icl=0 for usb suspend power: create chg_type node for factory test touchscreen_mmi: Support refresh reate notification in Rogue dubai: touch use gki api dlkm: fix vibrator stop fail issue typeC: add typec cc orientation interface typec: add host and device interface charging: add iio psy to provide api for other modules dlkm: rt9426a fg update read fg_extreg_table Cypfq: dlkm: Bringup touch CSOT ILI7807S dlkm: rt9426a fg update rt9426a_read_page_cmd charging: fixed user version build error for bq25890H wls-chrg: Add FOD_CURR and FOD_A/FOD_B settings API charging: dcp current base on dtsi config in mmi charger charger/bq25890: improve charger BC1.2 detection & rerun apsd typeC: import correct Modules.symvers in GKI build mode dlkm: Add focaltech fps module dubai: vib update file name power: discrete charger policy create force_chg_fail_clear dubai:input touch init setup Update goodix berlin touchscreen driver to v1.2.3 Power: discrete_charger policy create factory tcmd test node charging: optimize bc1.2 detect for sgm41542 DLKM/sar:optimise sx9375 driver on bo power: add get charing current api for discrete_charger_class power:fet_control: ironmn: Fix typo in chrg-fullcurr-en-gpio dlkm: add new regulator vibrator driver hall:fix not report issue pct1812_mmi: custom config options pct1812_mmi: report scroll gestures pd: add PD20/PD30 interface for tcpc pd: create pd adapter class charger/bq25890:export api for charger class goodix: support stylus mode switching. power: discrete charging solution intial version TCMD driver backlight: fix brightness flash issue Upgrade egis driver for supporting ET721 charging: fixed charging policy kernel panic Modify the config id and build id charger/bq25890: stop ADC when system shutdown sgm41542: provide some api for charger class charging: add discrete ics charging policy power: cw2217 fg's name rename to bms from battery power: rt9426a fg's name rename to bms from battery power: cw2217 fg add fcc/fcc_design info dubai: vibrator init setup power: rt9426a_fg introduce supprot muti-battery parameter func power: cw2217 introduce mutil-battery parameter func UWB: support build in kernel-5.10 sx937x:enable usb cal Charger/bq25890: force 5V/2A charging power: cw2217 fg update battery parameter power: rt9426a register charger_full node power: apply 1th battery parameter for CW2217 fg power:fet_control: Add logic for ironmn EVB HW 2nd Batt charger/bq25890:disable maxcharge handshake charger/bq25890:pull charge enable pin low when charge Revert "(CR) build: Only include modules needed by product" charger/rt9467:remove MMI_STOPSHIP change. Add a new DLKM to support smart pen charger driver Add OEM glink notification and notifier call chain charger/bq25890: add usb properties Resolve compilation errors for unused functions qti_glink_charger: extend addr&data to UINT32 typc: Open macro for TCPC charging: force 5V/2A solve the kobject_get_path undefined in gki build Only save test file in factory build sgm7220: add sgm7220 pwr interface charger/bq25890: force D+/D- detection for APSD typec: Open pd dbg info Does not distinguish 9916 and 9916P touch chips. touchscreen: dynamic check the goodix device status touchscreen: dynamic check the stmicro device status mmi_info: provide check dynamic device status interface xpeng: input touch add wait when single tap mmi_info: Get bootconfig from device tree utags: read utag block device path in bootconfig from device tree utags: Use bio to replace kernel_read and write API charger/bq25890:add BC1.2 feature rt1715:add debugfs interface for dump reg power/charger: add init bq25890 driver power: rt9426a_fg add soh api power: introduce fuel gauge cw2217b driver backlight: support backlight current align configuration for exp mode backlight: add lm3697 map type for linear or exponential mode backlight: add aw99703 map type for linear or exponential mode goodix: support factory tcmd test. goodix: update test file to 1.2.2 version charging: detect hw chip id before do any action Power: enable rt9426a fg parse dts function power/charger: add walkaround to fix REGN side effect power/charger: add free IRQ before reset goodix: enable stylus clock on Rogue project. charging: add HVDCP detected function backlight: don't enable aw99703 backlight while brighness level 0 pct1812_mmi: properly fail probe on i2c error Revert "(CR): mmi_charger: Fix battery_supply_init, batt_psy." power/charger: add rt9467 charger driver mmi_charger: Fix battery_supply_init, batt_psy. Support loadding multiple config files build: Only include modules needed by product pct1812_mmi: control debug messages pct1812_mmi: added input device pct1812_mmi: firmware update feature dlkm: add new silead fps driver Add sysfs to support force disable charging qti_glink: Add sysfs node to get wireless chip id add lpd and vbus present state Send LPD and VBUS uevent for LPD alarm feature vibrator: add new ldo vibrator driver Support touchscreen calss in the goodix drvier code. qti_glink_charger: move WLS property types to the end GKI kernel build upgrade build: Only include modules needed by product set screen default state to on dlkm: sd77426 modify battery NTC table fet_control: Add fet_control driver, full_current_en charging: add usb property charging: update sgm41542 driver V002 usb: mass_storage: Add support for SC_REBOOT typec: define sgm7220 typec func fix mass_storage module GKI build issue copy mass_storage driver from Kernel as initial version typec: improve rt1715 code typec: remove qcom pmic code arm/dts: improve rt1715 typec and pd compatible hall pen kernel bringup typec: Add sgm7220 driver initial version charging: add bc1.2 feature DLKM: force 5V/2A charging charging: fixed build error for sgm41542 default code charging: add SGM4154x charger basic driver pct1812_mmi: self-test and sysfs interfaces power: add detect sd77624 ic hw goodix_brl_mmi: Add mmi status check. Modify the goodix driver code format Update the poll mask when polling is aborted by hal mmi_sys_temp:fix compilation error. power: update sd77624_fg driver qti_glink_charger: Add sysfs node for factory wireless testing charge:Enable aicl at factory boot mode touchu:gc7372 tp modify for charger test and gesture usbnet:USBLAN Super speed plus support dlkm/wl2866d: disable avdd1 when device shutdown backlight: add aw99703 led boost configuration charge: define pps charge min out current charge: add limit main charge flag DLKM: Update SD77426 driver Add panel notification for egis rbs driver regulator: fix aw37501 gki build error regulator: add aw37501 lcd bias power driver pd: Add rt1715 driver initial version Cypfq: dlkm: Gc7372 add enable/disable wake irq for single tap Support sensitivity mode function power: introduce sd77426 fuel gauge driver power: add rt9426a driver add glink oem command to get LPD info focaltech_v2_mmi: keep rst high when config only for IDC mmi_info: Increase the MAX_BL_BUILD_SIG Cypfq: dlkm: Add power off process for ili9882a Update goodix berlin code to V1.1.21 charge: notify mmi-smbcharger-iio while charge pump start working charging: Add PD charging in DLKM pct1812_mmi: firmware upgrade pct1812_mmi: pct1812ff kernel driver Cypfq: dlkm: Add charger detection feature for ili9882a mmi_annotate: support minidump store Support touch corner/edge suppression function. Cypfq: dlkm: Support single tap feature for gc7372 cp: Remove charge rate, age, cycle Cypfq: dlkm: Change read vendor id process hall driver bring up watchdogtest: support build in kernel-5.10 Cypfq: dlkm: Improve gcore_mmi driver Cypfq: dlkm: Add GKI module dir definition charging: modify heartbeat cycle to 100s remove the mmi_info module dependency dlkm: bo: Support single tap feature for ili9882_mmi charger: Rename sc8549 to cp xpeng: input touch add game api charger:adaptive charger tolerance optimization goodix_fod_mmi.ko: Update Makefile to compat kernel 5.10 Use bi_bootmode instead of mmi_bl_bootmode. When find drm panel successfully, set panel_status to 0 FPS: Support multi-fingerprint function. put register_panel_notifier into ts_mmi_worker_func. Delayed active panel detection backlight: fix lm3697 probe fail panic backlight: add lm3697 led boost configuration use bi_bootmode to query the bootmode Cypfg: dlkm: Improve gcore_mmi driver fixup! (CR): mmi_info: read all from bootconfig mmi_info: read all from bootconfig backlight: add lm3697 hbm current mode configuration mmi_info: read bootreason from bootconfig utags: reads bootdevice name from bootconfig qpnp_adaptive_charge: Add adap_reinit charge: resolve sc85xx charge icon dont disappear cp: improve 8549 read status register modules: add leds-indicator-pwm.c driver parallel:init thermal parameter at high temp Rogue PRC ST54x driver Close the calibration operation after fwupdate. Modify bm ulog and mmi chargers for Android S focaltech_v2_mmi: disable focaltech driver drm notify ffc: add ffc featrue CP: Remove unuseful code qc3p:workaroud qc3p shalcomm adapter Modify the touchscreen report rate CP: Use CP read battery voltage slg5bm43670: Update slg5bm43670 for Kernel 5.10 QC3P:add afvc compensation voltage PD:add afvc compensation voltage pstar: input touch update edge set pstar: input touch add edge support focaltech_v2_mmi: don't set gesture_mode enable as default Adjust the heartbeat time to 100s in discharging state sx937x:Android S bringup Solve the problem of incompatible type 'struct timespec64' Slove the build error: redefinition of 'panel_event' fpc_fps_mmi: Modify Makefile for Android S build ko adjust moto_f_usbnet driver makefile Bring up touchscreen_mmi in Rogue S project. Bringup stmicro_mmi touch module in kernel-5.10 Cypfg: dlkm: Improve gcore_mmi driver Revert "(CR) sx937x:mv ps_get_state to work callback" Revert "(CR) sx937x: change global_sx937x initialization position" Modify the ITO test command sx937x: change global_sx937x initialization position sx937x:mv ps_get_state to work callback qpnp-adaptive-charge: use mmi_charger to contrl battery charging add vote mechanism support for mmi_charger qc3p:limit pulse not beyond max count use disable_irq_nosync in interrupt handler Add force_charging_enabled sysfs Add force_charger_suspend sysfs CP: add cp switch enable detect CP: force disable CP while plug out usb cable CP:Add switch enable detect function cp: config sc8549 fault bit Fix the build error on denver project. add charger state sync interface Revert "(CR): send charge rate uevent when power supply changes" Need to update fw on resume for zero-flash touch IC. novatek: Support parameter upgrade method st21nfc:support build in kernel-5.10 qc3p:Set AICL thres at qc3p pmic charging dlkm: add enable CP api add power ctrl for fpc driver add power ctrl for goodix kernel driver aw8695: move camera start entry before the vibrator timer dlkm: Touch gc7372 bringup pstar: vibrator add moto fw Fix artificial vibrating pattern caused AF always on. charge: Add thermal interface qc3p:clear sm work when vbus off Add sense off process to enter the idle process. CP: add qc3p charge policy CP: Reorganize charge pump Print ADSP battery manager log if charging changes Create bm_adsp_ulog module qc3p:config 33W charging current sx937x:fix wrong POWER_SUPPLY_ONLINE define Cyprus: dlkm: ili9882 driver improvement input: focaltech_v2_mmi: add ft3519 upgrade function Solve the build error: MODULE_IMPORT_NS missing pstar: sar: support multi parameters for different panels aw8695: optimize vibrator&camera resonance issue Stmicro: Support parameter upgrade method Add flash mode sysfs node in touchscreen mmi dlkm: lm3697: free resouces when init failed DLKM: bring up corfup PD 30W charging charging: pick base parellel charger from mmi_parallel_charger send charge rate uevent when power supply changes bq25980:update charge VOUT parameter bq27426: Fix kbuild to use ANDROID_BUILD_TOP mmi_info: support build in kernel-5.10 mmi_annotate: support build in kernel-5.10 utags: support build in kernel-5.10 bos0614_mmi: fix alignment issue Enable PANEL_NOTIFICATIONS for berlna touchscreen Revert "(CR): fix user version build error" Add NVT_SET_TOUCH_STATE to avoid compilation errors Deleate fts_system_reset in wait_for_ready Add 30W turbo charger type touch mmi:declare dependency. dlkm: leds_aw99703: free gpio if init failed dlkm: leds_lm3697: add initial version lm3697 driver Fix berlna user version build error. Support novatek single tap in berlna fix user version build error sx937x:change offset val bit mask touch mmi:2nd patch, fix user version build error. touch mmi:Fix user version build error. charger:mmi_hb_wake lock not released SX937x: USE power online state bos0614: access to sysfs for others bos0614_mmi: waveform shape feature focaltech_v2_mmi: bringup ft3519 on kernel 5.4 qc3p:config ibus max to 3A mmi_parallel_charger:reduce charge rate report dlkm: Cyprus: touch: ili7807s bringup Add Egis fps kernel module for rbs Support report rate switch Add game mode parameter adjustment function input: goodix_v1510: change to api in chip vendor whitelist Add pollForEvent check mechanism smbcharger:QC3P charging support module:QC3P charging support init module:mmi parallel charger qc3p repo init bos0614_mmi: support rev C Delete the calibration process on probe Support single tap to wake the device power:fet_control: Charge path gpio too slow Fix the BTN_TOUCH report error Solve the issue that firmware can not be updated. Add support for Build_external_kernelmodule.mk touch:sleep in atomic context input: goodix_v1510: set regulator avdd load to 50mA Do not set scan mode when setting charge mode use request_threaded_irq to handle TP events. focaltech_0flash: rm register_panel_notifier null define bos0614_mmi: fix few bugs input: focaltech_0flash_mmi: add panel notifications Report BTN_TOUCH event when the fingers are lifted. fet_control: banks: Enable only pm8350b chrg for usb2/3 sx937x: reset sar on i2c failures update the charger_suspend config in charger configure synaptics_mmi_class: fix broken build berlNA: support usb detection of novatek TP. Get usb status through POWER_SUPPLY_PROP_ONLINE property. stmicro: Add USB detection based on touch class ETS: Solve the compilation problem of androidR Support TP report rate switching regulator: wl2866d: support to read init value from dts Resolve compilation errors for nio Support touchscreen class for novatek Move sysfs node to the parent of battery device power: fet_control: Update paths on usb psy prop online qrng: Add qrng driver qti_glink_charger: Add sys node to pass TCMD to ADSP qti_glink_charger: Add sys node to set pmic_icl Resolve compilation errors with unused parameters "ret" Resolve compilation errors with unused parameters charge: add sc8549 driver for corfuP product Export panel supplier method for ST Use supplier to distinguish limit files. power:fet_control: Batt flip dischg fet ctl, chg cur_en qti_glink_charger: Add sys node to pass TCMD to ADSP input: goodix_mmi: add goodix i2c 1510 version driver qti_battery_charger_mmi: Initial add bq25890_mmi: Fix power supply type mmi_charger: Add voltage and current combos driver:adjust bq25960 parameter synaptics_mmi_class: gpio access func can sleep Add calibrate sysfs node for stmicro TP. synaptics_mmi_class: rename files bq25960:remove online property power:fet_control: banks flip batt fet-control driver mmi_charger: Add ext_charger bq25890: Add get/set for fcc and fv Revert "(CR) synaptics_mmi_class: fix build issue" bos0614_mmi: added features synaptics_mmi_class: fix build issue Support fw update at device startup for berlin. fixup! (CR) synaptics_mmi_class: banks cli bringup synaptics_mmi_class: banks cli bringup smb:integrate charge pump ffc feature stmicro_mmi: build and config ids Remove pressure events charger:bq25960 30w charger support charger:enable charger rate at 30w charger Enable irq during touch resume for berlin. pstar: input touch stm fix issue fixup! (CR) stmicro_mmi: bug fixes and new features stmicro_mmi: bug fixes and new features pstar: input touch fix disable irq panic Get the profile id from device tree Add new platfrom driver to support smb charger Add change to be more compatible Reorganize files to meet compilation mechanism on enabled GKI products. aw8695: Fix compilation error of aw8695 for android R Make Trustonic TEE driver module compatible with kernel 5.4. mmi_parallel_charger:enable parallel charger at R charge: Config charge rate for internal FG product Charge: Config step first current comp for CP Charge: config min tuning current Charge: Clear err flag before start CP mmi_parallel_charger: Add Turbo_30w power level charge:notify smb5 while charge pump start working dlkm: no need rerun aicl for odessa dlkm: add enable CP api mmi_parallel_charger: set charge_control_limit as writeable mmi_parallel_charger: UI support for 45W charger fg: soc report 99% lasted for long time mmi_pl_chg: Add mmi_cycle_count to calculate batt age mmi_parallel_charger: Add factory mode detect mmi_pl_chg: clear pmic limit after remove pd power mmi_parallel_charger: "battery" psy update PROP_STATUS mmi_parallel_charger: optimize 45w charger policy optimize the charging logic in thermal mitigation process Improve the PD charging performance in high temperature mmi_paralel_charger: Enhance the compatibility of PD charger mmi_parallel_charger: enhance the stability of sm work mmi_pl_chrg: improve the chrg recovery handling mmi_chrg_manager: optimize thermal mitigation logic mmi_pl_chrg: create some sysfs node for setting mmi_params mmi_parallel_charger: optimize temp zone structure mmi_parallel_charger: Optimize 40w charging logc, 1.0 mmi_parallel_charger: Optimize 40w charging policy mmi_parallel_charger: Create Heartbeat work DLKM: mmi_parallel_charger pstar: input touch support cqa test bq25890: commit initial version bq27426: guard extra batt props correct the charger present based on charger type pstar: input touch stm bring up dlkm: bo: Improve touch driver for novatek bos0614_mmi: build kernel code bos0614_mmi: initial reference driver mmi_charger: Option to start with no factory kill sx933x: handle reinitialize during suspend pstar: input touch st bring up charger:revert parallel charger driver Update Trustonic TEE driver module to version 410a-V107 synaptics_i2c: Compilation errors Revert "(CR) synaptics_mmi_class: banks cli bringup" sec_mmi: fix regulator get/put synaptics_mmi_class: banks cli bringup kernel:charger rate duplicate with parallel charger kernel:paralle charger driver kernel:bq25980 charger driver raydium_mmi: fix build error uwb: sr100: add gpio-exp dep for banks regulator: Add wl2866d driver. ili9882_mmi: CQA test node update for tianma panel nio: input touch add edge suppression regulator: init all wl2864c register when probe driver driver/GoodixFP Add the soft dependency of gpio-pcal6408 Add register dump interface for WL2864C Revert "(CR): Add register dump interface for WL2864C.." Adjust the charger configure data Adjust charger configure data Add register dump interface for WL2864C.. Fix compile errors for ilitek_0flash_mmi module Fix deprecated function call on ilitek_0flash_mmi regulator: modify wl2864c iovdd current limit fpc1020: fix null pointer panic issue exfat:Fix panic of handlings of unhashed alias ili9882_mmi: support ili7806s IC dlkm: Improve novatek touch process when using GKI uwb: sr100: make clocks optional uwb: sr100: allow cansleep gpio funcs gpio: pcal6408: fix set output qpnp-smbcharger-mmi: Add PD charging in DLKM dlkm: sn1xx: fix tcmd ioctl error DLKM: leds_aw99703: support update by panel config sm4350/sensor: optimze sx937x log output nio: input touch nova add delay for request fw retry dlkm: fix free irq warning for chipone sensor Charge: report battery power supply change vl53l5: Support 32bit compatible Kernel driver for vl53l5 dlkm: fpc1020: free gpio when remove Correct the config_id and build_id errors of focaltech IC gpio: pcal6408: add initial module Modify compilation error of synaptics Modify compilation error of sec_mmi Modify compilation error of stmicro qpnp-smbcharger-mmi: Add charge_full_design in battery psy mmi_sigprint: Fix CFI check failure input: focaltech_v2_mmi: change some focal driver macros synaptics_tcm_mmi: mmi status check stmicro_mmi: mmi status check sec_mmi: mmi status check stmicro_mmi: identify product by chip id stmicro_mmi: update driver to version 5.2.19 stmicro_mmi: use with touscreen class driver input: touchscreen_mmi: add palm detection sensor class input: focaltech_v2_mmi: add palm detection function aw869xx: keep using default device name dlkm: add qti_glink_charger driver dlkm: charger driver for Moto common features DLKM: mmi charging LKM must probe after qpnp smb5 DLKM: use new api in mmi-pmic-voter.c Revert "(CR): DLKM: build error on user build" module: remove useless code in charging LKM input: focaltech_v2_mmi: enable single tap function input: focaltech_v2_mmi: add usb charger detection input: focaltech_v2_mmi: add sys node to upgrade firmware mmi_sigprint: Use a new way to get kallsyms_lookup_name() kernel:stop incresing vubs while charger plug out usbnet: correct usb_ether_xmit return value aw8695: Add start/stop vibrating notification to actuator. usbnet: fix CFI checking failure module: use orderly shutdown in factory mode denver/sensor: update sarsensor params module: add address and data api for tcmd Chipone: Compatible with android R with 5.4.0 dlkm: bo: Improve novatek 0flash driver FM: fix current leak on GPIO47 add mmi_relay notify interface by conditional module: removed nonstandard props qpnp-power-on-mmi: fix build error on user build mmi: fix power supply change frequently dlkm/qpnp-power-on-mmi: change vfs_write to kernel_write ili9882_mmi: support panel gesture config ets_fps_mmi: Register panel notifier for display on/off input: focaltech_v2_mmi: Configure power supply dlkm: bo: Support multi panel-supplier for novatek DLKM/Sar:add abov 7ch driver input: focaltech_v2_mmi: add V2 version of i2c focal driver Register mmi_relay notification for touchscreen Register mmi_relay notification for FOD An common module used for all of module communication. Revert "(CR): An common module used for all of module communication." Revert "(CR): Register mmi_relay notification for FOD" Revert "(CR): Register mmi_relay notification for touchscreen" mmi_relay: Add gki flag to avoid module load failure driver/sar-sensor: sx937x bring up Register mmi_relay notification for touchscreen Register mmi_relay notification for FOD An common module used for all of module communication. ili9882_mmi: deep sleep update with gesture config nova_0flash_mmi: improve panel-supplier ili9882_mmi: tp suspend improve dlkm: bo: Support multi panel-supplier for novatek on 5.4.0 UWB bring up for driver ili9882_mmi: improve RESUME_BY_DDI support nova_0flash_mmi: add LCM_FAST_LIGHTUP support Support tapTowake feature on android R for novatek chipone_tddi_mmi: ICNL9911C and ESD improve exfat: fix build err on user build. chipone_tddi_mmi: support ICNL9911C NFC driver mmi and DLKM support driver/sar-sensor: build error on user build driver/sar-sensor: sx937x bring up Continue to probe touch even if no matching panel is found DLKM: build error on user build [capsensor] add debug support for cap sensor Add 5ms delay for wl2864c ramp-up driver/sar-sensor: build error on user build dlkm: bo: Fixed compile error on android R [capsensor] add debug info for read_rawdata Ibiza: Touch ICNL9911C bringup Revert "(CR): utags.ko: solve the unused remove_proc_subtree symbol definition" Revert "(CR): utags.ko: force this module unloadable" DLKM: disable update_now and usb_otg property DLKM: bring up charging module DLKM: submit the charging base code watchdogtest: add qcom_wdt_trigger_bite for trigger wdog exfat: workround end_buffer_async_write undefine issue in GKI 5.4 guamp: input touch fix esd lock issue dlkm: chipone: fix build error on kernel 5.4 driver/sar-sensor: add sx937x base driver hall: stylus bu520xx: Fix wakeup_source event API change touch:nt36xxx: add ESD config hall: stylus bu520xx: fix the compilation errors mmi_info: export API for dynamically match mmi device exfat:fixed exfat compliling failed on kernel 5.4 touch:nt36xxx: NT36525c improvement touch:nt36xxx: support panel ic info Force Trustonic TEE schedule run in Silver cores. ili9882_mmi: capri txd/tm ili9882 touch bringup Revert "(CR) ili9882_mmi: capri txd/tm ili9882 touch bringup" ili9882_mmi: capri txd/tm ili9882 touch bringup denver: modify wl2864c driver touch:nt36xxx: support nt36525c touch:nt36xxx:support panel config dlkm: bo: Bringup touch driver for novatek Modify the compilation error of the device_create function Use alloc_chrdev_region instead of input_get_new_minor the battery should be charged in taper-charger until iterm dlkm: bo: Bringup touch driver for novatek sx933x: Add a dummy flush function sx9338: sar sensor bring up Capri:Add compability of chipone driver Capri:Add support for Chipone FPS input: ilitek_0flash_mmi: change memcpy wlen value Fixing factory kill function Flip sign of current during taper check Add battery profile v5 Print all Ra tables watchdogtest: fix kallsyms_lookup_name issue in GKI 5.4 touchscreen_mmi: import correct Modules.symvers in GKI build mode tzlog_dump: use ioremap to map ram from kernel 5.4 tzlog_dump: workaround msm_dump_data_register undefine issue in GKI 5.4 Add battery number to logging fix ITPOR and CFGUPMODE logging sec_mmi: import ANDROID_GKI_VFS_EXPORT_ONLY namespace for kernel_read utags: import ANDROID_GKI_VFS_EXPORT_ONLY namespace for kernel_read Refactoring code to use new wake API himax_0flash: fix driver resume issue focaltech_0flash_mmi: add reg log when tp not in normal mode guam: input touch ilitek set deep sleep mode Add Trustonic TEE driver module input: ilitek_0flash_mmi: add ic_ver sys node for MotoCare mmi_info: import correct Modules.symvers in GKI build mode guam: input touch ilitek enable gesture ili9882_mmi: fix build breakage on R guam: input touch add ic_ver support ets_fps: filter unexpected double-click event mmi_info: add dependency of mmi_annotate module qpnp-smbcharger-mmi: Charger Temp change adjust utag: free the buffer when failed to open utag utag: report the return value of store_utags() to userspace guam: input update touch ilitek fw 02 Turn off the output log of the LSI touch FW raw data. modify the compilation errors of goodix_berlin sec_mmi: Don't USE_STUBS restrict compilation for snd_soc_tfa9874 fixup! (CR): Instead of vfs_write with kernel_write Instead of vfs_read with kernel_read Revert "(CR): Instead of vfs_read with kernel_read" Instead of vfs_read with kernel_read Instead of vfs_write with kernel_write synaptics prob if it matches the value of "mmi,panel_name" Specify the dependency of the synaptics touchscreen modules. Modify synaptics compile error on Viking. Add CONFIG_DRM_PANEL_PANEL_NOTIFICATIONS on Viking Determine whether to load by "mmi,panel_name" touch: nt36xxx: Resolve include build error Awinic: aw8624: Replace wakeup_source API with macro touch: nt36xxx: Replace wakeup_source API with macro pmic: Replace wakeup_source API with macro mmi_wake_lock: Resolve malloc build error Awinic: aw8695: Replace wakeup_source API with macro Awinic: aw8697x: Replace wakeup_source API with macro Awinic: aw8697: Replace wakeup_source API with macro touch: synaptics: Replace wakeup_source API with macro touch: focaltech: Replace wakeup_source API with macro touch: sec_ts: Replace wakeup_source API with macro touch: ilitek: Replace wakeup_source API with macro touch: fts: Replace wakeup_source API with macro misc: ets_fps: Replace wakeup_source API with macro touch: synapticsi_dsx: Fix wakeup_source event API change wakeup_source: Choose wakeup_source API based on version aw8624: Fix build error due to wakeup API changes nt36xxx: Fix build error due to wakeup API changes Specify the dependency of sec_mmi on touchscreen_mmi Slove the compile error of of_drm_find_panel function himax_v2_mmi: fix build failure Modify samsung compilation errors for viking. Temporarily modify the value of device minor Add mmi_bl_bootmode function to get boot mode. Add DRM PANEL notifications to touchscreen tas2562: fix build failure input: ilitek_0flash_mmi: add usb charger detection Modify touchscreen class compilation errors on Viking. vl53l5: add stmvl53l5 init and deinit functions vl53l5: initial version of vl53l5 sensor driver usbnet: fix GKI compliance issue on sock access dubai: bring up goodix fingerprint for android R guam: input add touch ili9882n factory support guam: input add touch ili9882n support DLKM/Sar:remove CONFIG_CAPSENSE_CONTROL_VDD for borneo NA DLKM:modify capsensor_enable_flag_t enum for abov aw869xx: Fix build issue on Viking aw869xx: Add awinic 869xx haptic driver regulator: modify slg5bm43670 driver to support kernel 5.4 fir: update for coefficient read cci: modify cci_intf driver to support kernel 5.4 DLKM:control VDD off when sar sensor is off Modify the compilation error of ST touchscreen on Viking guamna: input touch himax runin debug aw8697: play weak haptic on implicit setup aw8697: improve latency synaptics_mmi_class: remove handler fix fts: support touchscreen class Sx933x:use ANDROID_BUILD_TOP in Kbuild utags.ko: force this module unloadable Revert "(CR): qpnp-smbchrgr-mmi: Optimize charger current over Temp" fg: Add Golden Profiles v4 qpnp-smbchrgr-mmi: Optimize charger current over Temp DLKM: himax_v2_mmi: fix compile error AndroidKernelModule.mk: use Qcom dlkm file for GKI products sec_mmi: add clip area guamna: input fix touch himax allocate memory Revert "(CR): AndroidKernelModule.mk: sync the file with qcom dlkm" AndroidKernelModule.mk: sync the file with qcom dlkm power: Fix build error due to wakeup API changes aw8695: Fix build error due to wakeup API changes ets_fps: Fix build error due to wakeup API changes focaltech_0_flash: Fix build error due to wakeup API changes focaltech_0_flash: Fix build error due to wakeup API changes ets_fps: Fix build error due to wakeup API changes aw8695: Fix build error due to wakeup API changes power: Fix build error due to wakeup API changes Initial goodix_berlin touchscreen driver code touchscreen_mmi: fix undefined symbol error on kernel 5.4 mmi_sys_temp: use ANDROID_BUILD_TOP in Kbuild exfat:fixed fs_error access null pointer ikswq-123771: power: scale down initial chrg curr sensor_class: use ANDROID_BUILD_TOP in Kbuild mmi_info: use ANDROID_BUILD_TOP in Kbuild mmi_annotate: vmap the physical ram in kernel 5.4 utags.ko: solve the unused remove_proc_subtree symbol definition Egis.FPS Call early panel power-on when finger detected guamp: input add touch ilitek support nt36xx: Fix bld error due to wakeup_api_changes focaltech_0_flash: fix bld error due to wakeup API changes touch: nt36xxx: fix build error due to wakeup API changes ets_fps: fix build error due to changes in the wakeup API fix ST NFC driver compile error power: Charge curr over adjustment- check both batts power: Schedule 1sec smbchrg heartbeat when in ocp guam: input update init drm callback timer guam: input add touch ilitek support synaptics_mmi_class: postpone loading functions focaltech_0flash_mmi: ft fw file not found focaltech_0flash_mmi:8006s_aa update irq config input: touchscreen: Check buffer size input: touchscreen: focaltech: fix pointer comparison Kiev: Add usb detection based on touchscreen class Initialize usb state when registering the usb notification sx933x: reinitialize via i2c watchdog Add SOH function qpnp-smbcharger-mmi: Offer hvdcp_power_max setting by sysfs sx933x: reset and re-init the device on i2c failures power: Remove FG reset for factory bootmode focaltech_0flash_mmi:8006s_aa enable irq when supspend power: Remove FG reset check for factory sw build Add macro definition to control unused code in Kiev Kiev: ft8756:report touch events to touchscreen class Double tap optimization focaltech_0flash_mmi: fix tp recovery issue for fts8006s_aa power: TI FG dm_ver3 aw8695:Ensure wakeup_source API is compatible for all kernels aw8697: optimize sequencer registers write aw8697: i2c transaction logging aw8697: treat 100ms haptics as short vibration fts: initial STmicro touch driver code fixup! (CR): touch:Ensure wakeup_source API is compatible for all kernels awinic:Ensure wakeup_source API is compatible for all kernels touch:Ensure wakeup_source API is compatible for all kernels pmic: Ensure wakeup_source API is compatible for all kernels touch: Fix sec_ts build error due to wakeup_source API Awinic: fix build error due to wakeup_source API's touch: synaptics: Fix wakeup_source event API change Power: fix implicit bld errs of wakeup_source API's focaltech_0flash_mmi: Add ESD log config power: smbcharger: Heartbeat Delay if FG reset incomplete vl53l1: Make do_gettimeofday compatible to new Kernel version usbnet: Use KERNEL_DS to replace get_ds() for compilation Kiev: Add ft8756 single-tap wakeup gesture Revert "(CR): Send the touchscreen status to display" Send the touchscreen status to display ITERM80 mA DLKM: add ktd3136 backlight Add sys node ic_ver and name DLKM: ilitek_0flash_mmi: add ilitek driver patch for dma input: ilitek_0flash_mmi: pull down reset when shutdown focaltech_0flash_mmi: CONFIG_DRM_PANEL support mmi_info: fix undefined symbol error on kernel 5.4 mmi_info: remove unexported symbol in kernel5.4 Kiev: Add touchscreen class for focaltech fir: update the power manage logic aw8624: Upgrade driver from 1.0.7 to 1.3.9 Change double tap interval for Egis FPS input: ilitek_0flash_mmi: reset IC if esd recovery fail Increment dm_ver Fixup the definition of unregister_panel_notifier focaltech_0flash_mmi: enable ESD for ft8006s_aa KeivJP: bringup chipone fps driver Added dts901b1 thermopile kernel module input: ilitek_0flash_mmi: import some ili common changes DLKM: leds_aw99703: change backlight type to Platform Use kernel_definitions.mk if AndroidKernel.mk not existed input: ilitek_0flash_mmi: resume touch by ddi Add Golden Profiles from testing input: ilitek_0flash_mmi: add support for single tap qpnp-smbcharger-mmi: update ocp check synaptics_mmi_class: handle delayed init DLKM/sar:optimise process of sar to support 4 channels aw8695: nairo: add 3 ATT ringtone waveforms himax_v2_mmi: Add productinfo & buildid sys node focaltech_0flash_mmi: support FT tp ft8006s_aa Guam: input update touch chipone resume time synaptics_mmi_class: panel ready handling aw8697: Add "Moto Retro" to ringtone map fg: Trigger POR in factory mode or factory software DLKM: leds_aw99703: don't pull down enable pin again racer 5G: aw8695: Add 3 new ringtone waveforms aw8697: A fix of rtp playing from Awinic aw8697: Stop repeatedly waveform playing aw8697: Support repeatedly waveform playing adjust factory image identification guam: input add moto care support aw8695: A fix of rtp playing from Awinic aw8695: Cancel the 120s timer when stopping vibrating aw8695: Stop repeatedly waveform playing guam: input touch add class ic_ver support dlkm: Add himax touch info node for Moto Care Revert "(CR): modules: power: Add Adaptive Charging feature" Revert "(CR): qpnp-smbcharger-mmi: Fix getting stuck in adaptive mode" mmi_sys_temp: Add thermal sensors monitor work dlkm: Add novatek touch info node for Moto Care Add the judgment on gesture_enabled configuration in dtbo Double tap optimization aw8697: smith: Add boot-up vibration synaptics_mmi_class: fix suspend/resume callbacks Release touch events after suspend Set the type of release event to the correct value. dlkm: Improve himax_0flash_mmi for single tap add dm_code ver 1 to both fg p938x_charger: wake lock initialized too late capsense: Add dummy set_poll_delay function touchscreen_mmi: optimize poison event synaptics_tcm_v2: Add touchscreen class handle touch event touchscreen_mmi: Add poison slot support. guam: input update touch chipone driver version dlkm: bo: Clean up focaltech_0flash_8756_mmi ilitek_0flash_mmi: add ili9881x initial driver backlight: Add wleds driver aw99703 Nairobi hx83112f touch driver improvement ASoC: aw882xx: set speaker default impedance value aw8695: Support repeatedly waveform playing Set the default value of gs_distance is 0x1e Syna: Modify the baseline update process touchscreen_mmi: do not lock in irq context [Kiev]To support USB calibration sx933x: update flip registers after init sx933x: turn off sensing before flip updates Add qpnp_adaptive_charge module touchscreen_mmi: Properly handle the deletion process. Add more configuration commands for FG guam: input update touch himax driver sec_mmi: show firmware version info touchscreen_mmi: Control baseline update by FPS notifier sec_mmi: Add update baseline method for lsi IC touchscreen_mmi: Add update baseline entry goodix_fod_mmi: Add device enable notifier chain aw8697: Disable external triggers touchscreen_mmi: selete on state when panel register. Synaptics: Add hold-distance function, command is 0xdc. synaptics: Add suppression control function Report finger lift events after touch suspend. synaptics_tcm_v2: Add wait_for_ready methord touchscreen_mmi: Add default pinctrl methord Solve NFC wake lock issue touchscreen_mmi: exports touch events handler Syna: Report down/up touch events to touchscreen class touchscreen_mmi: qcom drm notifications support sec_mmi: fix compile error add panel_notifier.h to mmi kernel modules area Syna: Modify the ratio of the major and minor values guam: input update touch himax driver input: himax_v2_mmi: Sync touch suspend and resume thread input: himax_v2_mmi: set hx83012d only if defined Set up common vendor id for fps fg: Trigger POR through sysfs instead of factory mode capsense sx933x recive headset state ASoC: implement ICN control in TAS2562 Fail out of probe gracefully smbcharger-mmi: Report turbo charging for wireless p938x_charger: report fast charging if >= 15W Revert "(CR): touchscreen_mmi: Do not write if value is same with cached" Fix complilation error after removing -fno-builtin qpnp-power-on-mmi: support hw_warmreset feature fix 'rmmod ets_fps_mmi' error Use touch class unified interface to support edge gesture touchscreen_mmi: Do not write if value is same with cached touchscreen_mmi: use try to call and try to read touchscreen_mmi: update RW sys entry. touchscreen_mmi: Only update refresh & charger when active touchscreen_mmi: Add macro to get touch status touchscreen_mmi: Add edge touch support Revert "(CR) qpnp-power-on-mmi: support hw_warmreset feature" it will cause compile error on other mainline qpnp-power-on-mmi: support hw_warmreset feature touchscreen_mmi: Correctly Initialize temp cmd variable sx933x: update registers on open/close Reset fuel gauge in factory mode Modify synaptics' log information Add power flag to indicate power status. dlkm: Himax 0Flash touch improvement dlkm: Himax 0Flash touch improvement dlkm: Himax 0Flash touch improvement dlkm: Himax 0Flash touch improvement ASoC: add aw882xx volume ramp function exfat: use kvzalloc instead kzalloc in exfat_fill_super(). power: bq_27426_mmi: Add FG OCV voltage support Syna: USB detection support dlkm/sensor: optimize sx933x boot-time Modify the value of synaptics major and minor Solve resume and suspend confusion,causes touchscreen crash Revert "(CR): exfat: use kvzalloc instead kzalloc in exfat_fill_super()." exfat: use kvzalloc instead kzalloc in exfat_fill_super(). DLKM/sarsensor:add tcmd test interfaces for abov mmi fixup! (CR): aw8697: Add error checking to RTP mode fixup! (CR): goodix_gtx8_v1430_mmi: Port goodix v1.4.3.0 driver code fixup! (CR): create mmi_info module Pass absolute path of "TOP" to Kbuild. ASoC: aw882xx:correct a property variate in parse dt dlkm: Himax: Apply for new interface for single tap himax: Compatible with the way of gesture to report key ASoC: aw882xx driver update support pill region and gs-distance support dlkm: Improve himax_0flash_mmi dlkm: Improve himax_0flash_mmi - continous dlkm: Improve himax_0flash_mmi motorola:qpnp-smbcharger-mmi Clean up commits motorola:qpnp-smbcharger-mmi Delay first boot heartbeat motorola:qpnp-smbcharger-mmi delay first heartbeat 10 seconds dlkm: himax touch driver improvement sx933x: Add generic usb/flip recal options dlkm: Support the touch hx83112f for nairo watchdogtest: replace msm_trigger_wdog_bite() Add synaptics wakeup gesture handler Syna: Modify the suspend and resume process. Modify the disable-irq process in touchscreen class. Allow for multiple batteries and multiple battery profiles ASoC: monitor key registers in aw882xx DLKM/sarsensor:optimise code for sar sensor of abov guam: input add touch chipone fw sec_mmi: mutual capacitance range interface update CCI tools nairobi/sensor: set CONFIG_CAPSENSE_USB_CAL dlkm: ets_fps: Set up double tap feature guam: add touch chipone support Re-Enable DRM Event Notification Solve the problem of charge mode setting when power off racer 5G: aw8695: Add new ringtone waveform dlkm: st21nfc: update driver DLKM/sar: Add fw mode detection for A96T346HW. mmi_sigprint: add death signal debug feature driver DLKM/sar: Add fw mode detection for A96T346HW. fixup! (CR) sec_mmi: support holding grip detection SDM710: Reduce the spam charger related logs Fixup! Check the value to be written Check the value to be written Add synaptics major and minor sec_mmi: support holding grip detection touchscreen_mmi: export class kobject qpnp-smbcharger-mmi: Fix getting stuck in adaptive mode sec_mmi: add grip supp distance register sec_mmi: Fix default prop reset on resume guam: add touch module support fixup! (CR): Solve the problem of I2C error when power off Solve the problem of I2C error when power off fps: fixup kernel panic by calling input_free_device FM: support elna module input: himax_v2_mmi: change resume timing for hx83102d sec_mmi: add hold distance register dlkm: aw8695: fix enter standby mode failture Revert:(CR):timeout to wait for wake lock at suspend Support dts property to configure force device on option modules: power: Update README document for bq27426 driver modules: power: Build with battery profile header files modules: power: Add battery profile files from TI Revert "(CR) aw8697: boost ram loop mode playback" Disable navigation in driver sec_mmi: timeout to wait for wake lock at suspend Take a long time to enter pre_suspended modules: power: Add a long heartbeat delay for discharging dlkm: Nairobi single tap bringup for TDDI modules: power: Add Adaptive Charging feature modules: power: Review SMBMMI log messages dlkm: support 20W charger ASoC: upgrade Aw882xx driver to v0.1.8 qpnp-smbcharger-mmi: Add POWER_SUPPLY_PROP_HOT_TEMP prop p938x_charger: Reduce dc current if battery too hot Modify the output format of the testing node Update synaptics testiong code to V2.1 DLKM/sar:modify enable process of abov sar DLKM/sar:optimise driver of Abov 5 channels Racer_turbo: aw8697: Add new entry in ringtone array sec_mmi: cleanup device tree parse logs sec_mmi: add pill region support Solve the power on problem of Synaptics touchscreen Add touch suspend_noirq process sec_mmi: report major and minor value in pixel unit. Solve I2C error in the first suspend p938x_charger: Force dcin-en on when attached charge:real time check weak charge aw8697: Add error checking to RTP mode touchscreen_mmi: Modify the process of panel off and on sec_mmi: add delay if power supply off p938x_charger: protect fw flash and handle reboot case touchscreen_mmi: secondary touch panel supplier synaptics_mmi_class: fix firmware file name Add Build Flags for Data Width Change Add Data Width to CCI_intf p938x_charger: Wait for LDO to report charging p938x_charger: Update detection algorithm fixup! (CR) sec_mmi: update Kbuild synaptics_mmi_class: start using touchscreen_mmi class touchscreen_mmi: match panel notifier with control dsi synaptics_mmi: add touchscreen_mmi class check sec_mmi: update Kbuild sec_mmi: do not calibrate on firmware update aw8697: Move RTP update work out of irq handler p938x_charger: remove unneeded resets p938x_charger: Remove thermal message print add sar svdd regulator in kernel driver Change dt-gesture sensor to SPECIAL_REPORTING mode p938x_charger: Update tx mode fault handling modules: power: Updating chg-iterm spec on documentation sec_mmi: Get finger size from dts sec_mmi: grip suppression control interface p938x_charger: Update rx_connected with tx mode work dlkm: ets_fps: fix build issue on kernel 4.19 p938x_charger: change tm mode address p938x_charger: change the length of memcpy in fod_store MMI: Add DC psy notifier modules: power: Adding documentation to SMBMMI driver modules: power: Change Heartbeat delay for fast mitigation DLKM: Nairobi NT36672c touch bringup Update driver version to 2.0.4 syna_tcm_mmi_v2: Fix build ID and config ID Exfat:fix compile fail on kernel-4.19 aw8697: boost ram loop mode playback input: himax_v2_mmi: change factory self test codes regulator: modify slg5bm43670 to support interrupt sec_mmi: Fix zero tap gesture coordinate. ft8756: Compatible with the way of gesture to report key novatek: Compatible with the way of gesture to report key input: himax_v2_mmi: add hx83102d driver ASoC: add Awinic aw882xx driver regulator: Add wl2864c driver. kernel/sar: update a96t driver to support two channel Register touchscreen class of synaptics input: focaltech_0flash: enable FTS_POINT_REPORT_CHECK_EN racer: fix cci tools can not access cci-device-1 Racer5G: system crash when Synaptics shut dowm motorola: drivers: Add logic to PD charger detection regulator: separated slg51000 driver drivers: slg51000: Prevent Driver from touching voltages sec_mmi: single/zero tap report format change [racer]sx933x: add usb recal for cap sense modules:audio:tas2562:Turn off debug macro touchscreen_mmi: create more sys entries goodix_gtx8_v1430_mmi: Use i2c device to register ts_mmi Set samsung touch screen name Create the methods to get touchscreen class name aw8697: Add moto ringtone array touchscreen_mmi: use primary and secondary touchscreen_mmi: usb detection sec_mmi: touchscreen class based usb detection touchscreen_mmi: generic gesture handling sec_mmi: enhance class support p938x_charger: add thermal cooling device p938x_charger: add notify calls for hal aw8697: Use RAM mode for long vibration drivers: aw8697: fix kernel panic on RTP fixup! (CR): fix unused function in user build Sec_mmi firmware update goodix_gtx8_v1430_mmi: register tp_mmi notification. sec_mmi: add notification function sec_mmi: Porting gesture handler to sec_mmi_class. touchscreen_mmi: add notification function p938x_charger: read current limits from dt fixup! (CR): drivers: max170xx: fix reset on factory image drivers: max170xx: reset on factory image Show Panel supplier sec_mmi: register a weak function to fix symbol issue p938x_charger: Indicate online based on VRECT sec_mmi: register moto touch class. touchscreen_mmi: create extra sys entry group. Synaptics updated driver code to V2 fixup! (CR) sec_mmi: fix format conversion fixup! (CR) sec_mmi: fix format conversion sec_mmi: fix format conversion fixup! (CR) sec_mmi: wakeup gestures support fixup! (CR) sec_mmi: wakeup gestures support sec_mmi: wakeup gestures support p938x_charger: program fod and q factor Synaptics updated driver code to V2 goodix_gtx8_v1430_mmi: update fw in moto touch script. goodix_gtx8_v1430_mmi: register moto touch class. touchscreen_mmi: Add touchscreen class for moto product. goodix_gtx8_v1430_mmi: support touchscreen_mmi. Revert "(CR): ASoC: add APIs to access digital volume in tas25xx algo" drivers: sx933x: add usb recal for cap sense sec_mmi: make dynamic refresh rate optional sec_mmi: force calibration on power up sec_mmi: refresh rate update support p938x_charger: read epp capabilities ASoC: tas2562 digital volume regulator: slg51000: Set SLG IRQ to trigger low. Revert "(CR): MMI: Init batt health to GOOD" aw8697: support moto vibrator feature aw8697: decouple haptics and calibration wave forms p938x_charger: Only turn off from usb when charger attached fixup! (CR) sec_mmi: remove MMI_STOPSHIP synaptics_mmi: fix clang errors sec_mmi: remove MMI_STOPSHIP ASoC: tas2558: add digital volume control ... Conflicts: Documentation/devicetree/bindings~HEAD drivers/misc/Makefile drivers/regulator/wl2868c/Makefile drivers/regulator/wl2868c/wl2868c-regulator.c drivers/regulator/wl2868c/wl2868c-regulator.h drivers/sensors/Makefile fs/exfat/Kconfig fs/exfat/Makefile fs/exfat/README.md include/linux/input/synaptics_tcm.h include/linux/panel_notifier.h sound/soc/codecs/Makefile Change-Id: Ida4ebbd91a32e29c78afe924d26e7ced3a6a42ed
This commit is contained in:
commit
8208bde4b8
1666 changed files with 1016800 additions and 0 deletions
189
AndroidKernelModule.mk
Normal file
189
AndroidKernelModule.mk
Normal file
|
@ -0,0 +1,189 @@
|
|||
ifeq ($(call is-board-platform-in-list,taro kalama), true)
|
||||
ifneq (,$(findstring $(LOCAL_MODULE),$(BOARD_VENDOR_KERNEL_MODULES)))
|
||||
#Taro and beyond are using a new mechanisim to build kernel modules
|
||||
include device/qcom/common/dlkm/Build_external_kernelmodule.mk
|
||||
endif
|
||||
else
|
||||
ifneq (,$(findstring gki,$(KERNEL_DEFCONFIG)))
|
||||
#GKI product should use Qcom latest dlkm compile file
|
||||
include device/qcom/common/dlkm/AndroidKernelModule.mk
|
||||
else
|
||||
DISABLE_THIS_DLKM := $(strip $(TARGET_KERNEL_DLKM_DISABLE))
|
||||
|
||||
ifeq ($(DISABLE_THIS_DLKM),true)
|
||||
ifneq (,$(filter $(LOCAL_MODULE),$(TARGET_KERNEL_DLKM_OVERRIDE)))
|
||||
DISABLE_THIS_DLKM = false
|
||||
else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(DISABLE_THIS_DLKM),true)
|
||||
$(warning DLKM '$(LOCAL_MODULE)' disabled for target)
|
||||
else
|
||||
|
||||
# Assign external kernel modules to the DLKM class
|
||||
LOCAL_MODULE_CLASS := DLKM
|
||||
|
||||
# Set the default install path to vendor/lib/modules
|
||||
LOCAL_MODULE_PATH := $(strip $(LOCAL_MODULE_PATH))
|
||||
ifeq ($(LOCAL_MODULE_PATH),)
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules
|
||||
endif
|
||||
|
||||
# Set the default Kbuild file path to LOCAL_PATH
|
||||
KBUILD_FILE := $(strip $(KBUILD_FILE))
|
||||
ifeq ($(KBUILD_FILE),)
|
||||
KBUILD_FILE := $(LOCAL_PATH)/Kbuild
|
||||
endif
|
||||
|
||||
# Get rid of any whitespace
|
||||
LOCAL_MODULE_KBUILD_NAME := $(strip $(LOCAL_MODULE_KBUILD_NAME))
|
||||
|
||||
include $(BUILD_SYSTEM)/base_rules.mk
|
||||
|
||||
|
||||
# The kernel build system doesn't support parallel kernel module builds
|
||||
# that share the same output directory. Thus, in order to build multiple
|
||||
# kernel modules that reside in a single directory (and therefore have
|
||||
# the same output directory), there must be just one invocation of the
|
||||
# kernel build system that builds all the modules of a given directory.
|
||||
#
|
||||
# Therefore, all kernel modules must depend on the same, unique target
|
||||
# that invokes the kernel build system and builds all of the modules
|
||||
# for the directory. The $(KBUILD_TARGET) target serves this purpose.
|
||||
# To ensure the value of KBUILD_TARGET is unique, it is essentially set
|
||||
# to the path of the source directory, i.e. LOCAL_PATH.
|
||||
#
|
||||
# Since KBUILD_TARGET is used as a target and a variable name, it should
|
||||
# not contain characters other than letters, numbers, and underscores.
|
||||
KBUILD_TARGET := $(strip \
|
||||
$(subst .,_, \
|
||||
$(subst -,_, \
|
||||
$(subst :,_, \
|
||||
$(subst /,_,$(LOCAL_PATH))))))
|
||||
|
||||
# Intermediate directory where the kernel modules are created
|
||||
# by the kernel build system. Ideally this would be the same
|
||||
# directory as LOCAL_BUILT_MODULE, but because we're using
|
||||
# relative paths for both O= and M=, we don't have much choice
|
||||
KBUILD_OUT_DIR := $(TARGET_OUT_INTERMEDIATES)/$(LOCAL_PATH)
|
||||
|
||||
# Path to the intermediate location where the kernel build
|
||||
# system creates the kernel module.
|
||||
KBUILD_MODULE := $(KBUILD_OUT_DIR)/$(LOCAL_MODULE)
|
||||
|
||||
# Since we only invoke the kernel build system once per directory,
|
||||
# each kernel module must depend on the same target.
|
||||
$(KBUILD_MODULE): kbuild_out := $(KBUILD_OUT_DIR)/$(LOCAL_MODULE_KBUILD_NAME)
|
||||
$(KBUILD_MODULE): $(KBUILD_TARGET)
|
||||
ifneq "$(LOCAL_MODULE_KBUILD_NAME)" ""
|
||||
mv -f $(kbuild_out) $@
|
||||
endif
|
||||
|
||||
|
||||
# To ensure KERNEL_OUT and TARGET_PREBUILT_INT_KERNEL are defined,
|
||||
# kernel/AndroidKernel.mk (kernel_definitions.mk) must be included. While m and regular
|
||||
# make builds will include kernel/AndroidKernel.mk, mm and mmm builds
|
||||
# do not. Therefore, we need to explicitly include kernel/AndroidKernel.mk (kernel_definitions.mk).
|
||||
# It is safe to include it more than once because the entire file is
|
||||
# guarded by "ifeq ($(TARGET_PREBUILT_KERNEL),) ... endif".
|
||||
# If AndroidKernel.mk is not found, fall back to use the kernel_definitions.mk
|
||||
ifneq ($(wildcard $(TARGET_KERNEL_SOURCE)/AndroidKernel.mk),)
|
||||
TARGET_KERNEL_PATH := $(TARGET_KERNEL_SOURCE)/AndroidKernel.mk
|
||||
else
|
||||
TARGET_KERNEL_PATH := device/qcom/kernelscripts/kernel_definitions.mk
|
||||
endif
|
||||
include $(TARGET_KERNEL_PATH)
|
||||
|
||||
# Simply copy the kernel module from where the kernel build system
|
||||
# created it to the location where the Android build system expects it.
|
||||
# If LOCAL_MODULE_DEBUG_ENABLE is set, strip debug symbols. So that,
|
||||
# the final images generated by ABS will have the stripped version of
|
||||
# the modules
|
||||
ifeq ($(TARGET_KERNEL_VERSION),3.18)
|
||||
MODULE_SIGN_FILE := perl ./$(TARGET_KERNEL_SOURCE)/scripts/sign-file
|
||||
MODSECKEY := $(KERNEL_OUT)/signing_key.priv
|
||||
MODPUBKEY := $(KERNEL_OUT)/signing_key.x509
|
||||
else
|
||||
MODULE_SIGN_FILE := $(KERNEL_OUT)/scripts/sign-file
|
||||
MODSECKEY := $(KERNEL_OUT)/certs/signing_key.pem
|
||||
MODPUBKEY := $(KERNEL_OUT)/certs/signing_key.x509
|
||||
endif
|
||||
|
||||
$(LOCAL_BUILT_MODULE): $(KBUILD_MODULE) | $(ACP)
|
||||
ifneq "$(LOCAL_MODULE_DEBUG_ENABLE)" ""
|
||||
mkdir -p $(dir $@)
|
||||
cp $< $<.unstripped
|
||||
$(TARGET_STRIP) --strip-debug $<
|
||||
cp $< $<.stripped
|
||||
endif
|
||||
@sh -c "\
|
||||
KMOD_SIG_ALL=`cat $(KERNEL_OUT)/.config | grep CONFIG_MODULE_SIG_ALL | cut -d'=' -f2`; \
|
||||
KMOD_SIG_HASH=`cat $(KERNEL_OUT)/.config | grep CONFIG_MODULE_SIG_HASH | cut -d'=' -f2 | sed 's/\"//g'`; \
|
||||
if [ \"\$$KMOD_SIG_ALL\" = \"y\" ] && [ -n \"\$$KMOD_SIG_HASH\" ]; then \
|
||||
echo \"Signing kernel module: \" `basename $<`; \
|
||||
cp $< $<.unsigned; \
|
||||
$(MODULE_SIGN_FILE) \$$KMOD_SIG_HASH $(MODSECKEY) $(MODPUBKEY) $<; \
|
||||
fi; \
|
||||
"
|
||||
$(transform-prebuilt-to-target)
|
||||
|
||||
# This should really be cleared in build/core/clear-vars.mk, but for
|
||||
# the time being, we need to clear it ourselves
|
||||
LOCAL_MODULE_KBUILD_NAME :=
|
||||
LOCAL_MODULE_DEBUG_ENABLE :=
|
||||
|
||||
# Ensure the kernel module created by the kernel build system, as
|
||||
# well as all the other intermediate files, are removed during a clean.
|
||||
$(cleantarget): PRIVATE_CLEAN_FILES := $(PRIVATE_CLEAN_FILES) $(KBUILD_OUT_DIR)
|
||||
|
||||
|
||||
# Since this file will be included more than once for directories
|
||||
# with more than one kernel module, the shared KBUILD_TARGET rule should
|
||||
# only be defined once to avoid "overriding commands ..." warnings.
|
||||
ifndef $(KBUILD_TARGET)_RULE
|
||||
$(KBUILD_TARGET)_RULE := 1
|
||||
|
||||
# Kernel modules have to be built after:
|
||||
# * the kernel config has been created
|
||||
# * host executables, like scripts/basic/fixdep, have been built
|
||||
# (otherwise parallel invocations of the kernel build system will
|
||||
# fail as they all try to compile these executables at the same time)
|
||||
# * a full kernel build (to make module versioning work)
|
||||
#
|
||||
# For these reasons, kernel modules are dependent on
|
||||
# TARGET_PREBUILT_INT_KERNEL which will ensure all of the above.
|
||||
#
|
||||
# NOTE: Due to a bug in the kernel build system when using a Kbuild file
|
||||
# and relative paths for both O= and M=, the Kbuild file must
|
||||
# be copied to the output directory.
|
||||
#
|
||||
# NOTE: The following paths are equivalent:
|
||||
# $(KBUILD_OUT_DIR)
|
||||
# $(KERNEL_OUT)/../$(LOCAL_PATH)
|
||||
.PHONY: $(KBUILD_TARGET)
|
||||
$(KBUILD_TARGET): local_path := $(LOCAL_PATH)
|
||||
$(KBUILD_TARGET): kbuild_out_dir := $(KBUILD_OUT_DIR)
|
||||
$(KBUILD_TARGET): kbuild_options := $(KBUILD_OPTIONS)
|
||||
ifneq ($(USE_CLANG_FOR_MODULES),)
|
||||
$(KBUILD_TARGET): $(TARGET_PREBUILT_INT_KERNEL)
|
||||
@mkdir -p $(kbuild_out_dir)
|
||||
$(hide) cp -f $(local_path)/Kbuild $(kbuild_out_dir)/Kbuild
|
||||
$(MAKE) -C $(TARGET_KERNEL_SOURCE) M=$(KERNEL_TO_BUILD_ROOT_OFFSET)$(local_path) O=$(KERNEL_TO_BUILD_ROOT_OFFSET)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) modules $(kbuild_options) ANDROID_BUILD_TOP=$$(pwd) TOP=$$(pwd)
|
||||
else
|
||||
$(KBUILD_TARGET): $(TARGET_PREBUILT_INT_KERNEL)
|
||||
@mkdir -p $(kbuild_out_dir)
|
||||
$(hide) cp -f $(local_path)/Kbuild $(kbuild_out_dir)/Kbuild
|
||||
$(MAKE) -C $(TARGET_KERNEL_SOURCE) M=$(KERNEL_TO_BUILD_ROOT_OFFSET)$(local_path) O=$(KERNEL_TO_BUILD_ROOT_OFFSET)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules $(kbuild_options) TOP=$$(pwd)
|
||||
endif
|
||||
|
||||
# Once the KBUILD_OPTIONS variable has been used for the target
|
||||
# that's specific to the LOCAL_PATH, clear it. If this isn't done,
|
||||
# then every kernel module would need to explicitly set KBUILD_OPTIONS,
|
||||
# or the variable would have to be cleared in 'include $(CLEAR_VARS)'
|
||||
# which would require a change to build/core.
|
||||
KBUILD_OPTIONS :=
|
||||
endif
|
||||
endif
|
||||
endif #(findstring gki,$(KERNEL_DEFCONFIG))
|
||||
endif #(is-board-platform-in-list,taro....)
|
119
arch/arm64/boot/dts/vendor/bindings/cs40l2x.txt
vendored
Normal file
119
arch/arm64/boot/dts/vendor/bindings/cs40l2x.txt
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
CS40L20 Boosted Haptics Driver
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : One of "cirrus,cs40l20", "cirrus,cs40l25", "cirrus,cs40l25a"
|
||||
or "cirrus,cs40l25b".
|
||||
|
||||
- reg : The I2C slave address of the device.
|
||||
|
||||
- VA-supply, VP-supply : Regulators for the device's VA and VP supplies,
|
||||
respectively. See the following:
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
- cirrus,boost-ind-nanohenry : Boost inductor value, expressed in nH. Valid
|
||||
values include 1000, 1200, 1500 and 2200.
|
||||
|
||||
- cirrus,boost-cap-microfarad : Total equivalent boost capacitance on the VBST
|
||||
and VAMP pins, derated at 11 volts DC. The value must be rounded to the
|
||||
nearest integer and expressed in uF.
|
||||
|
||||
- cirrus,boost-ipk-milliamp : Boost inductor peak current, expressed in mA.
|
||||
Valid values range from 1600 to 4500 (inclusive) in steps of 50.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios : GPIO used for resetting the device.
|
||||
|
||||
- cirrus,refclk-gpio2 : Boolean for configuring the device to expect its
|
||||
32.768-kHz reference clock on the REFCLK/GPIO2 pin. If this property is
|
||||
omitted, the device expects its 32.768-kHz reference clock on the
|
||||
ASP_BCLK/REFCLK pin. This property is ignored for CS40L25A and CS40L25B
|
||||
devices as reference clock selection is configured automatically.
|
||||
|
||||
- cirrus,f0-default : Default LRA resonant frequency (f0), expressed as
|
||||
follows: cirrus,f0-default = f0 (Hz) * 2^14. This value represents the
|
||||
frequency used during playback of PWLE segments specified with frequency
|
||||
equal to f0; it also serves as the unit-specific f0 input to the click
|
||||
compensation algorithm. It can be overwritten at a later time by writing
|
||||
to the f0_stored sysfs control.
|
||||
|
||||
If this value is omitted or specified as zero, the measurement recorded in
|
||||
the f0_measured sysfs control is used. If LRA diagnostics has not been
|
||||
administered and f0_measured is uninitialized, 2621440 (160 Hz) is used.
|
||||
|
||||
- cirrus,f0-min : Minimum LRA resonant frequency (f0) that may be written to
|
||||
the f0_stored sysfs control, expressed using the same numerical format as
|
||||
cirrus,f0-default. If this value is omitted or specified as zero, no lower-
|
||||
bound validation is performed.
|
||||
|
||||
- cirrus,f0-max : Maximum LRA resonant frequency (f0) that may be written to
|
||||
the f0_stored sysfs control, expressed using the same numerical format as
|
||||
cirrus,f0-default. If this value is omitted or specified as zero, no upper-
|
||||
bound validation is performed.
|
||||
|
||||
- cirrus,redc-default : Default LRA series resistance (ReDC), expressed as
|
||||
follows: cirrus,redc-default = ReDC (ohms) / 5.857 * 2^17. This value
|
||||
represents the unit-specific ReDC input to the click compensation algorithm.
|
||||
It can be overwritten at a later time by writing to the redc_stored sysfs
|
||||
control.
|
||||
|
||||
If this value is omitted or specified as zero, the measurement recorded in
|
||||
the redc_measured sysfs control is used. If LRA diagnostics has not been
|
||||
administered and redc_measured is uninitialized, 340787 (15.2 ohms) is used.
|
||||
|
||||
- cirrus,redc-min : Minimum LRA series resistance (ReDC) that may be written
|
||||
to the redc_stored sysfs control, expressed using the same numerical format
|
||||
as cirrus,redc-default. If this value is omitted or specified as zero, no
|
||||
lower-bound validation is performed.
|
||||
|
||||
- cirrus,redc-max : Maximum LRA series resistance (ReDC) that may be written
|
||||
to the redc_stored sysfs control, expressed using the same numerical format
|
||||
as cirrus,redc-default. If this value is omitted or specified as zero, no
|
||||
upper-bound validation is performed.
|
||||
|
||||
- cirrus,gpio1-rise-index : Specifies the wavetable index mapped to GPIO1
|
||||
rising edges. If this value is omitted, specified as zero or exceeds the
|
||||
maximum available index in the wavetable, GPIO1 rising edges are mapped to
|
||||
index 1.
|
||||
|
||||
- cirrus,gpio1-fall-index : Specifies the wavetable index mapped to GPIO1
|
||||
falling edges. If this value is omitted, specified as zero or exceeds the
|
||||
maximum available index in the wavetable, GPIO1 falling edges are mapped to
|
||||
index 2.
|
||||
|
||||
- cirrus,gpio1-fall-timeout : Specifies the number of 48-kHz periods for
|
||||
which the device remains in the active state in search of a GPIO1 falling
|
||||
edge, following a GPIO1 rising edge (the latter of which renders the device
|
||||
active). If a GPIO1 falling edge does not arrive within this timeout, the
|
||||
device automatically returns to the standby state and the subsequent GPIO1
|
||||
falling edge is ignored. If this value is omitted or exceeds the maximum
|
||||
timeout (8388607) then a default of 240000 is assumed (corresponding to
|
||||
240000 / 48000 = 5 seconds). If this value is specified as zero, the timeout
|
||||
is effectively disabled.
|
||||
|
||||
- cirrus,gpio1-mode : Specifies the operating mode of the GPIO1 pin, equal to
|
||||
one of the following.
|
||||
|
||||
0 = enabled by default
|
||||
1 = disabled by default
|
||||
2 = disabled by default, but automatically enabled and disabled upon suspend
|
||||
and resume, respectively
|
||||
|
||||
If this value is omitted or given an invalid value, mode 0 (enabled by
|
||||
default) is assumed. Regardless of mode, the GPIO1 pin can be enabled or
|
||||
disabled at will from user space using the gpio1_enable sysfs control.
|
||||
|
||||
Example:
|
||||
|
||||
cs40l20: cs40l20@43 {
|
||||
compatible = "cirrus,cs40l20";
|
||||
reg = <0x43>;
|
||||
reset-gpios = <&gpio0 54 0>;
|
||||
VA-supply = <&dummy_vreg>;
|
||||
VP-supply = <&dummy_vreg>;
|
||||
cirrus,boost-ind-nanohenry = <1000>;
|
||||
cirrus,boost-cap-microfarad = <4>;
|
||||
cirrus,boost-ipk-milliamp = <4500>;
|
||||
cirrus,refclk-gpio2;
|
||||
};
|
28
arch/arm64/boot/dts/vendor/bindings/input/misc/ets_fps_mmi/ets_fps.txt
vendored
Normal file
28
arch/arm64/boot/dts/vendor/bindings/input/misc/ets_fps_mmi/ets_fps.txt
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
Egis Technology Inc fingerprint driver
|
||||
et320 is a fps sensor in front of the phone, it connects to mainboard via SPI.
|
||||
et516 is a fps sensor on the back of the phone, it connects to mainboard via SPI.
|
||||
Required properties:
|
||||
- compatible: Should be "egistec,et516" or "egistec,et320"
|
||||
- gpio_irq : GPIO used for interrupt
|
||||
- gpio_rst: GPIO used for ets sensor reset
|
||||
- gpio_ldo1p8_en : GPIO used to enable vdd 1.8v
|
||||
- gpio_ldo3p3_en : GPIO used to enable vcc 3.3v
|
||||
- pinctrl-names,pinctrl-0: the pincontrol setting to configure muxing properly
|
||||
for pins that connect to ets fps sensor.
|
||||
|
||||
Example:
|
||||
ets_fps: ets_fps{
|
||||
compatible = "egistec,et320","egistec,et516";
|
||||
status = "ok";
|
||||
reg = <0>;
|
||||
interrupt-parent = <&tlmm>;
|
||||
interrupts = <128 0x0>;
|
||||
egistec,gpio_irq = <&tlmm 128 0x1>;
|
||||
egistec,gpio_rst = <&tlmm 127 0x2>;
|
||||
egistec,gpio_ldo1p8_en = <&tlmm 132 0x0>;
|
||||
egistec,gpio_ldo3p3_en = <&tlmm 133 0x0>;
|
||||
pinctrl-names = "default", "suspend";
|
||||
pinctrl-0 = <&rst_active &int_active &ldo_en_active &ldo3_en_active>;
|
||||
pinctrl-1 = <&rst_suspend &int_suspend &ldo_en_suspend &ldo3_en_suspend>;
|
||||
};
|
18
arch/arm64/boot/dts/vendor/bindings/input/misc/goodix_fod_mmi/goodix_fod_mmi.txt
vendored
Normal file
18
arch/arm64/boot/dts/vendor/bindings/input/misc/goodix_fod_mmi/goodix_fod_mmi.txt
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
Goodix Fingerprint TEE driver
|
||||
|
||||
Required properties:
|
||||
|
||||
-compatible : should be "goodix,fingerprint".
|
||||
-interrupt-parent : gpio interrupt parent declare
|
||||
-fp-gpio-irq : irq gpio declare
|
||||
-fp-gpio-reset : reset gpio declare
|
||||
|
||||
Example:
|
||||
|
||||
goodix_fp {
|
||||
compatible = "goodix,fingerprint";
|
||||
interrupt-parent = <&tlmm>;
|
||||
fp-gpio-irq = <&tlmm 58 0x00>;
|
||||
fp-gpio-reset = <&tlmm 59 0x00>;
|
||||
status = "okay";
|
||||
};
|
28
arch/arm64/boot/dts/vendor/bindings/input/misc/stmvl53l1.txt
vendored
Normal file
28
arch/arm64/boot/dts/vendor/bindings/input/misc/stmvl53l1.txt
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
st,stmvl53l1 laser driver
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Should be "st,stmvl53l1".
|
||||
|
||||
Optional properites:
|
||||
|
||||
|
||||
Example:
|
||||
stmvl53l1@29 {
|
||||
status = "ok";
|
||||
compatible = "st,stmvl53l1";
|
||||
reg = <0x29>;
|
||||
/* L22 is always on for now */
|
||||
/* vdd-supply = <&pm8998_l22>; */
|
||||
gpios = <&pm8998_gpios 15 0>, <&tlmm 79 0>;
|
||||
qcom,gpio-reset = <0>;
|
||||
qcom,gpio-req-tbl-num = <0 1>;
|
||||
qcom,gpio-req-tbl-flags = <0 1>;
|
||||
qcom,gpio-req-tbl-label ="TOF_XSHUTDOWN","TOF_INT";
|
||||
pinctrl-names = "laser_default", "laser_suspend";
|
||||
pinctrl-0 = <&laser_active >;
|
||||
pinctrl-1 = <&laser_suspend >;
|
||||
st,sensorthreshold = <60 65>;
|
||||
st,xtalkval = <19>;
|
||||
};
|
||||
|
37
arch/arm64/boot/dts/vendor/bindings/input/misc/sx933x/sx933x.txt
vendored
Normal file
37
arch/arm64/boot/dts/vendor/bindings/input/misc/sx933x/sx933x.txt
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
sx933x cap touch sensor from semtech
|
||||
|
||||
It is a i2c slave device
|
||||
two specific properties for driver init registers's value
|
||||
|
||||
a).CONFIG_INPUT_SX933x corresponding driver sx933x_sar.c,
|
||||
sx933x is 5 channels driver.
|
||||
|
||||
Required properties:
|
||||
- Semtech,button-flag :flag of used buttons,0~4 bits refers to button 0~4
|
||||
- Semtech,reg-num :num of registers need to be set
|
||||
- Semtech,reg-init :registers's val, format is <reg addr, reg val ...>
|
||||
|
||||
Example:
|
||||
|
||||
sx933x@28 {
|
||||
compatible = "Semtech,sx933x";
|
||||
reg = <0x28>;
|
||||
interrupt-parent = <&tlmm>;
|
||||
interrupts = <75 0>;
|
||||
Semtech,nirq-gpio = <&tlmm 75 0x00>;
|
||||
cap_vdd-supply = <&pm660l_l8>;
|
||||
Semtech,reg-num = <12>;
|
||||
Semtech,button-flag = <0x07>; //used button 0~2
|
||||
Semtech,reg-init = <0x8020 0x3F00C0
|
||||
0x8024 0x44F
|
||||
0x8028 0x24928000
|
||||
0x802C 0x44F
|
||||
0x8030 0x24960000
|
||||
0x8034 0x44F
|
||||
0x8038 0x24B20000
|
||||
0x803C 0x44F
|
||||
0x8040 0x25920000
|
||||
0x8044 0x44F
|
||||
0x8048 0x2C920000
|
||||
0x4004 0x67 >;
|
||||
};
|
71
arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_mmi/synaptics_tcm_i2c.txt
vendored
Normal file
71
arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_mmi/synaptics_tcm_i2c.txt
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
Synaptics TCM I2C touchscreen controller
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
should be "synaptics,tcm-i2c"
|
||||
- reg:
|
||||
i2c slave address of device
|
||||
- interrupt-parent:
|
||||
hardware controller of interrupt signal
|
||||
- interrupts:
|
||||
gpio number and flags of interrupt signal
|
||||
- vdd-supply:
|
||||
digital power source
|
||||
- avdd-supply:
|
||||
analog power source
|
||||
- pinctrl-names:
|
||||
- pinctrl-0:
|
||||
- pinctrl-1:
|
||||
should be defined if using pinctrl framework
|
||||
"pmx_ts_active": active configuration of pins
|
||||
"pmx_ts_suspend": disabled configuration of pins
|
||||
- synaptics,bus-reg-name:
|
||||
name of digital power source regulator
|
||||
- synaptics,pwr-reg-name:
|
||||
name of analog power source regulator
|
||||
- synaptics,irq-gpio:
|
||||
interrupt hardware controller, gpio number, and flags
|
||||
- synaptics,irq-on-state:
|
||||
active state of interrupt signal
|
||||
|
||||
Optional properties:
|
||||
- synaptics,power-gpio:
|
||||
hardware controller and gpio number of power control signal
|
||||
- synaptics,power-delay-ms:
|
||||
delay time in ms after powering on device
|
||||
- synaptics,reset-gpio:
|
||||
hardware controller and gpio number of reset signal
|
||||
- synaptics,reset-delay-ms:
|
||||
delay time in ms after issuing reset to device
|
||||
- synaptics,reset-on-state:
|
||||
active state of reset signal
|
||||
- synaptics,reset-active-ms:
|
||||
active duration in ms of reset signal
|
||||
- synaptics,x-flip:
|
||||
flip x axis
|
||||
- synaptics,y-flip:
|
||||
flip y axis
|
||||
- synaptics,swap-axes:
|
||||
swap x and y axes
|
||||
- synaptics,ubl-i2c-addr:
|
||||
i2c slave address of device in microbootloader mode
|
||||
|
||||
Example:
|
||||
synaptics_tcm@2c {
|
||||
compatible = "synaptics,tcm-i2c";
|
||||
reg = <0x2c>;
|
||||
interrupt-parent = <&msm_gpio>;
|
||||
interrupts = <65 0x2008>;
|
||||
vdd-supply = <&pm8994_lvs2>;
|
||||
avdd-supply = <&pm8994_l22>;
|
||||
pinctrl-names = "pmx_ts_active", "pmx_ts_suspend";
|
||||
pinctrl-0 = <&ts_active>;
|
||||
pinctrl-1 = <&ts_suspend>;
|
||||
synaptics,pwr-reg-name = "avdd";
|
||||
synaptics,bus-reg-name = "vdd";
|
||||
synaptics,irq-gpio = <&msm_gpio 65 0x2008>;
|
||||
synaptics,irq-on-state = <0>;
|
||||
synaptics,power-delay-ms = <200>;
|
||||
synaptics,reset-delay-ms = <200>;
|
||||
synaptics,ubl-i2c-addr = <0x2c>;
|
||||
};
|
86
arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_mmi/synaptics_tcm_spi.txt
vendored
Normal file
86
arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_mmi/synaptics_tcm_spi.txt
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
Synaptics TCM SPI touchscreen controller
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
should be "synaptics,tcm-spi"
|
||||
- reg:
|
||||
should be 0
|
||||
- spi-max-frequency:
|
||||
maximum spi clock frequency
|
||||
- interrupt-parent:
|
||||
hardware controller of interrupt signal
|
||||
- interrupts:
|
||||
gpio number and flags of interrupt signal
|
||||
- vdd-supply:
|
||||
digital power source
|
||||
- avdd-supply:
|
||||
analog power source
|
||||
- pinctrl-names:
|
||||
- pinctrl-0:
|
||||
- pinctrl-1:
|
||||
should be defined if using pinctrl framework
|
||||
"pmx_ts_active": active configuration of pins
|
||||
"pmx_ts_suspend": disabled configuration of pins
|
||||
- synaptics,bus-reg-name:
|
||||
name of digital power source regulator
|
||||
- synaptics,pwr-reg-name:
|
||||
name of analog power source regulator
|
||||
- synaptics,irq-gpio:
|
||||
interrupt hardware controller, gpio number, and flags
|
||||
- synaptics,irq-on-state:
|
||||
active state of interrupt signal
|
||||
|
||||
Optional properties:
|
||||
- synaptics,spi-mode:
|
||||
spi mode
|
||||
- synaptics,byte-delay-us:
|
||||
inter-byte delay time in us
|
||||
- synaptics,block-delay-us:
|
||||
inter-block delay time in us
|
||||
- synaptics,power-gpio:
|
||||
hardware controller and gpio number of power control signal
|
||||
- synaptics,power-delay-ms:
|
||||
delay time in ms after powering on device
|
||||
- synaptics,reset-gpio:
|
||||
hardware controller and gpio number of reset signal
|
||||
- synaptics,reset-delay-ms:
|
||||
delay time in ms after issuing reset to device
|
||||
- synaptics,reset-on-state:
|
||||
active state of reset signal
|
||||
- synaptics,reset-active-ms:
|
||||
active duration in ms of reset signal
|
||||
- synaptics,x-flip:
|
||||
flip x axis
|
||||
- synaptics,y-flip:
|
||||
flip y axis
|
||||
- synaptics,swap-axes:
|
||||
swap x and y axes
|
||||
- synaptics,ubl-max-freq:
|
||||
maximum spi clock frequency for microbootloader mode
|
||||
- synaptics,ubl-byte-delay-us:
|
||||
inter-byte delay time in us for microbootloader mode
|
||||
|
||||
Example:
|
||||
synaptics_tcm@0 {
|
||||
compatible = "synaptics,tcm-spi";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <10000000>;
|
||||
interrupt-parent = <&msm_gpio>;
|
||||
interrupts = <65 0x2008>;
|
||||
vdd-supply = <&pm8994_lvs2>;
|
||||
avdd-supply = <&pm8994_l22>;
|
||||
pinctrl-names = "pmx_ts_active", "pmx_ts_suspend";
|
||||
pinctrl-0 = <&ts_active>;
|
||||
pinctrl-1 = <&ts_suspend>;
|
||||
synaptics,bus-reg-name = "vdd";
|
||||
synaptics,pwr-reg-name = "avdd";
|
||||
synaptics,irq-gpio = <&msm_gpio 65 0x2008>;
|
||||
synaptics,irq-on-state = <0>;
|
||||
synaptics,spi-mode = <3>;
|
||||
synaptics,byte-delay-us = <0>;
|
||||
synaptics,block-delay-us = <0>;
|
||||
synaptics,power-delay-ms = <200>;
|
||||
synaptics,reset-delay-ms = <200>;
|
||||
synaptics,ubl-max-freq = <5000000>;
|
||||
synaptics,ubl-byte-delay-us = <20>;
|
||||
};
|
84
arch/arm64/boot/dts/vendor/bindings/regulator/slg51000.txt
vendored
Normal file
84
arch/arm64/boot/dts/vendor/bindings/regulator/slg51000.txt
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
* Dialog Semiconductor SLG51000 Voltage Regulator
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "dlg,slg51000" for SLG51000
|
||||
- reg : Specifies the I2C slave address.
|
||||
|
||||
Optional properties:
|
||||
- interrupt-parent : Specifies the reference to the interrupt controller.
|
||||
- interrupts : IRQ line information.
|
||||
- dlg,cs-gpios : Specify a valid GPIO for chip select
|
||||
|
||||
Sub-nodes:
|
||||
- regulators : This node defines the settings for the regulators.
|
||||
The content of the sub-node is defined by the standard binding
|
||||
for regulators; see regulator.txt.
|
||||
|
||||
The SLG51000 regulators are bound using their names listed below:
|
||||
ldo1
|
||||
ldo2
|
||||
ldo3
|
||||
ldo4
|
||||
ldo5
|
||||
ldo6
|
||||
ldo7
|
||||
|
||||
Optional properties for regulators:
|
||||
- enable-gpios : Specify a valid GPIO for platform control of the regualtor.
|
||||
|
||||
Example:
|
||||
pmic: slg51000@75 {
|
||||
compatible = "dlg,slg51000";
|
||||
reg = <0x75>;
|
||||
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
regulators {
|
||||
ldo1 {
|
||||
regulator-name = "ldo1";
|
||||
regulator-min-microvolt = <2400000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
ldo2 {
|
||||
regulator-name = "ldo2";
|
||||
regulator-min-microvolt = <2400000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
enable-gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>
|
||||
};
|
||||
|
||||
ldo3 {
|
||||
regulator-name = "ldo3";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <3750000>;
|
||||
};
|
||||
|
||||
ldo4 {
|
||||
regulator-name = "ldo4";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <3750000>;
|
||||
};
|
||||
|
||||
ldo5 {
|
||||
regulator-name = "ldo5";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
};
|
||||
|
||||
ldo6 {
|
||||
regulator-name = "ldo6";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
};
|
||||
|
||||
ldo7 {
|
||||
regulator-name = "ldo7";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <3750000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
};
|
14
arch/arm64/boot/dts/vendor/bindings/sound/tas2560-algo.txt
vendored
Normal file
14
arch/arm64/boot/dts/vendor/bindings/sound/tas2560-algo.txt
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
Tas2560 algo driver
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "ti,tas2560-algo"
|
||||
|
||||
- tas2560-port-id : afe port id for the mi2s used for tas2560.
|
||||
|
||||
Example:
|
||||
|
||||
ti,tas2560-algo {
|
||||
compatible = "ti,tas2560-algo";
|
||||
ti,tas2560-port-id = <0x1016>, <0x1017>;
|
||||
};
|
14
drivers/backlight/aw99703/Android.mk
Normal file
14
drivers/backlight/aw99703/Android.mk
Normal file
|
@ -0,0 +1,14 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := leds_aw99703.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true)
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/
|
||||
else
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
endif
|
||||
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
5
drivers/backlight/aw99703/Kbuild
Normal file
5
drivers/backlight/aw99703/Kbuild
Normal file
|
@ -0,0 +1,5 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
|
||||
|
||||
obj-m += leds_aw99703.o
|
10
drivers/backlight/aw99703/Makefile
Normal file
10
drivers/backlight/aw99703/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
809
drivers/backlight/aw99703/leds_aw99703.c
Normal file
809
drivers/backlight/aw99703/leds_aw99703.c
Normal file
|
@ -0,0 +1,809 @@
|
|||
/*
|
||||
* aw99703.c aw99703 backlight module
|
||||
*
|
||||
* Version: v1.0.3
|
||||
*
|
||||
* Copyright (c) 2019 AWINIC Technology CO., LTD
|
||||
*
|
||||
* Author: Joseph <zhangzetao@awinic.com.cn>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/backlight.h>
|
||||
#include "leds_aw99703.h"
|
||||
|
||||
#define AW99703_LED_DEV "aw99703-bl"
|
||||
#define AW99703_NAME "aw99703-bl"
|
||||
|
||||
#define AW99703_VERSION "v1.0.3"
|
||||
|
||||
struct aw99703_data *g_aw99703_data;
|
||||
|
||||
static int platform_read_i2c_block(struct i2c_client *client, char *writebuf,
|
||||
int writelen, char *readbuf, int readlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (writelen > 0) {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 2);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: i2c read error.\n",
|
||||
__func__);
|
||||
} else {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s:i2c read error.\n", __func__);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aw99703_i2c_read(struct i2c_client *client, u8 addr, u8 *val)
|
||||
{
|
||||
return platform_read_i2c_block(client, &addr, 1, val, 1);
|
||||
}
|
||||
|
||||
static int platform_write_i2c_block(struct i2c_client *client,
|
||||
char *writebuf, int writelen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: i2c write error.\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aw99703_i2c_write(struct i2c_client *client, u8 addr, const u8 val)
|
||||
{
|
||||
u8 buf[2] = {0};
|
||||
|
||||
buf[0] = addr;
|
||||
buf[1] = val;
|
||||
|
||||
return platform_write_i2c_block(client, buf, sizeof(buf));
|
||||
}
|
||||
static void aw99703_hwen_pin_ctrl(struct aw99703_data *drvdata, int en)
|
||||
{
|
||||
if (gpio_is_valid(drvdata->hwen_gpio)) {
|
||||
if (en) {
|
||||
pr_info("hwen pin is going to be high!---<%d>\n", en);
|
||||
gpio_set_value(drvdata->hwen_gpio, true);
|
||||
usleep_range(3500, 4000);
|
||||
} else {
|
||||
pr_info("hwen pin is going to be low!---<%d>\n", en);
|
||||
gpio_set_value(drvdata->hwen_gpio, false);
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int aw99703_gpio_init(struct aw99703_data *drvdata)
|
||||
{
|
||||
|
||||
int ret;
|
||||
|
||||
if (gpio_is_valid(drvdata->hwen_gpio)) {
|
||||
ret = gpio_request(drvdata->hwen_gpio, "hwen_gpio");
|
||||
if (ret < 0) {
|
||||
pr_err("failed to request gpio\n");
|
||||
return -1;
|
||||
}
|
||||
pr_info("gpio is valid %d!\n",drvdata->hwen_gpio);
|
||||
aw99703_hwen_pin_ctrl(drvdata, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw99703_i2c_write_bit(struct i2c_client *client,
|
||||
unsigned int reg_addr, unsigned int mask, unsigned char reg_data)
|
||||
{
|
||||
unsigned char reg_val = 0;
|
||||
|
||||
aw99703_i2c_read(client, reg_addr, ®_val);
|
||||
reg_val &= mask;
|
||||
reg_val |= reg_data;
|
||||
aw99703_i2c_write(client, reg_addr, reg_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw99703_brightness_map(unsigned int level)
|
||||
{
|
||||
/*MAX_LEVEL_256*/
|
||||
if (g_aw99703_data->bl_map == 1) {
|
||||
if (level == 255)
|
||||
return 2047;
|
||||
return level * 8;
|
||||
}
|
||||
/*MAX_LEVEL_1024*/
|
||||
if (g_aw99703_data->bl_map == 2)
|
||||
return level * 2;
|
||||
/*MAX_LEVEL_2048*/
|
||||
if (g_aw99703_data->bl_map == 3)
|
||||
return level;
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
static int aw99703_bl_enable_channel(struct aw99703_data *drvdata)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (drvdata->channel == 3) {
|
||||
pr_info("%s turn all channel on!\n", __func__);
|
||||
ret = aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_LEDCUR,
|
||||
AW99703_LEDCUR_CHANNEL_MASK,
|
||||
AW99703_LEDCUR_CH3_ENABLE |
|
||||
AW99703_LEDCUR_CH2_ENABLE |
|
||||
AW99703_LEDCUR_CH1_ENABLE);
|
||||
} else if (drvdata->channel == 2) {
|
||||
pr_info("%s turn two channel on!\n", __func__);
|
||||
ret = aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_LEDCUR,
|
||||
AW99703_LEDCUR_CHANNEL_MASK,
|
||||
AW99703_LEDCUR_CH2_ENABLE |
|
||||
AW99703_LEDCUR_CH1_ENABLE);
|
||||
} else if (drvdata->channel == 1) {
|
||||
pr_info("%s turn one channel on!\n", __func__);
|
||||
ret = aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_LEDCUR,
|
||||
AW99703_LEDCUR_CHANNEL_MASK,
|
||||
AW99703_LEDCUR_CH1_ENABLE);
|
||||
} else {
|
||||
pr_info("%s all channels are going to be disabled\n", __func__);
|
||||
ret = aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_LEDCUR,
|
||||
AW99703_LEDCUR_CHANNEL_MASK,
|
||||
0x98);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aw99703_pwm_mode_enable(struct aw99703_data *drvdata)
|
||||
{
|
||||
if (drvdata->pwm_mode) {
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_MODE,
|
||||
AW99703_MODE_PDIS_MASK,
|
||||
AW99703_MODE_PDIS_ENABLE);
|
||||
pr_info("%s pwm_mode is enable\n", __func__);
|
||||
} else {
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_MODE,
|
||||
AW99703_MODE_PDIS_MASK,
|
||||
AW99703_MODE_PDIS_DISABLE);
|
||||
pr_info("%s pwm_mode is disable\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
static void aw99703_ramp_setting(struct aw99703_data *drvdata)
|
||||
{
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_TURNCFG,
|
||||
AW99703_TURNCFG_ON_TIM_MASK,
|
||||
drvdata->ramp_on_time << 4);
|
||||
pr_info("%s drvdata->ramp_on_time is 0x%x\n",
|
||||
__func__, drvdata->ramp_on_time);
|
||||
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_TURNCFG,
|
||||
AW99703_TURNCFG_OFF_TIM_MASK,
|
||||
drvdata->ramp_off_time);
|
||||
pr_info("%s drvdata->ramp_off_time is 0x%x\n",
|
||||
__func__, drvdata->ramp_off_time);
|
||||
|
||||
}
|
||||
static void aw99703_transition_ramp(struct aw99703_data *drvdata)
|
||||
{
|
||||
|
||||
pr_info("%s enter\n", __func__);
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_TRANCFG,
|
||||
AW99703_TRANCFG_PWM_TIM_MASK,
|
||||
drvdata->pwm_trans_dim);
|
||||
pr_info("%s drvdata->pwm_trans_dim is 0x%x\n", __func__,
|
||||
drvdata->pwm_trans_dim);
|
||||
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_TRANCFG,
|
||||
AW99703_TRANCFG_I2C_TIM_MASK,
|
||||
drvdata->i2c_trans_dim);
|
||||
pr_info("%s drvdata->i2c_trans_dim is 0x%x\n",
|
||||
__func__, drvdata->i2c_trans_dim);
|
||||
|
||||
}
|
||||
|
||||
static int aw99703_backlight_init(struct aw99703_data *drvdata)
|
||||
{
|
||||
pr_info("%s enter.\n", __func__);
|
||||
|
||||
aw99703_pwm_mode_enable(drvdata);
|
||||
|
||||
/*mode:map type*/
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_MODE,
|
||||
AW99703_MODE_MAP_MASK,
|
||||
drvdata->map_type);
|
||||
|
||||
/*default OVPSEL 38V*/
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_BSTCTR1,
|
||||
AW99703_BSTCTR1_OVPSEL_MASK,
|
||||
drvdata->ovp_level);
|
||||
|
||||
/*switch frequency 1000kHz*/
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_BSTCTR1,
|
||||
AW99703_BSTCTR1_SF_MASK,
|
||||
AW99703_BSTCTR1_SF_1000KHZ);
|
||||
|
||||
/*OCP SELECT*/
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_BSTCTR1,
|
||||
AW99703_BSTCTR1_OCPSEL_MASK,
|
||||
drvdata->ocp_level);
|
||||
|
||||
/*BSTCRT2 IDCTSEL*/
|
||||
if (drvdata->bl_reconfig_enable && (AW99703_REG_BSTCTR2 == drvdata->bl_slow_reg)) {
|
||||
pr_info("%s: REG_BSTCTR2 slow set\n", __func__);
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_BSTCTR2,
|
||||
AW99703_BSTCTR2_IDCTSEL_MASK | AW99703_BSTCTR2_EMISEL_MASK,
|
||||
AW99703_BSTCTR2_IDCTSEL_10UH | AW99703_BSTCTR2_EMISEL_SLOW1);
|
||||
} else {
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_BSTCTR2,
|
||||
AW99703_BSTCTR2_IDCTSEL_MASK,
|
||||
AW99703_BSTCTR2_IDCTSEL_10UH);
|
||||
}
|
||||
|
||||
/*Backlight current full scale*/
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_LEDCUR,
|
||||
AW99703_LEDCUR_BLFS_MASK,
|
||||
drvdata->full_scale_led << 3);
|
||||
|
||||
aw99703_bl_enable_channel(drvdata);
|
||||
|
||||
aw99703_ramp_setting(drvdata);
|
||||
aw99703_transition_ramp(drvdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw99703_backlight_enable(struct aw99703_data *drvdata)
|
||||
{
|
||||
pr_info("%s enter.\n", __func__);
|
||||
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_MODE,
|
||||
AW99703_MODE_WORKMODE_MASK,
|
||||
AW99703_MODE_WORKMODE_BACKLIGHT);
|
||||
|
||||
drvdata->enable = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aw99703_set_brightness(struct aw99703_data *drvdata, int brt_val)
|
||||
{
|
||||
pr_info("%s brt_val is %d\n", __func__, brt_val);
|
||||
|
||||
if (drvdata->enable == false) {
|
||||
if(brt_val == 0)
|
||||
return 0;
|
||||
aw99703_backlight_init(drvdata);
|
||||
}
|
||||
|
||||
brt_val = aw99703_brightness_map(brt_val);
|
||||
|
||||
if (brt_val > 0) {
|
||||
/*enalbe bl mode*/
|
||||
/* set backlight brt_val */
|
||||
aw99703_i2c_write(drvdata->client,
|
||||
AW99703_REG_LEDLSB,
|
||||
brt_val&0x0007);
|
||||
aw99703_i2c_write(drvdata->client,
|
||||
AW99703_REG_LEDMSB,
|
||||
(brt_val >> 3)&0xff);
|
||||
|
||||
/* backlight enable */
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_MODE,
|
||||
AW99703_MODE_WORKMODE_MASK,
|
||||
AW99703_MODE_WORKMODE_BACKLIGHT);
|
||||
drvdata->enable = true;
|
||||
} else {
|
||||
/* standby mode*/
|
||||
aw99703_i2c_write_bit(drvdata->client,
|
||||
AW99703_REG_MODE,
|
||||
AW99703_MODE_WORKMODE_MASK,
|
||||
AW99703_MODE_WORKMODE_STANDBY);
|
||||
}
|
||||
|
||||
drvdata->brightness = brt_val;
|
||||
|
||||
if (drvdata->brightness == 0)
|
||||
drvdata->enable = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
static int aw99703_bl_get_brightness(struct backlight_device *bl_dev)
|
||||
{
|
||||
return bl_dev->props.brightness;
|
||||
}
|
||||
|
||||
static int aw99703_bl_update_status(struct backlight_device *bl_dev)
|
||||
{
|
||||
struct aw99703_data *drvdata = bl_get_data(bl_dev);
|
||||
int brt;
|
||||
|
||||
if (bl_dev->props.state & BL_CORE_SUSPENDED)
|
||||
bl_dev->props.brightness = 0;
|
||||
|
||||
brt = bl_dev->props.brightness;
|
||||
/*
|
||||
* Brightness register should always be written
|
||||
* not only register based mode but also in PWM mode.
|
||||
*/
|
||||
return aw99703_set_brightness(drvdata, brt);
|
||||
}
|
||||
|
||||
static const struct backlight_ops aw99703_bl_ops = {
|
||||
.update_status = aw99703_bl_update_status,
|
||||
.get_brightness = aw99703_bl_get_brightness,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int aw99703_read_chipid(struct aw99703_data *drvdata)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 value = 0;
|
||||
unsigned char cnt = 0;
|
||||
|
||||
while (cnt < AW_READ_CHIPID_RETRIES) {
|
||||
ret = aw99703_i2c_read(drvdata->client, 0x00, &value);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to read reg AW99703_REG_ID: %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
switch (value) {
|
||||
case 0x03:
|
||||
pr_info("%s aw99703 detected\n", __func__);
|
||||
return 0;
|
||||
default:
|
||||
pr_info("%s unsupported device revision (0x%x)\n",
|
||||
__func__, value);
|
||||
break;
|
||||
}
|
||||
cnt++;
|
||||
|
||||
msleep(AW_READ_CHIPID_RETRY_DELAY);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static void __aw99703_work(struct aw99703_data *led,
|
||||
enum led_brightness value)
|
||||
{
|
||||
mutex_lock(&led->lock);
|
||||
aw99703_set_brightness(led, value);
|
||||
mutex_unlock(&led->lock);
|
||||
}
|
||||
|
||||
static void aw99703_work(struct work_struct *work)
|
||||
{
|
||||
struct aw99703_data *drvdata = container_of(work,
|
||||
struct aw99703_data, work);
|
||||
|
||||
__aw99703_work(drvdata, drvdata->led_dev.brightness);
|
||||
}
|
||||
|
||||
|
||||
static void aw99703_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brt_val)
|
||||
{
|
||||
struct aw99703_data *drvdata;
|
||||
|
||||
drvdata = container_of(led_cdev, struct aw99703_data, led_dev);
|
||||
schedule_work(&drvdata->work);
|
||||
}
|
||||
|
||||
static int aw99703_parse_dt(struct aw99703_data *drvdata)
|
||||
{
|
||||
struct device_node *chosen;
|
||||
int rc = -EINVAL;
|
||||
|
||||
pr_info("%s enter\n", __func__);
|
||||
chosen = of_find_node_by_name(NULL, "chosen");
|
||||
if (chosen) {
|
||||
const char *supplier;
|
||||
char *s, *d;
|
||||
|
||||
rc = of_property_read_string(chosen, "mmi,panel_name", (const char **)&supplier);
|
||||
if (rc) {
|
||||
pr_info("%s: cannot read mmi,panel_name %d\n", __func__, rc);
|
||||
} else {
|
||||
int split_num = 0;
|
||||
/* keep panel & ic info */
|
||||
s = (char *)supplier;
|
||||
d = drvdata->panel_info;
|
||||
while (*s && split_num < 2) {
|
||||
*d++ = *s++;
|
||||
if (*s == '_')
|
||||
split_num++;
|
||||
}
|
||||
|
||||
pr_info("%s: panel_info %s\n", __func__, drvdata->panel_info);
|
||||
}
|
||||
of_node_put(chosen);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
aw99703_get_dt_data(struct device *dev, struct aw99703_data *drvdata)
|
||||
{
|
||||
int rc;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 bl_channel, temp;
|
||||
|
||||
drvdata->hwen_gpio = of_get_named_gpio(np, "aw99703,hwen-gpio", 0);
|
||||
pr_info("%s drvdata->hwen_gpio --<%d>\n", __func__, drvdata->hwen_gpio);
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,pwm-mode", &drvdata->pwm_mode);
|
||||
if (rc != 0)
|
||||
pr_err("%s pwm-mode not found\n", __func__);
|
||||
else
|
||||
pr_info("%s pwm_mode=%d\n", __func__, drvdata->pwm_mode);
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,map-type", &drvdata->map_type);
|
||||
if (rc != 0) {
|
||||
drvdata->map_type = AW99703_MODE_MAP_LINEAR;
|
||||
pr_err("%s map-type not found\n", __func__);
|
||||
}
|
||||
else
|
||||
pr_info("%s map-type=%d\n", __func__, drvdata->map_type);
|
||||
|
||||
drvdata->using_lsb = of_property_read_bool(np, "aw99703,using-lsb");
|
||||
pr_info("%s using_lsb --<%d>\n", __func__, drvdata->using_lsb);
|
||||
|
||||
if (drvdata->using_lsb) {
|
||||
drvdata->max_brightness = 2047;
|
||||
} else {
|
||||
drvdata->max_brightness = 255;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,default-brightness", &drvdata->default_brightness);
|
||||
if (rc != 0) {
|
||||
drvdata->default_brightness = drvdata->max_brightness;
|
||||
pr_err("%s default-brightness not found, set to max %d\n", __func__, drvdata->default_brightness);
|
||||
}
|
||||
else
|
||||
pr_info("%s default-brightness=%d\n", __func__, drvdata->default_brightness);
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,bl-fscal-led", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid backlight full-scale led current!\n");
|
||||
} else {
|
||||
drvdata->full_scale_led = temp;
|
||||
pr_info("%s full-scale led current --<%d mA>\n",
|
||||
__func__, drvdata->full_scale_led);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,turn-on-ramp", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid ramp timing ,turnon!\n");
|
||||
} else {
|
||||
drvdata->ramp_on_time = temp;
|
||||
pr_info("%s ramp on time --<%d ms>\n",
|
||||
__func__, drvdata->ramp_on_time);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,turn-off-ramp", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid ramp timing ,,turnoff!\n");
|
||||
} else {
|
||||
drvdata->ramp_off_time = temp;
|
||||
pr_info("%s ramp off time --<%d ms>\n",
|
||||
__func__, drvdata->ramp_off_time);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,pwm-trans-dim", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid pwm-tarns-dim value!\n");
|
||||
} else {
|
||||
drvdata->pwm_trans_dim = temp;
|
||||
pr_info("%s pwm trnasition dimming --<%d ms>\n",
|
||||
__func__, drvdata->pwm_trans_dim);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,i2c-trans-dim", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid i2c-trans-dim value !\n");
|
||||
} else {
|
||||
drvdata->i2c_trans_dim = temp;
|
||||
pr_info("%s i2c transition dimming --<%d ms>\n",
|
||||
__func__, drvdata->i2c_trans_dim);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,bl-channel", &bl_channel);
|
||||
if (rc) {
|
||||
pr_err("Invalid channel setup\n");
|
||||
} else {
|
||||
drvdata->channel = bl_channel;
|
||||
pr_info("%s bl-channel --<%x>\n", __func__, drvdata->channel);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,bl-map", &drvdata->bl_map);
|
||||
if (rc != 0)
|
||||
pr_err("%s bl_map not found\n", __func__);
|
||||
else
|
||||
pr_info("%s bl_map=%d\n", __func__, drvdata->bl_map);
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,ovp-level", &temp);
|
||||
if (rc) {
|
||||
drvdata->ovp_level = AW99703_BSTCTR1_OVPSEL_38V;
|
||||
pr_err("ovp-level not found, set default %x!\n", drvdata->ovp_level);
|
||||
} else {
|
||||
drvdata->ovp_level = temp<<2;
|
||||
pr_info("%s ovp_level %x\n", __func__, drvdata->ovp_level);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,ocp-level", &temp);
|
||||
if (rc) {
|
||||
drvdata->ocp_level = AW99703_BSTCTR1_OCPSEL_2P7A;
|
||||
pr_err("ocp-level not found, set default %x!\n", drvdata->ocp_level);
|
||||
} else {
|
||||
drvdata->ocp_level = temp;
|
||||
pr_info("%s ocp_level %x\n", __func__, drvdata->ocp_level);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "aw99703,bl-slow-reg", &drvdata->bl_slow_reg);
|
||||
if (!rc) {
|
||||
const char *reconfg_panel;
|
||||
|
||||
pr_info("%s bl_slow_reg=%d\n", __func__, drvdata->bl_slow_reg);
|
||||
rc = of_property_read_string(np, "aw99703,bl-reconfig-panel", (const char **)&reconfg_panel);
|
||||
if (rc) {
|
||||
/* enable for all panels */
|
||||
drvdata->bl_reconfig_enable = true;
|
||||
}
|
||||
else {
|
||||
rc = aw99703_parse_dt(drvdata);
|
||||
if (!rc && strstr(drvdata->panel_info, reconfg_panel)) {
|
||||
/* enable for matched panel */
|
||||
drvdata->bl_reconfig_enable = true;
|
||||
}
|
||||
}
|
||||
pr_info("%s bl_reconfig_enable=%d\n", __func__, drvdata->bl_reconfig_enable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
*
|
||||
* sys group attribute: reg
|
||||
*
|
||||
******************************************************/
|
||||
static ssize_t aw99703_i2c_reg_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct aw99703_data *aw99703 = dev_get_drvdata(dev);
|
||||
|
||||
unsigned int databuf[2] = {0, 0};
|
||||
|
||||
if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) {
|
||||
aw99703_i2c_write(aw99703->client,
|
||||
(unsigned char)databuf[0],
|
||||
(unsigned char)databuf[1]);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t aw99703_i2c_reg_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct aw99703_data *aw99703 = dev_get_drvdata(dev);
|
||||
ssize_t len = 0;
|
||||
unsigned char i = 0;
|
||||
unsigned char reg_val = 0;
|
||||
|
||||
for (i = 0; i < AW99703_REG_MAX; i++) {
|
||||
if (!(aw99703_reg_access[i]®_RD_ACCESS))
|
||||
continue;
|
||||
aw99703_i2c_read(aw99703->client, i, ®_val);
|
||||
len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x\n",
|
||||
i, reg_val);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(reg, 0664, aw99703_i2c_reg_show, aw99703_i2c_reg_store);
|
||||
static struct attribute *aw99703_attributes[] = {
|
||||
&dev_attr_reg.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group aw99703_attribute_group = {
|
||||
.attrs = aw99703_attributes
|
||||
};
|
||||
|
||||
static int aw99703_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct aw99703_data *drvdata;
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
struct backlight_device *bl_dev;
|
||||
struct backlight_properties props;
|
||||
#endif
|
||||
int err = 0;
|
||||
pr_err("%s enter! driver version %s\n", __func__, AW99703_VERSION);
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
pr_err("%s : I2C_FUNC_I2C not supported\n", __func__);
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (!client->dev.of_node) {
|
||||
pr_err("%s : no device node\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
drvdata = kzalloc(sizeof(struct aw99703_data), GFP_KERNEL);
|
||||
if (drvdata == NULL) {
|
||||
pr_err("%s : kzalloc failed\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
drvdata->client = client;
|
||||
drvdata->adapter = client->adapter;
|
||||
drvdata->addr = client->addr;
|
||||
drvdata->brightness = LED_OFF;
|
||||
drvdata->enable = true;
|
||||
drvdata->led_dev.default_trigger = "bkl-trigger";
|
||||
drvdata->led_dev.name = AW99703_LED_DEV;
|
||||
drvdata->led_dev.brightness_set = aw99703_brightness_set;
|
||||
drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
|
||||
mutex_init(&drvdata->lock);
|
||||
INIT_WORK(&drvdata->work, aw99703_work);
|
||||
aw99703_get_dt_data(&client->dev, drvdata);
|
||||
i2c_set_clientdata(client, drvdata);
|
||||
aw99703_gpio_init(drvdata);
|
||||
|
||||
err = aw99703_read_chipid(drvdata);
|
||||
if (err < 0) {
|
||||
pr_err("%s : ID idenfy failed\n", __func__);
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
err = led_classdev_register(&client->dev, &drvdata->led_dev);
|
||||
if (err < 0) {
|
||||
pr_err("%s : Register led class failed\n", __func__);
|
||||
err = -ENODEV;
|
||||
goto err_init;
|
||||
} else {
|
||||
pr_debug("%s: Register led class successful\n", __func__);
|
||||
}
|
||||
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.brightness = MAX_BRIGHTNESS;
|
||||
props.max_brightness = MAX_BRIGHTNESS;
|
||||
bl_dev = backlight_device_register(AW99703_NAME, &client->dev,
|
||||
drvdata, &aw99703_bl_ops, &props);
|
||||
#endif
|
||||
|
||||
g_aw99703_data = drvdata;
|
||||
aw99703_backlight_init(drvdata);
|
||||
aw99703_backlight_enable(drvdata);
|
||||
|
||||
aw99703_set_brightness(drvdata, drvdata->default_brightness);
|
||||
err = sysfs_create_group(&client->dev.kobj, &aw99703_attribute_group);
|
||||
if (err < 0) {
|
||||
dev_info(&client->dev, "%s error creating sysfs attr files\n",
|
||||
__func__);
|
||||
goto err_sysfs;
|
||||
}
|
||||
pr_info("%s exit\n", __func__);
|
||||
return 0;
|
||||
|
||||
err_sysfs:
|
||||
err_init:
|
||||
gpio_free(drvdata->hwen_gpio);
|
||||
kfree(drvdata);
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int aw99703_remove(struct i2c_client *client)
|
||||
{
|
||||
struct aw99703_data *drvdata = i2c_get_clientdata(client);
|
||||
|
||||
led_classdev_unregister(&drvdata->led_dev);
|
||||
|
||||
kfree(drvdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id aw99703_id[] = {
|
||||
{AW99703_NAME, 0},
|
||||
{}
|
||||
};
|
||||
static struct of_device_id match_table[] = {
|
||||
{.compatible = "awinic,aw99703-bl",}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, aw99703_id);
|
||||
|
||||
static struct i2c_driver aw99703_i2c_driver = {
|
||||
.probe = aw99703_probe,
|
||||
.remove = aw99703_remove,
|
||||
.id_table = aw99703_id,
|
||||
.driver = {
|
||||
.name = AW99703_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_i2c_driver(aw99703_i2c_driver);
|
||||
MODULE_DESCRIPTION("Back Light driver for aw99703");
|
||||
MODULE_LICENSE("GPL v2");
|
257
drivers/backlight/aw99703/leds_aw99703.h
Normal file
257
drivers/backlight/aw99703/leds_aw99703.h
Normal file
|
@ -0,0 +1,257 @@
|
|||
#ifndef _AW99703_REG_H_
|
||||
#define _AW99703_REG_H_
|
||||
|
||||
/*********************************************************
|
||||
*
|
||||
* kernel version
|
||||
*
|
||||
********************************************************/
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||
#define KERNEL_ABOVE_4_14
|
||||
#endif
|
||||
|
||||
/********************************************
|
||||
* Register List
|
||||
*******************************************/
|
||||
#define AW99703_REG_MAX 0x70
|
||||
#define AW99703_REG_ID 0x00
|
||||
#define AW99703_REG_SFTRST 0x01
|
||||
#define AW99703_REG_MODE 0x02
|
||||
#define AW99703_REG_LEDCUR 0x03
|
||||
#define AW99703_REG_BSTCTR1 0x04
|
||||
#define AW99703_REG_BSTCTR2 0x05
|
||||
#define AW99703_REG_LEDLSB 0x06
|
||||
#define AW99703_REG_LEDMSB 0x07
|
||||
#define AW99703_REG_PWM 0x08
|
||||
#define AW99703_REG_TURNCFG 0x09
|
||||
#define AW99703_REG_TRANCFG 0x0a
|
||||
#define AW99703_REG_FLASH 0x0b
|
||||
#define AW99703_REG_AFHIGH 0x0c
|
||||
#define AW99703_REG_AFLOW 0x0d
|
||||
#define AW99703_REG_FLAGS1 0x0e
|
||||
#define AW99703_REG_FLAGS2 0x0f
|
||||
#define AW99703_REG_FLAGS3 0x11
|
||||
#define AW99703_REG_AUTOZERO 0x21
|
||||
#define AW99703_REG_EMI 0x22
|
||||
#define AW99703_REG_BSTCTR3 0x23
|
||||
#define AW99703_REG_BSTCTR4 0x24
|
||||
#define AW99703_REG_BSTCTR5 0x25
|
||||
#define AW99703_REG_LEDCFG 0x26
|
||||
#define AW99703_REG_DITHER 0x27
|
||||
#define AW99703_REG_PWMMSB 0x28
|
||||
#define AW99703_REG_PWMLSB 0x29
|
||||
#define AW99703_REG_TEST 0x31
|
||||
#define AW99703_REG_FLTDIS 0x33
|
||||
#define AW99703_REG_EFUSE1 0x40
|
||||
#define AW99703_REG_EFUSE2 0x41
|
||||
#define AW99703_REG_EFUSE3 0x42
|
||||
#define AW99703_REG_EFUSE4 0x43
|
||||
#define AW99703_REG_EFUSE5 0x44
|
||||
#define AW99703_REG_EFUSE6 0x45
|
||||
#define AW99703_REG_EFUSE7 0x46
|
||||
#define AW99703_REG_EFUSE8 0x47
|
||||
#define AW99703_REG_EFRUN 0x48
|
||||
#define AW99703_REG_EFMODE 0x49
|
||||
#define AW99703_REG_WPRT1 0x67
|
||||
#define AW99703_REG_WPRT2 0x68
|
||||
#define AW99703_REG_SCANEN 0x69
|
||||
|
||||
|
||||
/********************************************
|
||||
* Register Access
|
||||
*******************************************/
|
||||
#define REG_NONE_ACCESS 0
|
||||
#define REG_RD_ACCESS (1 << 0)
|
||||
#define REG_WR_ACCESS (1 << 1)
|
||||
|
||||
const unsigned char aw99703_reg_access[AW99703_REG_MAX] = {
|
||||
[AW99703_REG_ID] = REG_RD_ACCESS,
|
||||
[AW99703_REG_SFTRST] = REG_WR_ACCESS,
|
||||
[AW99703_REG_MODE] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_LEDCUR] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_BSTCTR1] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_BSTCTR2] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_LEDLSB] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_LEDMSB] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_PWM] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_TURNCFG] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_TRANCFG] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_FLASH] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_AFHIGH] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_AFLOW] = REG_RD_ACCESS|REG_WR_ACCESS,
|
||||
[AW99703_REG_FLAGS1] = REG_RD_ACCESS,
|
||||
[AW99703_REG_FLAGS2] = REG_RD_ACCESS,
|
||||
[AW99703_REG_FLAGS3] = REG_RD_ACCESS,
|
||||
[AW99703_REG_AUTOZERO] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EMI] = REG_RD_ACCESS,
|
||||
[AW99703_REG_BSTCTR3] = REG_RD_ACCESS,
|
||||
[AW99703_REG_BSTCTR4] = REG_RD_ACCESS,
|
||||
[AW99703_REG_BSTCTR5] = REG_RD_ACCESS,
|
||||
[AW99703_REG_LEDCFG] = REG_RD_ACCESS,
|
||||
[AW99703_REG_DITHER] = REG_RD_ACCESS,
|
||||
[AW99703_REG_PWMMSB] = REG_RD_ACCESS,
|
||||
[AW99703_REG_PWMLSB] = REG_RD_ACCESS,
|
||||
[AW99703_REG_TEST] = REG_RD_ACCESS,
|
||||
[AW99703_REG_FLTDIS] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFUSE1] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFUSE2] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFUSE3] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFUSE4] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFUSE5] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFUSE6] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFUSE7] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFUSE8] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFRUN] = REG_RD_ACCESS,
|
||||
[AW99703_REG_EFMODE] = REG_RD_ACCESS,
|
||||
[AW99703_REG_WPRT1] = REG_RD_ACCESS,
|
||||
[AW99703_REG_WPRT2] = REG_RD_ACCESS,
|
||||
[AW99703_REG_SCANEN] = REG_RD_ACCESS,
|
||||
};
|
||||
|
||||
#define MAX_BRIGHTNESS (2047)
|
||||
/******************************************************
|
||||
* Register Detail
|
||||
*****************************************************/
|
||||
/*SFTRST:0x01*/
|
||||
#define AW99703_SFTRST_MASK (~(1<<0))
|
||||
#define AW99703_SFTRST_NOT_RST (0<<0)
|
||||
#define AW99703_SFTRST_RST (1<<0)
|
||||
|
||||
/*MODE:0x02*/
|
||||
#define AW99703_MODE_PDIS_MASK (~(1<<4))
|
||||
#define AW99703_MODE_PDIS_ENABLE (0<<4)
|
||||
#define AW99703_MODE_PDIS_DISABLE (1<<4)
|
||||
#define AW99703_MODE_MAP_MASK (~(1<<2))
|
||||
#define AW99703_MODE_MAP_EXPONENTIAL (0<<2)
|
||||
#define AW99703_MODE_MAP_LINEAR (1<<2)
|
||||
#define AW99703_MODE_WORKMODE_MASK (~(3<<0))
|
||||
#define AW99703_MODE_WORKMODE_STANDBY (0<<0)
|
||||
#define AW99703_MODE_WORKMODE_BACKLIGHT (1<<0)
|
||||
#define AW99703_MODE_WORKMODE_FLASH (2<<0)
|
||||
|
||||
/*MODE:0x03*/
|
||||
#define AW99703_LEDCUR_BLFS_MASK (~(31<<3))
|
||||
#define AW99703_LEDCUR_CHANNEL_MASK (~(7<<0))
|
||||
#define AW99703_LEDCUR_CH3_ENABLE (1<<2)
|
||||
#define AW99703_LEDCUR_CH3_DISABLE (0<<2)
|
||||
#define AW99703_LEDCUR_CH2_ENABLE (1<<1)
|
||||
#define AW99703_LEDCUR_CH2_DISABLE (0<<1)
|
||||
#define AW99703_LEDCUR_CH1_ENABLE (1<<0)
|
||||
#define AW99703_LEDCUR_CH1_DISABLE (0<<0)
|
||||
|
||||
/*BSTCTR1:0x04*/
|
||||
#define AW99703_BSTCTR1_SF_SFT_MASK (~(3<<6))
|
||||
#define AW99703_BSTCTR1_SF_SFT_UP20 (1<<6)
|
||||
#define AW99703_BSTCTR1_SF_SFT_DOWN12 (2<<6)
|
||||
#define AW99703_BSTCTR1_SF_SFT_DOWN24 (3<<6)
|
||||
#define AW99703_BSTCTR1_SF_MASK (~(1<<5))
|
||||
#define AW99703_BSTCTR1_SF_500KHZ (0<<5)
|
||||
#define AW99703_BSTCTR1_SF_1000KHZ (1<<5)
|
||||
#define AW99703_BSTCTR1_OVPSEL_MASK (~(7<<2))
|
||||
#define AW99703_BSTCTR1_OVPSEL_17V (0<<2)
|
||||
#define AW99703_BSTCTR1_OVPSEL_24V (1<<2)
|
||||
#define AW99703_BSTCTR1_OVPSEL_31V (2<<2)
|
||||
#define AW99703_BSTCTR1_OVPSEL_38V (3<<2)
|
||||
#define AW99703_BSTCTR1_OVPSEL_41P5V (4<<2)
|
||||
#define AW99703_BSTCTR1_OCPSEL_MASK (~(3<<0))
|
||||
#define AW99703_BSTCTR1_OCPSEL_0P9A (0<<0)
|
||||
#define AW99703_BSTCTR1_OCPSEL_1P8A (1<<0)
|
||||
#define AW99703_BSTCTR1_OCPSEL_2P7A (2<<0)
|
||||
#define AW99703_BSTCTR1_OCPSEL_3P4A (3<<0)
|
||||
|
||||
/*BSTCTR2:0x05*/
|
||||
#define AW99703_BSTCTR2_AFEN_MASK (~(1<<7))
|
||||
#define AW99703_BSTCTR2_AFEN_ENABLE (1<<7)
|
||||
#define AW99703_BSTCTR2_AFEN_DISABLE (0<<7)
|
||||
#define AW99703_BSTCTR2_IDCTSEL_MASK (~(1<<6))
|
||||
#define AW99703_BSTCTR2_IDCTSEL_4P7UH (0<<6)
|
||||
#define AW99703_BSTCTR2_IDCTSEL_10UH (1<<6)
|
||||
#define AW99703_BSTCTR2_EMISEL_MASK (~(7<<3))
|
||||
#define AW99703_BSTCTR2_EMISEL_TYPICAL (0<<3)
|
||||
#define AW99703_BSTCTR2_EMISEL_SLOW1 (1<<3)
|
||||
#define AW99703_BSTCTR2_EMISEL_SLOW2 (2<<3)
|
||||
#define AW99703_BSTCTR2_EMISEL_SLOW3 (3<<3)
|
||||
#define AW99703_BSTCTR2_EMISEL_FAST1 (4<<3)
|
||||
#define AW99703_BSTCTR2_EMISEL_FAST2 (5<<3)
|
||||
#define AW99703_BSTCTR2_EMISEL_FAST3 (6<<3)
|
||||
#define AW99703_BSTCTR2_EMISEL_FAST4 (7<<3)
|
||||
#define AW99703_BSTCTR2_ADEN_MASK (~(1<<2))
|
||||
#define AW99703_BSTCTR2_ADEN_ENABLE (1<<2)
|
||||
#define AW99703_BSTCTR2_ADEN_DISABLE (0<<2)
|
||||
|
||||
/*PWM:0x08*/
|
||||
#define AW99703_PWM_P_SF_MASK (~(3<<6))
|
||||
#define AW99703_PWM_P_SF_800KHZ (0<<6)
|
||||
#define AW99703_PWM_P_SF_4MKHZ (1<<6)
|
||||
#define AW99703_PWM_P_SF_24MKHZ (2<<6)
|
||||
#define AW99703_PWM_P_ACT_MASK (~(1<<5))
|
||||
#define AW99703_PWM_P_ACT_HIGH (0<<5)
|
||||
#define AW99703_PWM_P_ACT_LOW (1<<5)
|
||||
#define AW99703_PWM_P_HYS_MASK (~(7<<2))
|
||||
#define AW99703_PWM_P_HYS_NONE (0<<2)
|
||||
#define AW99703_PWM_P_HYS_1LSB (1<<2)
|
||||
#define AW99703_PWM_P_HYS_2LSB (2<<2)
|
||||
#define AW99703_PWM_P_HYS_3LSB (3<<2)
|
||||
#define AW99703_PWM_P_HYS_4LSB (4<<2)
|
||||
#define AW99703_PWM_P_HYS_5LSB (5<<2)
|
||||
#define AW99703_PWM_P_HYS_6LSB (6<<2)
|
||||
#define AW99703_PWM_P_HYS_7LSB (7<<2)
|
||||
#define AW99703_PWM_P_FLT_MASK (~(3<<0))
|
||||
#define AW99703_PWM_P_FLT_NONE (0<<0)
|
||||
#define AW99703_PWM_P_FLT_100MS (1<<0)
|
||||
#define AW99703_PWM_P_FLT_150MS (2<<0)
|
||||
#define AW99703_PWM_P_FLT_200MS (3<<0)
|
||||
|
||||
/*TURNCFG:0x09*/
|
||||
#define AW99703_TURNCFG_ON_TIM_MASK (~(15<<4))
|
||||
#define AW99703_TURNCFG_OFF_TIM_MASK (~(15<<0))
|
||||
|
||||
/*TRANCFG:0x0A*/
|
||||
#define AW99703_TRANCFG_PWM_TIM_MASK (~(7<<4))
|
||||
#define AW99703_TRANCFG_I2C_TIM_MASK (~(15<<0))
|
||||
|
||||
#define MAX_BRIGHTNESS (2047)
|
||||
#define AW_READ_CHIPID_RETRIES 5
|
||||
#define AW_READ_CHIPID_RETRY_DELAY 2
|
||||
|
||||
struct aw99703_data {
|
||||
struct led_classdev led_dev;
|
||||
struct i2c_client *client;
|
||||
struct device dev;
|
||||
struct i2c_adapter *adapter;
|
||||
unsigned short addr;
|
||||
struct mutex lock;
|
||||
struct work_struct work;
|
||||
enum led_brightness brightness;
|
||||
bool enable;
|
||||
unsigned char pwm_cfg;
|
||||
unsigned char full_scale_current;
|
||||
bool brt_code_enable;
|
||||
unsigned short *brt_code_table;
|
||||
int hwen_gpio;
|
||||
unsigned int pwm_mode;
|
||||
unsigned int map_type;
|
||||
bool using_lsb;
|
||||
bool bl_reconfig_enable;
|
||||
char panel_info[16];
|
||||
unsigned int bl_slow_reg;
|
||||
unsigned int pwm_period;
|
||||
unsigned int full_scale_led;
|
||||
unsigned int ramp_on_time;
|
||||
unsigned int ramp_off_time;
|
||||
unsigned int pwm_trans_dim;
|
||||
unsigned int i2c_trans_dim;
|
||||
unsigned int channel;
|
||||
unsigned int ovp_level;
|
||||
unsigned int ocp_level;
|
||||
unsigned int frequency;
|
||||
unsigned int default_brightness;
|
||||
unsigned int max_brightness;
|
||||
unsigned int induct_current;
|
||||
unsigned int flash_current;
|
||||
unsigned int flash_timeout;
|
||||
unsigned int bl_map;
|
||||
struct backlight_device *bl_dev;
|
||||
};
|
||||
|
||||
#endif
|
14
drivers/backlight/ktd3136/Android.mk
Normal file
14
drivers/backlight/ktd3136/Android.mk
Normal file
|
@ -0,0 +1,14 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := ktd3136_bl.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true)
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/
|
||||
else
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
endif
|
||||
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
5
drivers/backlight/ktd3136/Kbuild
Normal file
5
drivers/backlight/ktd3136/Kbuild
Normal file
|
@ -0,0 +1,5 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
|
||||
|
||||
obj-m += ktd3136_bl.o
|
10
drivers/backlight/ktd3136/Makefile
Normal file
10
drivers/backlight/ktd3136/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
704
drivers/backlight/ktd3136/ktd3136_bl.c
Normal file
704
drivers/backlight/ktd3136/ktd3136_bl.c
Normal file
|
@ -0,0 +1,704 @@
|
|||
/*
|
||||
* KTD3136_BL Driver
|
||||
*
|
||||
* SiliconMitus KTD3136 Backlight driver chip
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/backlight.h>
|
||||
#if defined(CONFIG_FB)
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/fb.h>
|
||||
#endif
|
||||
|
||||
#include "ktd3136_bl.h"
|
||||
|
||||
#define KTD3136_LED_DEV "ktd3136-BL"
|
||||
#define KTD3136_NAME "ktd3136-bl"
|
||||
#define KTD3136_CHIP_ID 0x18
|
||||
|
||||
static int platform_read_i2c_block(struct i2c_client *client, char *writebuf,
|
||||
int writelen, char *readbuf, int readlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (writelen > 0) {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 2);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: i2c read error.\n",
|
||||
__func__);
|
||||
} else {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s:i2c read error.\n", __func__);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ktd3136_read_reg(struct i2c_client *client, u8 addr, u8 *val)
|
||||
{
|
||||
return platform_read_i2c_block(client, &addr, 1, val, 1);
|
||||
}
|
||||
|
||||
static int platform_write_i2c_block(struct i2c_client *client, char *writebuf, int writelen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: i2c write error.\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ktd3136_write_reg(struct i2c_client *client, u8 addr, const u8 val)
|
||||
{
|
||||
u8 buf[2] = {0};
|
||||
|
||||
buf[0] = addr;
|
||||
buf[1] = val;
|
||||
return platform_write_i2c_block(client, buf, sizeof(buf));
|
||||
}
|
||||
static void ktd3136_hwen_pin_ctrl(struct ktd3136_data *drvdata, int en)
|
||||
{
|
||||
if (gpio_is_valid(drvdata->hwen_gpio)) {
|
||||
if (en) {
|
||||
pr_debug("hwen pin is going to be high!---<%d>\n", en);
|
||||
gpio_set_value(drvdata->hwen_gpio, true);
|
||||
} else {
|
||||
pr_debug("hwen pin is going to be low!---<%d>\n", en);
|
||||
gpio_set_value(drvdata->hwen_gpio, false);
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int ktd3136_gpio_init(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_info("%s enter\n", __func__);
|
||||
if (gpio_is_valid(drvdata->hwen_gpio)) {
|
||||
ret = gpio_request(drvdata->hwen_gpio, "ktd_hwen_gpio");
|
||||
if (ret<0) {
|
||||
pr_err("failed to request gpio\n");
|
||||
return -1;
|
||||
}
|
||||
ret = gpio_direction_output(drvdata->hwen_gpio, 0);
|
||||
pr_debug(" request gpio init\n");
|
||||
if (ret<0) {
|
||||
pr_err("failed to set output");
|
||||
gpio_free(drvdata->hwen_gpio);
|
||||
return ret;
|
||||
}
|
||||
pr_debug("gpio is valid!\n");
|
||||
ktd3136_hwen_pin_ctrl(drvdata, 1);
|
||||
}
|
||||
|
||||
pr_info("%s exit\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
static int ktd3136_masked_write(struct i2c_client *client, int reg, u8 mask, u8 val)
|
||||
{
|
||||
int rc;
|
||||
u8 temp;
|
||||
|
||||
rc = ktd3136_read_reg(client, reg, &temp);
|
||||
if (rc < 0) {
|
||||
pr_err("failed to read reg=0x%x, rc=%d\n", reg, rc);
|
||||
} else {
|
||||
temp &= ~mask;
|
||||
temp |= val & mask;
|
||||
rc = ktd3136_write_reg(client, reg, temp);
|
||||
if (rc<0) {
|
||||
pr_err( "failed to write masked data. reg=%03x, rc=%d\n", reg, rc);
|
||||
}
|
||||
}
|
||||
|
||||
ktd3136_read_reg(client, reg, &temp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ktd3136_bl_enable_channel(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (drvdata->channel == 0) {
|
||||
//default value for mode Register, all channel disabled.
|
||||
pr_debug("all channels are going to be disabled\n");
|
||||
ret = ktd3136_write_reg(drvdata->client, REG_PWM, 0x18);//b0001 1000
|
||||
} else if (drvdata->channel == 3) {
|
||||
pr_debug("turn all channel on!\n");
|
||||
ret = ktd3136_masked_write(drvdata->client, REG_PWM, 0x07, 0x07);
|
||||
} else if (drvdata->channel == 2) {
|
||||
ret = ktd3136_masked_write(drvdata->client, REG_PWM, 0x07, 0x03);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
static void ktd3136_pwm_mode_enable(struct ktd3136_data *drvdata, bool en)
|
||||
{
|
||||
u8 value;
|
||||
|
||||
if (en) {
|
||||
if (drvdata->pwm_mode) {
|
||||
pr_debug("already activated!\n");
|
||||
} else {
|
||||
drvdata->pwm_mode = en;
|
||||
}
|
||||
ktd3136_masked_write(drvdata->client, REG_PWM, 0x80, 0x80);
|
||||
} else {
|
||||
if (drvdata->pwm_mode) {
|
||||
drvdata->pwm_mode = en;
|
||||
}
|
||||
ktd3136_masked_write(drvdata->client, REG_PWM, 0x80, 0x00);
|
||||
}
|
||||
|
||||
ktd3136_read_reg(drvdata->client, REG_PWM, &value);
|
||||
pr_debug("current pwm_mode is --<%x>\n", value);
|
||||
}
|
||||
static int ktd_find_bit(int x)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while ((x = x >> 1))
|
||||
i++;
|
||||
|
||||
return i+1;
|
||||
}
|
||||
|
||||
static void ktd3136_ramp_setting(struct ktd3136_data *drvdata)
|
||||
{
|
||||
unsigned int max_time = 16384;
|
||||
int temp = 0;
|
||||
|
||||
if (drvdata->ramp_on_time == 0) {//512us
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0xf0, 0x00);
|
||||
pr_debug("rampon time is 0 \n");
|
||||
} else if (drvdata->ramp_on_time > max_time) {
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0xf0, 0xf0);
|
||||
pr_debug("rampon time is max \n");
|
||||
} else {
|
||||
temp = ktd_find_bit(drvdata->ramp_on_time);
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0xf0, temp<<4);
|
||||
pr_debug("temp is %d\n", temp);
|
||||
}
|
||||
|
||||
if (drvdata->ramp_off_time == 0) {//512us
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0x0f, 0x00);
|
||||
pr_debug("rampoff time is 0 \n");
|
||||
} else if (drvdata->ramp_off_time > max_time) {
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0x0f, 0x0f);
|
||||
pr_debug("rampoff time is max \n");
|
||||
} else {
|
||||
temp = ktd_find_bit(drvdata->ramp_off_time);
|
||||
ktd3136_masked_write(drvdata->client, REG_RAMP_ON, 0x0f, temp);
|
||||
pr_debug("temp is %d\n", temp);
|
||||
}
|
||||
|
||||
}
|
||||
static void ktd3136_transition_ramp(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int reg_i2c, reg_pwm, temp;
|
||||
|
||||
if (drvdata->i2c_trans_dim >= 1024) {
|
||||
reg_i2c = 0xf;
|
||||
} else if (drvdata->i2c_trans_dim < 128) {
|
||||
reg_i2c = 0x0;
|
||||
} else {
|
||||
temp =drvdata->i2c_trans_dim/64;
|
||||
reg_i2c = temp-1;
|
||||
pr_debug("reg_i2c is --<0x%x>\n", reg_i2c);
|
||||
}
|
||||
|
||||
if(drvdata->pwm_trans_dim >= 256){
|
||||
reg_pwm = 0x7;
|
||||
}else if(drvdata->pwm_trans_dim < 4){
|
||||
reg_pwm = 0x0;
|
||||
}else{
|
||||
temp = ktd_find_bit(drvdata->pwm_trans_dim);
|
||||
reg_pwm = temp -2;
|
||||
pr_debug("temp is %d\n", temp);
|
||||
}
|
||||
|
||||
ktd3136_masked_write(drvdata->client, REG_TRANS_RAMP, 0x70, reg_pwm);
|
||||
ktd3136_masked_write(drvdata->client, REG_TRANS_RAMP, 0x0f, reg_i2c);
|
||||
|
||||
}
|
||||
|
||||
static int ktd3136_backlight_init(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int err = 0;
|
||||
u8 value;
|
||||
u8 update_value;
|
||||
pr_info("%s enter.\n", __func__);
|
||||
update_value = (drvdata->ovp_level == 32) ? 0x20 : 0x00;
|
||||
(drvdata->induct_current == 2600) ? update_value |=0x08 : update_value;
|
||||
(drvdata->frequency == 1000) ? update_value |=0x40: update_value;
|
||||
|
||||
ktd3136_write_reg(drvdata->client, REG_CONTROL, update_value | 0x06); /* Linear default*/
|
||||
ktd3136_bl_enable_channel(drvdata);
|
||||
if (drvdata->pwm_mode) {
|
||||
ktd3136_pwm_mode_enable(drvdata, true);
|
||||
} else {
|
||||
ktd3136_pwm_mode_enable(drvdata, false);
|
||||
}
|
||||
ktd3136_ramp_setting(drvdata);
|
||||
ktd3136_transition_ramp(drvdata);
|
||||
ktd3136_read_reg(drvdata->client, REG_CONTROL, &value);
|
||||
pr_debug("read control register -before--<0x%x> -after--<0x%x> \n",
|
||||
update_value, value);
|
||||
|
||||
pr_info("%s exit\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ktd3136_backlight_enable(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int err = 0;
|
||||
pr_info("%s enter.\n", __func__);
|
||||
ktd3136_masked_write(drvdata->client, REG_MODE, 0xf8, drvdata->full_scale_led);
|
||||
drvdata->enable = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ktd3136_set_brightness(struct ktd3136_data *drvdata, int brt_val)
|
||||
{
|
||||
pr_info("%s brt_val is %d\n", __func__, brt_val);
|
||||
|
||||
if (drvdata->enable == false)
|
||||
ktd3136_backlight_init(drvdata);
|
||||
|
||||
if (brt_val>0) {
|
||||
ktd3136_masked_write(drvdata->client, REG_MODE, 0x01, 0x01); //enalbe bl mode
|
||||
} else {
|
||||
ktd3136_masked_write(drvdata->client, REG_MODE, 0x01, 0x00); //disable bl mode
|
||||
}
|
||||
if (drvdata->using_lsb) {
|
||||
ktd3136_masked_write(drvdata->client, REG_RATIO_LSB, 0x07, brt_val);
|
||||
ktd3136_masked_write(drvdata->client, REG_RATIO_MSB, 0xff, brt_val>>3);
|
||||
} else {
|
||||
ktd3136_masked_write(drvdata->client, REG_RATIO_LSB, 0x07, ktd3136_brightness_table_reg4[brt_val]);
|
||||
ktd3136_masked_write(drvdata->client, REG_RATIO_MSB, 0xff, ktd3136_brightness_table_reg5[brt_val]);
|
||||
}
|
||||
|
||||
if (drvdata->enable == false)
|
||||
ktd3136_backlight_enable(drvdata);
|
||||
|
||||
drvdata->brightness = brt_val;
|
||||
|
||||
if (drvdata->brightness == 0)
|
||||
drvdata->enable = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
static int ktd3136_bl_get_brightness(struct backlight_device *bl_dev)
|
||||
{
|
||||
return bl_dev->props.brightness;
|
||||
}
|
||||
|
||||
static int ktd3136_bl_update_status(struct backlight_device *bl_dev)
|
||||
{
|
||||
struct ktd3136_data *drvdata = bl_get_data(bl_dev);
|
||||
int brt;
|
||||
|
||||
if (bl_dev->props.state & BL_CORE_SUSPENDED)
|
||||
bl_dev->props.brightness = 0;
|
||||
|
||||
brt = bl_dev->props.brightness;
|
||||
/*
|
||||
* Brightness register should always be written
|
||||
* not only register based mode but also in PWM mode.
|
||||
*/
|
||||
return ktd3136_set_brightness(drvdata, brt);
|
||||
}
|
||||
|
||||
static const struct backlight_ops ktd3136_bl_ops = {
|
||||
.update_status = ktd3136_bl_update_status,
|
||||
.get_brightness = ktd3136_bl_get_brightness,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int ktd3136_backlight_reset(struct ktd3136_data *drvdata)
|
||||
{
|
||||
int err = 0;
|
||||
ktd3136_masked_write(drvdata->client, REG_SW_RESET, 0x01, 0x01);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ktd3136_check_id(struct ktd3136_data *drvdata)
|
||||
{
|
||||
u8 value=0;
|
||||
int err = 0;
|
||||
ktd3136_read_reg(drvdata->client, 0x00, &value);
|
||||
pr_info("%s: ID check: %x0x\n", __func__, value);
|
||||
if (value != KTD3136_CHIP_ID) {
|
||||
pr_err("%s : ID check err\n", __func__);
|
||||
err = -EINVAL;
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ktd3136_check_status(struct ktd3136_data *drvdata)
|
||||
{
|
||||
u8 value=0;
|
||||
|
||||
ktd3136_read_reg(drvdata->client, REG_STATUS, &value);
|
||||
if (value) {
|
||||
pr_err("status bit has been change! <%x>", value);
|
||||
|
||||
if (value & RESET_CONDITION_BITS) {
|
||||
ktd3136_backlight_reset(drvdata);
|
||||
ktd3136_backlight_init(drvdata);
|
||||
ktd3136_backlight_enable(drvdata);
|
||||
}
|
||||
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FB)
|
||||
static int fb_notifier_callback(struct notifier_block *self,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
int *blank;
|
||||
struct fb_event *evdata = data;
|
||||
struct ktd3136_data *drvdata =
|
||||
container_of(self, struct ktd3136_data, fb_notif);
|
||||
|
||||
/*
|
||||
* FB_EVENT_BLANK(0x09): A hardware display blank change occurred.
|
||||
* FB_EARLY_EVENT_BLANK(0x10): A hardware display blank early change
|
||||
* occurred.
|
||||
*/
|
||||
if (evdata && evdata->data && (event == FB_EARLY_EVENT_BLANK)) {
|
||||
blank = evdata->data;
|
||||
if (*blank == FB_BLANK_POWERDOWN)
|
||||
drvdata->enable = false;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __ktd3136_work(struct ktd3136_data *led,
|
||||
enum led_brightness value)
|
||||
{
|
||||
mutex_lock(&led->lock);
|
||||
ktd3136_set_brightness(led, value);
|
||||
mutex_unlock(&led->lock);
|
||||
}
|
||||
|
||||
static void ktd3136_work(struct work_struct *work)
|
||||
{
|
||||
struct ktd3136_data *drvdata = container_of(work,
|
||||
struct ktd3136_data, work);
|
||||
|
||||
__ktd3136_work(drvdata, drvdata->led_dev.brightness);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void ktd3136_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brt_val)
|
||||
{
|
||||
struct ktd3136_data *drvdata;
|
||||
|
||||
drvdata = container_of(led_cdev, struct ktd3136_data, led_dev);
|
||||
|
||||
schedule_work(&drvdata->work);
|
||||
}
|
||||
|
||||
static void ktd3136_get_dt_data(struct device *dev, struct ktd3136_data *drvdata)
|
||||
{
|
||||
int rc;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 bl_channel, temp;
|
||||
drvdata->hwen_gpio = of_get_named_gpio(np, "ktd,hwen-gpio", 0);
|
||||
pr_info("%s hwen --<%d>\n", __func__, drvdata->hwen_gpio);
|
||||
|
||||
drvdata->pwm_mode = of_property_read_bool(np,"ktd,pwm-mode");
|
||||
pr_debug("pwmmode --<%d> \n", drvdata->pwm_mode);
|
||||
|
||||
drvdata->using_lsb = of_property_read_bool(np, "ktd,using-lsb");
|
||||
pr_info("%s using_lsb --<%d>\n", __func__, drvdata->using_lsb);
|
||||
|
||||
if (drvdata->using_lsb) {
|
||||
drvdata->default_brightness = 0x7ff;
|
||||
drvdata->max_brightness = 2047;
|
||||
} else {
|
||||
drvdata->default_brightness = 0xff;
|
||||
drvdata->max_brightness = 255;
|
||||
}
|
||||
rc = of_property_read_u32(np, "ktd,pwm-frequency", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid pwm-frequency!\n");
|
||||
} else {
|
||||
drvdata->pwm_period = temp;
|
||||
pr_debug("pwm-frequency --<%d> \n", drvdata->pwm_period);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,bl-fscal-led", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid backlight full-scale led current!\n");
|
||||
} else {
|
||||
drvdata->full_scale_led = temp;
|
||||
pr_debug("full-scale led current --<%d mA> \n", drvdata->full_scale_led);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,turn-on-ramp", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid ramp timing ,,turnon!\n");
|
||||
} else {
|
||||
drvdata->ramp_on_time = temp;
|
||||
pr_debug("ramp on time --<%d ms> \n", drvdata->ramp_on_time);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,turn-off-ramp", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid ramp timing ,,turnoff!\n");
|
||||
} else {
|
||||
drvdata->ramp_off_time = temp;
|
||||
pr_debug("ramp off time --<%d ms> \n", drvdata->ramp_off_time);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,pwm-trans-dim", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid pwm-tarns-dim value!\n");
|
||||
}
|
||||
else {
|
||||
drvdata->pwm_trans_dim = temp;
|
||||
pr_debug("pwm trnasition dimming --<%d ms> \n", drvdata->pwm_trans_dim);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,i2c-trans-dim", &temp);
|
||||
if (rc) {
|
||||
pr_err("Invalid i2c-trans-dim value !\n");
|
||||
} else {
|
||||
drvdata->i2c_trans_dim = temp;
|
||||
pr_debug("i2c transition dimming --<%d ms>\n", drvdata->i2c_trans_dim);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,bl-channel", &bl_channel);
|
||||
if (rc) {
|
||||
pr_err("Invalid channel setup\n");
|
||||
} else {
|
||||
drvdata->channel = bl_channel;
|
||||
pr_debug("bl-channel --<%x> \n", drvdata->channel);
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,ovp-level", &temp);
|
||||
if (!rc) {
|
||||
drvdata->ovp_level = temp;
|
||||
pr_debug("ovp-level --<%d> --temp <%d>\n", drvdata->ovp_level, temp);
|
||||
}else
|
||||
pr_err("Invalid OVP level!\n");
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,switching-frequency", &temp);
|
||||
if (!rc) {
|
||||
drvdata->frequency = temp;
|
||||
pr_debug("switching frequency --<%d> \n", drvdata->frequency);
|
||||
} else {
|
||||
pr_err("Invalid Frequency value!\n");
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,inductor-current", &temp);
|
||||
if (!rc) {
|
||||
drvdata->induct_current = temp;
|
||||
pr_debug("inductor current limit --<%d> \n", drvdata->induct_current);
|
||||
} else
|
||||
pr_err("invalid induct_current limit\n");
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,flash-timeout", &temp);
|
||||
if (!rc) {
|
||||
drvdata->flash_timeout = temp;
|
||||
pr_debug("flash timeout --<%d> \n", drvdata->flash_timeout);
|
||||
} else {
|
||||
pr_err("invalid flash-time value!\n");
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(np, "ktd,flash-current", &temp);
|
||||
if (!rc) {
|
||||
drvdata->flash_current = temp;
|
||||
pr_debug("flash current --<0x%x> \n", drvdata->flash_current);
|
||||
} else {
|
||||
pr_err("invalid flash current value!\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int ktd3136_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ktd3136_data *drvdata;
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
struct backlight_device *bl_dev;
|
||||
struct backlight_properties props;
|
||||
#endif
|
||||
int err = 0;
|
||||
|
||||
pr_info("%s enter!\n", __func__);
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
pr_err("%s : I2C_FUNC_I2C not supported\n", __func__);
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (!client->dev.of_node) {
|
||||
pr_err("%s : no device node\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
drvdata = kzalloc(sizeof(struct ktd3136_data), GFP_KERNEL);
|
||||
if (drvdata == NULL) {
|
||||
pr_err("%s : kzalloc failed\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
drvdata->client = client;
|
||||
drvdata->adapter = client->adapter;
|
||||
#ifdef KTD3136_REG_CONFILCT
|
||||
pr_info("%s: client->addr=0x%x\n", __func__, client->addr);
|
||||
client->addr = KTD3136_REG_REAL;
|
||||
pr_info("%s: confilct, reset client->addr to 0x%x\n", __func__, client->addr);
|
||||
#endif
|
||||
drvdata->addr = client->addr;
|
||||
drvdata->brightness = LED_OFF;
|
||||
drvdata->enable = true;
|
||||
drvdata->led_dev.default_trigger = "bkl-trigger";
|
||||
drvdata->led_dev.name = KTD3136_LED_DEV;
|
||||
drvdata->led_dev.brightness_set = ktd3136_brightness_set;
|
||||
drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
|
||||
ktd3136_get_dt_data(&client->dev, drvdata);
|
||||
i2c_set_clientdata(client, drvdata);
|
||||
err =ktd3136_check_id(drvdata);
|
||||
if (err <0) {
|
||||
pr_err("%s : ID idenfy failed\n", __func__);
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
mutex_init(&drvdata->lock);
|
||||
INIT_WORK(&drvdata->work, ktd3136_work);
|
||||
err = led_classdev_register(&client->dev, &drvdata->led_dev);
|
||||
if (err < 0) {
|
||||
pr_err("%s : Register led class failed\n", __func__);
|
||||
err = -ENODEV;
|
||||
goto err_init;
|
||||
} else {
|
||||
pr_info("%s: Register led class successful\n", __func__);
|
||||
}
|
||||
ktd3136_gpio_init(drvdata);
|
||||
|
||||
#ifdef KERNEL_ABOVE_4_14
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.brightness = MAX_BRIGHTNESS;
|
||||
props.max_brightness = MAX_BRIGHTNESS;
|
||||
bl_dev = backlight_device_register(KTD3136_NAME, &client->dev,
|
||||
drvdata, &ktd3136_bl_ops, &props);
|
||||
#endif
|
||||
ktd3136_backlight_init(drvdata);
|
||||
ktd3136_backlight_enable(drvdata);
|
||||
ktd3136_check_status(drvdata);
|
||||
|
||||
#if defined(CONFIG_FB)
|
||||
drvdata->fb_notif.notifier_call = fb_notifier_callback;
|
||||
err = fb_register_client(&drvdata->fb_notif);
|
||||
if (err)
|
||||
pr_err("%s : Unable to register fb_notifier: %d\n", __func__, err);
|
||||
#endif
|
||||
|
||||
pr_info("%s exit\n", __func__);
|
||||
return 0;
|
||||
|
||||
err_init:
|
||||
pr_info("%s err_init\n", __func__);
|
||||
kfree(drvdata);
|
||||
err_out:
|
||||
pr_info("%s err_out\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ktd3136_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ktd3136_data *drvdata = i2c_get_clientdata(client);
|
||||
|
||||
led_classdev_unregister(&drvdata->led_dev);
|
||||
|
||||
kfree(drvdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ktd3136_id[] = {
|
||||
{KTD3136_NAME, 0},
|
||||
{}
|
||||
};
|
||||
static struct of_device_id match_table[] = {
|
||||
{.compatible = "ktd,ktd3136",}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ktd3136_id);
|
||||
|
||||
static struct i2c_driver ktd3136_i2c_driver = {
|
||||
.probe = ktd3136_probe,
|
||||
.remove = ktd3136_remove,
|
||||
.id_table = ktd3136_id,
|
||||
.driver = {
|
||||
.name = KTD3136_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_i2c_driver(ktd3136_i2c_driver);
|
||||
MODULE_DESCRIPTION("Backlight driver for ktd3136");
|
||||
MODULE_LICENSE("GPL v2");
|
120
drivers/backlight/ktd3136/ktd3136_bl.h
Normal file
120
drivers/backlight/ktd3136/ktd3136_bl.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
#ifndef _KTD3136_REG_H_
|
||||
#define _KTD3136_REG_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
/*********************************************************
|
||||
*
|
||||
* kernel version
|
||||
*
|
||||
********************************************************/
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||
#define KERNEL_ABOVE_4_14
|
||||
#endif
|
||||
|
||||
#undef pr_debug
|
||||
#define pr_debug pr_info
|
||||
|
||||
/*********************************************************
|
||||
*
|
||||
* kernel version
|
||||
*
|
||||
********************************************************/
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||
#define KERNEL_ABOVE_4_14
|
||||
#endif
|
||||
|
||||
#define KTD3136_REG_CONFILCT
|
||||
#ifdef KTD3136_REG_CONFILCT
|
||||
#define KTD3136_REG_REAL 0x36
|
||||
#endif
|
||||
|
||||
#define MAX_BRIGHTNESS (2047)
|
||||
#define BANK_NONE 0x00
|
||||
#define REG_DEV_ID 0x00
|
||||
#define REG_SW_RESET 0x01
|
||||
#define REG_MODE 0x02
|
||||
#define REG_CONTROL 0x03
|
||||
#define REG_RATIO_LSB 0x04
|
||||
#define REG_RATIO_MSB 0x05
|
||||
#define REG_PWM 0x06
|
||||
#define REG_RAMP_ON 0x07
|
||||
#define REG_TRANS_RAMP 0x08
|
||||
#define REG_FLASH_SETTING 0x09
|
||||
#define REG_STATUS 0x0A
|
||||
#define BIT_CH3_FAULT BIT(7)
|
||||
#define BIT_CH2_FAULT BIT(6)
|
||||
#define BIT_CH1_FAULT BIT(5)
|
||||
#define BIT_FLASH_TIMEOUT BIT(4)
|
||||
#define BIT_OVP BIT(3)
|
||||
#define BIT_UVLO BIT(2)
|
||||
#define BIT_OCP BIT(1)
|
||||
#define BIT_THERMAL_SHUTDOWN BIT(0)
|
||||
|
||||
#define RESET_CONDITION_BITS (BIT_CH3_FAULT | BIT_CH2_FAULT | BIT_CH1_FAULT | BIT_OVP | BIT_OCP)
|
||||
|
||||
|
||||
int ktd3136_brightness_table_reg4[256] = {0x01,0x02,0x04,0x04,0x07,0x02,0x00,0x06,0x04,0x02,0x03,0x04,0x05,0x06,0x02,0x06,0x02,
|
||||
0x06,0x02,0x06,0x02,0x06,0x02,0x04,0x05,0x06,0x05,0x03,0x00,0x05,0x02,0x06,0x02,0x06,0x02,0x06,0x02,0x06,0x02,0x06,
|
||||
0x02,0x06,0x02,0x06,0x02,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x05,0x07,
|
||||
0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x00,0x01,0x02,0x03,
|
||||
0x04,0x05,0x06,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x06,0x05,
|
||||
0x04,0x03,0x02,0x01,0x00,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x07,0x05,0x03,0x01,0x07,0x05,0x03,0x01,0x07,0x05,0x03,
|
||||
0x01,0x07,0x05,0x03,0x00,0x05,0x02,0x07,0x04,0x01,0x06,0x03,0x00,0x05,0x02,0x07,0x04,0x01,0x06,0x03,0x00,0x05,0x02,
|
||||
0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x07,
|
||||
0x03,0x07,0x03,0x07,0x03,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x06,0x01,0x04,0x07,0x02,0x05,0x00,0x03,0x06,0x01,
|
||||
0x04,0x07,0x02,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,
|
||||
0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,0x03,0x05,0x07,0x01,
|
||||
0x03,0x05,0x07,0x01,0x03,0x04,0x05,0x06,0x07};
|
||||
|
||||
int ktd3136_brightness_table_reg5[256] = {0x00,0x06,0x0C,0x11,0x15,0x1A,0x1E,0x21,0x25,0x29,0x2C,0x2F,0x32,0x35,0x38,0x3A,0x3D,
|
||||
0x3F,0x42,0x44,0x47,0x49,0x4C,0x4E,0x50,0x52,0x54,0x56,0x58,0x59,0x5B,0x5C,0x5E,0x5F,0x61,0x62,0x64,0x65,0x67,0x68,
|
||||
0x6A,0x6B,0x6D,0x6E,0x70,0x71,0x73,0x74,0x75,0x77,0x78,0x7A,0x7B,0x7C,0x7E,0x7F,0x80,0x82,0x83,0x85,0x86,0x87,0x88,
|
||||
0x8A,0x8B,0x8C,0x8D,0x8F,0x90,0x91,0x92,0x94,0x95,0x96,0x97,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA1,0xA2,0xA3,0xA4,
|
||||
0xA5,0xA6,0xA7,0xA8,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xB9,0xBA,0xBB,
|
||||
0xBC,0xBD,0xBE,0xBF,0xC0,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC7,0xC8,0xC9,0xC9,0xCA,0xCB,0xCC,0xCC,0xCD,0xCE,
|
||||
0xCF,0xCF,0xD0,0xD1,0xD2,0xD2,0xD3,0xD3,0xD4,0xD5,0xD5,0xD6,0xD7,0xD7,0xD8,0xD8,0xD9,0xDA,0xDA,0xDB,0xDC,0xDC,0xDD,
|
||||
0xDD,0xDE,0xDE,0xDF,0xDF,0xE0,0xE0,0xE1,0xE1,0xE2,0xE2,0xE3,0xE3,0xE4,0xE4,0xE5,0xE5,0xE6,0xE6,0xE7,0xE7,0xE8,0xE8,
|
||||
0xE9,0xE9,0xEA,0xEA,0xEB,0xEB,0xEC,0xEC,0xEC,0xED,0xED,0xEE,0xEE,0xEE,0xEF,0xEF,0xEF,0xF0,0xF0,0xF1,0xF1,0xF1,0xF2,
|
||||
0xF2,0xF2,0xF3,0xF3,0xF3,0xF4,0xF4,0xF4,0xF4,0xF5,0xF5,0xF5,0xF5,0xF6,0xF6,0xF6,0xF6,0xF7,0xF7,0xF7,0xF7,0xF8,0xF8,
|
||||
0xF8,0xF8,0xF9,0xF9,0xF9,0xF9,0xFA,0xFA,0xFA,0xFA,0xFB,0xFB,0xFB,0xFB,0xFC,0xFC,0xFC,0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,
|
||||
0xFE,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
||||
|
||||
struct ktd3136_data {
|
||||
struct led_classdev led_dev;
|
||||
struct i2c_client *client;
|
||||
struct i2c_adapter *adapter;
|
||||
unsigned short addr;
|
||||
struct mutex lock;
|
||||
struct work_struct work;
|
||||
enum led_brightness brightness;
|
||||
#ifdef CONFIG_FB
|
||||
struct notifier_block fb_notif;
|
||||
#endif
|
||||
bool enable;
|
||||
u8 pwm_cfg;
|
||||
u8 boost_ctl;
|
||||
u8 full_scale_current;
|
||||
bool brt_code_enable;
|
||||
u16 *brt_code_table;
|
||||
int hwen_gpio;
|
||||
bool pwm_mode;
|
||||
bool using_lsb;
|
||||
unsigned int pwm_period;
|
||||
unsigned int full_scale_led;
|
||||
unsigned int ramp_on_time;
|
||||
unsigned int ramp_off_time;
|
||||
unsigned int pwm_trans_dim;
|
||||
unsigned int i2c_trans_dim;
|
||||
unsigned int channel;
|
||||
unsigned int ovp_level;
|
||||
unsigned int frequency;
|
||||
unsigned int default_brightness;
|
||||
unsigned int max_brightness;
|
||||
unsigned int induct_current;
|
||||
unsigned int flash_current;
|
||||
unsigned int flash_timeout;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
14
drivers/backlight/lm3697/Android.mk
Normal file
14
drivers/backlight/lm3697/Android.mk
Normal file
|
@ -0,0 +1,14 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := leds_lm3697.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true)
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/
|
||||
else
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
endif
|
||||
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
8
drivers/backlight/lm3697/Kbuild
Normal file
8
drivers/backlight/lm3697/Kbuild
Normal file
|
@ -0,0 +1,8 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
|
||||
|
||||
obj-m := leds_lm3697.o
|
||||
leds_lm3697-objs += ti_lm3697.o
|
||||
leds_lm3697-objs += ti_lm3697_backlight.o
|
||||
leds_lm3697-objs += ti_lm3697_backlight_data.o
|
71
drivers/backlight/lm3697/ti-lmu.h
Normal file
71
drivers/backlight/lm3697/ti-lmu.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* TI LMU (Lighting Management Unit) Devices
|
||||
*
|
||||
* Copyright 2017 Texas Instruments
|
||||
*
|
||||
* Author: Milo Kim <milo.kim@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __MFD_TI_LMU_H__
|
||||
#define __MFD_TI_LMU_H__
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* Notifier event */
|
||||
#define LMU_EVENT_MONITOR_DONE 0x01
|
||||
|
||||
enum ti_lmu_id {
|
||||
LM3697,
|
||||
LMU_MAX_ID,
|
||||
};
|
||||
|
||||
enum ti_lmu_max_current {
|
||||
LMU_IMAX_5mA,
|
||||
LMU_IMAX_6mA,
|
||||
LMU_IMAX_7mA = 0x03,
|
||||
LMU_IMAX_8mA,
|
||||
LMU_IMAX_9mA,
|
||||
LMU_IMAX_10mA = 0x07,
|
||||
LMU_IMAX_11mA,
|
||||
LMU_IMAX_12mA,
|
||||
LMU_IMAX_13mA,
|
||||
LMU_IMAX_14mA,
|
||||
LMU_IMAX_15mA = 0x0D,
|
||||
LMU_IMAX_16mA,
|
||||
LMU_IMAX_17mA,
|
||||
LMU_IMAX_18mA,
|
||||
LMU_IMAX_19mA,
|
||||
LMU_IMAX_20mA = 0x13,
|
||||
LMU_IMAX_21mA,
|
||||
LMU_IMAX_22mA,
|
||||
LMU_IMAX_23mA = 0x17,
|
||||
LMU_IMAX_24mA,
|
||||
LMU_IMAX_25mA,
|
||||
LMU_IMAX_26mA,
|
||||
LMU_IMAX_27mA = 0x1C,
|
||||
LMU_IMAX_28mA,
|
||||
LMU_IMAX_29mA,
|
||||
LMU_IMAX_30mA,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_lmu
|
||||
*
|
||||
* @dev: Parent device pointer
|
||||
* @regmap: Used for i2c communcation on accessing registers
|
||||
* @en_gpio: GPIO for HWEN pin [Optional]
|
||||
* @notifier: Notifier for reporting hwmon event
|
||||
*/
|
||||
struct ti_lmu {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
int en_gpio;
|
||||
struct blocking_notifier_head notifier;
|
||||
};
|
||||
#endif
|
183
drivers/backlight/lm3697/ti_lm3697.c
Normal file
183
drivers/backlight/lm3697/ti_lm3697.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* TI LMU (Lighting Management Unit) Core Driver
|
||||
*
|
||||
* Copyright 2017 Texas Instruments
|
||||
*
|
||||
* Author: Milo Kim <milo.kim@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include "ti_lm3697.h"
|
||||
#include "ti_lm3697_regulator.h"
|
||||
#include "ti-lmu.h"
|
||||
|
||||
struct ti_lmu_data {
|
||||
struct mfd_cell *cells;
|
||||
int num_cells;
|
||||
unsigned int max_register;
|
||||
};
|
||||
|
||||
#define LM3697_I2C_ADDR 0x36
|
||||
|
||||
static int ti_lmu_enable_hw(struct ti_lmu *lmu, enum ti_lmu_id id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (gpio_is_valid(lmu->en_gpio)) {
|
||||
ret = devm_gpio_request_one(lmu->dev, lmu->en_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "lmu_hwen");
|
||||
if (ret) {
|
||||
dev_err(lmu->dev, "Can not request enable GPIO: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Delay about 1ms after HW enable pin control */
|
||||
usleep_range(1000, 1500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ti_lmu_disable_hw(struct ti_lmu *lmu)
|
||||
{
|
||||
if (gpio_is_valid(lmu->en_gpio))
|
||||
gpio_set_value(lmu->en_gpio, 0);
|
||||
}
|
||||
|
||||
|
||||
static struct mfd_cell lm3697_devices[] = {
|
||||
{
|
||||
.name = "ti-lmu-backlight",
|
||||
.id = LM3697,
|
||||
.of_compatible = "ti,lm3697-backlight",
|
||||
},
|
||||
/* Monitoring driver for open/short circuit detection */
|
||||
{
|
||||
.name = "ti-lmu-fault-monitor",
|
||||
.id = LM3697,
|
||||
.of_compatible = "ti,lm3697-fault-monitor",
|
||||
},
|
||||
};
|
||||
|
||||
#define TI_LMU_DATA(chip, max_reg) \
|
||||
static const struct ti_lmu_data chip##_data = \
|
||||
{ \
|
||||
.cells = chip##_devices, \
|
||||
.num_cells = ARRAY_SIZE(chip##_devices),\
|
||||
.max_register = max_reg, \
|
||||
} \
|
||||
|
||||
TI_LMU_DATA(lm3697, LM3697_MAX_REG);
|
||||
|
||||
static const struct of_device_id ti_lmu_of_match[] = {
|
||||
{ .compatible = "ti,lm3697", .data = &lm3697_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
|
||||
|
||||
static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &cl->dev;
|
||||
const struct of_device_id *match;
|
||||
const struct ti_lmu_data *data;
|
||||
struct regmap_config regmap_cfg;
|
||||
struct ti_lmu *lmu;
|
||||
int ret;
|
||||
|
||||
if (cl->addr != LM3697_I2C_ADDR)
|
||||
cl->addr = LM3697_I2C_ADDR;
|
||||
|
||||
match = of_match_device(ti_lmu_of_match, dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
/*
|
||||
* Get device specific data from of_match table.
|
||||
* This data is defined by using TI_LMU_DATA() macro.
|
||||
*/
|
||||
data = (struct ti_lmu_data *)match->data;
|
||||
|
||||
lmu = devm_kzalloc(dev, sizeof(*lmu), GFP_KERNEL);
|
||||
if (!lmu)
|
||||
return -ENOMEM;
|
||||
|
||||
lmu->dev = &cl->dev;
|
||||
|
||||
/* Setup regmap */
|
||||
memset(®map_cfg, 0, sizeof(struct regmap_config));
|
||||
regmap_cfg.reg_bits = 8;
|
||||
regmap_cfg.val_bits = 8;
|
||||
regmap_cfg.name = id->name;
|
||||
regmap_cfg.max_register = data->max_register;
|
||||
|
||||
lmu->regmap = devm_regmap_init_i2c(cl, ®map_cfg);
|
||||
if (IS_ERR(lmu->regmap))
|
||||
return PTR_ERR(lmu->regmap);
|
||||
|
||||
/* HW enable pin control and additional power up sequence if required */
|
||||
lmu->en_gpio = of_get_named_gpio(dev->of_node, "enable-gpios", 0);
|
||||
ret = ti_lmu_enable_hw(lmu, id->driver_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Fault circuit(open/short) can be detected by ti-lmu-fault-monitor.
|
||||
* After fault detection is done, some devices should re-initialize
|
||||
* configuration. The notifier enables such kind of handling.
|
||||
*/
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&lmu->notifier);
|
||||
|
||||
i2c_set_clientdata(cl, lmu);
|
||||
|
||||
mfd_add_devices(lmu->dev, 0, data->cells,
|
||||
data->num_cells, NULL, 0, NULL);
|
||||
|
||||
ti_lmu_backlight_device_init();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_lmu_remove(struct i2c_client *cl)
|
||||
{
|
||||
struct ti_lmu *lmu = i2c_get_clientdata(cl);
|
||||
|
||||
ti_lmu_disable_hw(lmu);
|
||||
mfd_remove_devices(lmu->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ti_lmu_ids[] = {
|
||||
{ "lm3697", LM3697 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ti_lmu_ids);
|
||||
|
||||
static struct i2c_driver ti_lmu_driver = {
|
||||
.probe = ti_lmu_probe,
|
||||
.remove = ti_lmu_remove,
|
||||
.driver = {
|
||||
.name = "ti-lmu",
|
||||
.of_match_table = ti_lmu_of_match,
|
||||
},
|
||||
.id_table = ti_lmu_ids,
|
||||
};
|
||||
|
||||
module_i2c_driver(ti_lmu_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TI LMU MFD Core Driver");
|
||||
MODULE_AUTHOR("Milo Kim");
|
||||
MODULE_LICENSE("GPL v2");
|
250
drivers/backlight/lm3697/ti_lm3697.h
Normal file
250
drivers/backlight/lm3697/ti_lm3697.h
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* TI LMU (Lighting Management Unit) Backlight Common Driver
|
||||
*
|
||||
* Copyright 2016 Texas Instruments
|
||||
*
|
||||
* Author: Milo Kim <milo.kim@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __TI_LMU_BACKLIGHT_H__
|
||||
#define __TI_LMU_BACKLIGHT_H__
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/notifier.h>
|
||||
#include "ti_lm3697_regulator.h"
|
||||
#include "ti-lmu.h"
|
||||
/**
|
||||
* LMU backlight register data
|
||||
* value[23:16] | mask[15:8] | address[7:0]
|
||||
*/
|
||||
#define LMU_BL_REG(addr, mask, value) \
|
||||
((value << 16) | (mask << 8) | addr)
|
||||
|
||||
#define LMU_BL_GET_ADDR(x) (x & 0xFF)
|
||||
#define LMU_BL_GET_MASK(x) ((x >> 8) & 0xFF)
|
||||
#define LMU_BL_GET_VAL(x) ((x >> 16) & 0xFF)
|
||||
|
||||
#define LM3697_INIT_RAMP_SELECT \
|
||||
LMU_BL_REG(LM3697_REG_RAMP_CONF, LM3697_RAMP_MASK, LM3697_RAMP_EACH)
|
||||
#define LM3697_CHANNEL_1 \
|
||||
LMU_BL_REG(LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED1_CFG_MASK, \
|
||||
LM3697_HVLED1_CFG_SHIFT)
|
||||
#define LM3697_CHANNEL_2 \
|
||||
LMU_BL_REG(LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED2_CFG_MASK, \
|
||||
LM3697_HVLED2_CFG_SHIFT)
|
||||
#define LM3697_CHANNEL_3 \
|
||||
LMU_BL_REG(LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED3_CFG_MASK, \
|
||||
LM3697_HVLED3_CFG_SHIFT)
|
||||
#define LM3697_MODE_PWM_A \
|
||||
LMU_BL_REG(LM3697_REG_PWM_CFG, LM3697_PWM_A_MASK, LM3697_PWM_A_MASK)
|
||||
#define LM3697_MODE_PWM_B \
|
||||
LMU_BL_REG(LM3697_REG_PWM_CFG, LM3697_PWM_B_MASK, LM3697_PWM_B_MASK)
|
||||
#define LM3697_RAMPUP \
|
||||
LMU_BL_REG(LM3697_REG_BL0_RAMP, LM3697_RAMPUP_MASK, LM3697_RAMPUP_SHIFT)
|
||||
#define LM3697_RAMPDN \
|
||||
LMU_BL_REG(LM3697_REG_BL0_RAMP, LM3697_RAMPDN_MASK, LM3697_RAMPDN_SHIFT)
|
||||
|
||||
#define LM3697_MAX_CHANNELS 3
|
||||
|
||||
#define MAX_BRIGHTNESS_8BIT 255
|
||||
#define MAX_BRIGHTNESS_11BIT 2047
|
||||
|
||||
enum ti_lmu_bl_ctrl_mode {
|
||||
BL_REGISTER_BASED,
|
||||
BL_PWM_BASED,
|
||||
};
|
||||
|
||||
enum ti_lmu_bl_pwm_action {
|
||||
/* Update PWM duty, no brightness register update is required */
|
||||
UPDATE_PWM_ONLY,
|
||||
/* Update not only duty but also brightness register */
|
||||
UPDATE_PWM_AND_BRT_REGISTER,
|
||||
/* Update max value in brightness registers */
|
||||
UPDATE_MAX_BRT,
|
||||
};
|
||||
|
||||
enum ti_lmu_bl_ramp_mode {
|
||||
BL_RAMP_UP,
|
||||
BL_RAMP_DOWN,
|
||||
};
|
||||
|
||||
struct ti_lmu_bl;
|
||||
struct ti_lmu_bl_chip;
|
||||
|
||||
/**
|
||||
* struct ti_lmu_bl_reg
|
||||
*
|
||||
* @init: Device initialization registers
|
||||
* @num_init: Numbers of initialization registers
|
||||
* @channel: Backlight channel configuration registers
|
||||
* @mode: Brightness control mode registers
|
||||
* @ramp: Ramp registers for lighting effect
|
||||
* @ramp_reg_offset: Ramp register offset.
|
||||
* Only used for multiple ramp registers.
|
||||
* @enable: Enable control register address
|
||||
* @enable_offset: Enable control register bit offset
|
||||
* @enable_usec: Delay time for updating enable register.
|
||||
* Unit is microsecond.
|
||||
* @brightness_msb: Brightness MSB(Upper 8 bits) registers.
|
||||
* Concatenated with LSB in 11 bit dimming mode.
|
||||
* In 8 bit dimming, only MSB is used.
|
||||
* @brightness_lsb: Brightness LSB(Lower 3 bits) registers.
|
||||
* Only valid in 11 bit dimming mode.
|
||||
*/
|
||||
struct ti_lmu_bl_reg {
|
||||
u32 *init;
|
||||
int num_init;
|
||||
u32 *channel;
|
||||
u32 *mode;
|
||||
u32 *ramp;
|
||||
int ramp_reg_offset;
|
||||
u8 *enable;
|
||||
u8 enable_offset;
|
||||
unsigned long enable_usec;
|
||||
u8 *brightness_msb;
|
||||
u8 *brightness_lsb;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_lmu_bl_cfg
|
||||
*
|
||||
* @reginfo: Device register configuration
|
||||
* @num_channels: Number of backlight channels
|
||||
* @single_bank_used: [Optional] Set true if one bank controls multiple channels.
|
||||
* Only used for LM36274.
|
||||
* @max_brightness: Max brightness value of backlight device
|
||||
* @pwm_action: How to control brightness registers in PWM mode
|
||||
* @ramp_table: [Optional] Ramp time table for lighting effect.
|
||||
* It's used for searching approximate register index.
|
||||
* @size_ramp: [Optional] Size of ramp table
|
||||
* @fault_monitor_used: [Optional] Set true if the device needs to handle
|
||||
* LMU fault monitor event.
|
||||
*
|
||||
* This structure is used for device specific data configuration.
|
||||
*/
|
||||
struct ti_lmu_bl_cfg {
|
||||
const struct ti_lmu_bl_reg *reginfo;
|
||||
int num_channels;
|
||||
bool single_bank_used;
|
||||
int max_brightness;
|
||||
enum ti_lmu_bl_pwm_action pwm_action;
|
||||
int *ramp_table;
|
||||
int size_ramp;
|
||||
bool fault_monitor_used;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_lmu_bl_chip
|
||||
*
|
||||
* @dev: Parent device pointer
|
||||
* @lmu: LMU structure.
|
||||
* Used for register R/W access and notification.
|
||||
* @cfg: Device configuration data
|
||||
* @lmu_bl: Multiple backlight channels
|
||||
* @num_backlights: Number of backlight channels
|
||||
* @nb: Notifier block for handling LMU fault monitor event
|
||||
*
|
||||
* One backlight chip can have multiple backlight channels, 'ti_lmu_bl'.
|
||||
*/
|
||||
struct ti_lmu_bl_chip {
|
||||
struct device *dev;
|
||||
struct ti_lmu *lmu;
|
||||
const struct ti_lmu_bl_cfg *cfg;
|
||||
struct ti_lmu_bl *lmu_bl;
|
||||
int num_backlights;
|
||||
struct notifier_block nb;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_lmu_bl
|
||||
*
|
||||
* @chip: Pointer to parent backlight device
|
||||
* @bl_dev: Backlight subsystem device structure
|
||||
* @bank_id: Backlight bank ID
|
||||
* @name: Backlight channel name
|
||||
* @mode: Backlight control mode
|
||||
* @led_sources: Backlight output channel configuration.
|
||||
* Bit mask is set on parsing DT.
|
||||
* @default_brightness: [Optional] Initial brightness value
|
||||
* @ramp_up_msec: [Optional] Ramp up time
|
||||
* @ramp_down_msec: [Optional] Ramp down time
|
||||
* @pwm_period: [Optional] PWM period
|
||||
* @pwm: [Optional] PWM subsystem structure
|
||||
*
|
||||
* Each backlight device has its own channel configuration.
|
||||
* For chip control, parent chip data structure is used.
|
||||
*/
|
||||
struct ti_lmu_bl {
|
||||
struct ti_lmu_bl_chip *chip;
|
||||
struct backlight_device *bl_dev;
|
||||
|
||||
int bank_id;
|
||||
const char *name;
|
||||
enum ti_lmu_bl_ctrl_mode mode;
|
||||
unsigned long led_sources;
|
||||
|
||||
unsigned int default_brightness;
|
||||
|
||||
/* Used for lighting effect */
|
||||
unsigned int ramp_up_msec;
|
||||
unsigned int ramp_down_msec;
|
||||
|
||||
/* Only valid in PWM mode */
|
||||
unsigned int pwm_period;
|
||||
|
||||
/* current mode */
|
||||
unsigned int led_current_mode;
|
||||
|
||||
/* Boost OVP */
|
||||
unsigned int led_boost_ovp;
|
||||
/* Boost frequency */
|
||||
unsigned int led_boost_freq;
|
||||
|
||||
/* Map type */
|
||||
unsigned int map_type;
|
||||
|
||||
/* Align boost current to AW chip */
|
||||
unsigned int led_current_align;
|
||||
|
||||
struct pwm_device *pwm;
|
||||
};
|
||||
|
||||
enum backlight_hbm_mode {
|
||||
HBM_MODE_UN_SET,
|
||||
HBM_MODE_DEFAULT = 1,
|
||||
HBM_MODE_LEVEL1, //CURRENT = HBM_MODE_DEFAULT*112.5%
|
||||
HBM_MODE_LEVEL2, //CURRENT = HBM_MODE_DEFAULT*125%
|
||||
HBM_MODE_LEVEL_MAX
|
||||
};
|
||||
|
||||
enum backlight_boost_ovp {
|
||||
BOOST_OVP_16V,
|
||||
BOOST_OVP_24V,
|
||||
BOOST_OVP_32V,
|
||||
BOOST_OVP_40V
|
||||
};
|
||||
|
||||
enum backlight_boost_freq {
|
||||
BOOST_FREQ_500K,
|
||||
BOOST_FREQ_1M
|
||||
};
|
||||
|
||||
enum backlight_map_type {
|
||||
EXPONENTIAL_TYPE,
|
||||
LINEAR_TYPE
|
||||
};
|
||||
|
||||
enum backlight_exp_current_align {
|
||||
ALIGN_NONE,
|
||||
ALIGN_AW99703
|
||||
};
|
||||
|
||||
extern struct ti_lmu_bl_cfg lmu_bl_cfg[LMU_MAX_ID];
|
||||
extern int ti_lmu_backlight_device_init(void);
|
||||
extern void ti_lmu_backlight_exit(void);
|
||||
#endif
|
955
drivers/backlight/lm3697/ti_lm3697_backlight.c
Normal file
955
drivers/backlight/lm3697/ti_lm3697_backlight.c
Normal file
|
@ -0,0 +1,955 @@
|
|||
/*
|
||||
* TI LMU (Lighting Management Unit) Backlight Driver
|
||||
*
|
||||
* Copyright 2016 Texas Instruments
|
||||
*
|
||||
* Author: Milo Kim <milo.kim@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include "ti_lm3697.h"
|
||||
#include "ti_lm3697_regulator.h"
|
||||
#include "ti-lmu.h"
|
||||
|
||||
#define NUM_DUAL_CHANNEL 2
|
||||
#define LMU_BACKLIGHT_DUAL_CHANNEL_USED (BIT(0) | BIT(1))
|
||||
#define LMU_BACKLIGHT_11BIT_LSB_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
#define LMU_BACKLIGHT_11BIT_MSB_SHIFT 3
|
||||
#define DEFAULT_PWM_NAME "lmu-backlight"
|
||||
#define LM3697_NAME "lm3697-bl"
|
||||
|
||||
static struct ti_lmu_bl_chip *bl_chip;
|
||||
|
||||
int translate_value[2048] = {0, 50, 55, 171, 253, 317, 360, 414, 452, 486, 516, 543, 568, 591, 612, 632, 651, 668, 684, 700, 714, 728, 742, 754, 767, 778, 790,\
|
||||
800, 811, 821, 831, 840, 849, 858, 866, 875, 883, 891, 898, 906, 913, 920, 927, 934, 940, 947, 953, 959, 965, 971, 977, 983, 988,\
|
||||
994, 999, 1004, 1009, 1014, 1019, 1024, 1029, 1034, 1038, 1043, 1048, 1052, 1056, 1061, 1065, 1069, 1073, 1077, 1081, 1085,\
|
||||
1089, 1093, 1097, 1101, 1104, 1108, 1111, 1115, 1119, 1122, 1125, 1129, 1132, 1135, 1139, 1142, 1145, 1148, 1151, 1155, 1158,\
|
||||
1161, 1164, 1167, 1170, 1172, 1175, 1178, 1181, 1184, 1187, 1189, 1192, 1195, 1197, 1200, 1203, 1205, 1208, 1210, 1213, 1215,\
|
||||
1218, 1220, 1223, 1225, 1228, 1230, 1232, 1235, 1237, 1239, 1242, 1244, 1246, 1248, 1251, 1253, 1255, 1257, 1259, 1261, 1263,\
|
||||
1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1291, 1293, 1295, 1297, 1299, 1301, 1303, 1305, 1306,\
|
||||
1308, 1310, 1312, 1314, 1315, 1317, 1319, 1321, 1322, 1324, 1326, 1327, 1329, 1331, 1332, 1334, 1336, 1337, 1339, 1341, 1342,\
|
||||
1344, 1345, 1347, 1348, 1350, 1352, 1353, 1355, 1356, 1358, 1359, 1361, 1362, 1364, 1365, 1367, 1368, 1370, 1371, 1372, 1374,\
|
||||
1375, 1377, 1378, 1380, 1381, 1382, 1384, 1385, 1386, 1388, 1389, 1391, 1392, 1393, 1395, 1396, 1397, 1399, 1400, 1401, 1402,\
|
||||
1404, 1405, 1406, 1408, 1409, 1410, 1411, 1413, 1414, 1415, 1416, 1418, 1419, 1420, 1421, 1423, 1424, 1425, 1426, 1427, 1428,\
|
||||
1430, 1431, 1432, 1433, 1434, 1435, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452,\
|
||||
1453, 1454, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474,\
|
||||
1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495,\
|
||||
1496, 1497, 1498, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1508, 1509, 1510, 1511, 1512, 1513, 1514,\
|
||||
1515, 1516, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1528, 1529, 1530, 1531, 1532,\
|
||||
1533, 1533, 1534, 1535, 1536, 1537, 1537, 1538, 1539, 1540, 1541, 1541, 1542, 1543, 1544, 1545, 1545, 1546, 1547, 1548, 1549,\
|
||||
1549, 1550, 1551, 1552, 1552, 1553, 1554, 1555, 1555, 1556, 1557, 1558, 1558, 1559, 1560, 1561, 1561, 1562, 1563, 1564, 1564,\
|
||||
1565, 1566, 1567, 1567, 1568, 1569, 1570, 1570, 1571, 1572, 1572, 1573, 1574, 1575, 1575, 1576, 1577, 1577, 1578, 1579, 1579,\
|
||||
1580, 1581, 1582, 1582, 1583, 1584, 1584, 1585, 1586, 1586, 1587, 1588, 1588, 1589, 1590, 1590, 1591, 1592, 1592, 1593, 1594,\
|
||||
1594, 1595, 1596, 1596, 1597, 1598, 1598, 1599, 1600, 1600, 1601, 1602, 1602, 1603, 1604, 1604, 1605, 1606, 1606, 1607, 1607,\
|
||||
1608, 1609, 1609, 1610, 1611, 1611, 1612, 1612, 1613, 1614, 1614, 1615, 1616, 1616, 1617, 1617, 1618, 1619, 1619, 1620, 1620,\
|
||||
1621, 1622, 1622, 1623, 1623, 1624, 1625, 1625, 1626, 1626, 1627, 1628, 1628, 1629, 1629, 1630, 1631, 1631, 1632, 1632, 1633,\
|
||||
1633, 1634, 1635, 1635, 1636, 1636, 1637, 1637, 1638, 1639, 1639, 1640, 1640, 1641, 1641, 1642, 1643, 1643, 1644, 1644, 1645,\
|
||||
1645, 1646, 1646, 1647, 1648, 1648, 1649, 1649, 1650, 1650, 1651, 1651, 1652, 1652, 1653, 1654, 1654, 1655, 1655, 1656, 1656,\
|
||||
1657, 1657, 1658, 1658, 1659, 1659, 1660, 1660, 1661, 1662, 1662, 1663, 1663, 1664, 1664, 1665, 1665, 1666, 1666, 1667, 1667,\
|
||||
1668, 1668, 1669, 1669, 1670, 1670, 1671, 1671, 1672, 1672, 1673, 1673, 1674, 1674, 1675, 1675, 1676, 1676, 1677, 1677, 1678,\
|
||||
1678, 1679, 1679, 1680, 1680, 1681, 1681, 1682, 1682, 1683, 1683, 1684, 1684, 1685, 1685, 1686, 1686, 1687, 1687, 1688, 1688,\
|
||||
1689, 1689, 1689, 1690, 1690, 1691, 1691, 1692, 1692, 1693, 1693, 1694, 1694, 1695, 1695, 1696, 1696, 1697, 1697, 1697, 1698,\
|
||||
1698, 1699, 1699, 1700, 1700, 1701, 1701, 1702, 1702, 1703, 1703, 1703, 1704, 1704, 1705, 1705, 1706, 1706, 1707, 1707, 1707,\
|
||||
1708, 1708, 1709, 1709, 1710, 1710, 1711, 1711, 1711, 1712, 1712, 1713, 1713, 1714, 1714, 1715, 1715, 1715, 1716, 1716, 1717,\
|
||||
1717, 1718, 1718, 1718, 1719, 1719, 1720, 1720, 1721, 1721, 1721, 1722, 1722, 1723, 1723, 1724, 1724, 1724, 1725, 1725, 1726,\
|
||||
1726, 1726, 1727, 1727, 1728, 1728, 1729, 1729, 1729, 1730, 1730, 1731, 1731, 1731, 1732, 1732, 1733, 1733, 1733, 1734, 1734,\
|
||||
1735, 1735, 1736, 1736, 1736, 1737, 1737, 1738, 1738, 1738, 1739, 1739, 1740, 1740, 1740, 1741, 1741, 1742, 1742, 1742, 1743,\
|
||||
1743, 1744, 1744, 1744, 1745, 1745, 1745, 1746, 1746, 1747, 1747, 1747, 1748, 1748, 1749, 1749, 1749, 1750, 1750, 1751, 1751,\
|
||||
1751, 1752, 1752, 1752, 1753, 1753, 1754, 1754, 1754, 1755, 1755, 1755, 1756, 1756, 1757, 1757, 1757, 1758, 1758, 1758, 1759,\
|
||||
1759, 1760, 1760, 1760, 1761, 1761, 1761, 1762, 1762, 1763, 1763, 1763, 1764, 1764, 1764, 1765, 1765, 1766, 1766, 1766, 1767,\
|
||||
1767, 1767, 1768, 1768, 1768, 1769, 1769, 1769, 1770, 1770, 1771, 1771, 1771, 1772, 1772, 1772, 1773, 1773, 1773, 1774, 1774,\
|
||||
1774, 1775, 1775, 1776, 1776, 1776, 1777, 1777, 1777, 1778, 1778, 1778, 1779, 1779, 1779, 1780, 1780, 1780, 1781, 1781, 1781,\
|
||||
1782, 1782, 1782, 1783, 1783, 1784, 1784, 1784, 1785, 1785, 1785, 1786, 1786, 1786, 1787, 1787, 1787, 1788, 1788, 1788, 1789,\
|
||||
1789, 1789, 1790, 1790, 1790, 1791, 1791, 1791, 1792, 1792, 1792, 1793, 1793, 1793, 1794, 1794, 1794, 1795, 1795, 1795, 1796,\
|
||||
1796, 1796, 1797, 1797, 1797, 1798, 1798, 1798, 1799, 1799, 1799, 1800, 1800, 1800, 1800, 1801, 1801, 1801, 1802, 1802, 1802,\
|
||||
1803, 1803, 1803, 1804, 1804, 1804, 1805, 1805, 1805, 1806, 1806, 1806, 1807, 1807, 1807, 1808, 1808, 1808, 1808, 1809, 1809,\
|
||||
1809, 1810, 1810, 1810, 1811, 1811, 1811, 1812, 1812, 1812, 1813, 1813, 1813, 1813, 1814, 1814, 1814, 1815, 1815, 1815, 1816,\
|
||||
1816, 1816, 1816, 1817, 1817, 1817, 1818, 1818, 1818, 1819, 1819, 1819, 1820, 1820, 1820, 1820, 1821, 1821, 1821, 1822, 1822,\
|
||||
1822, 1823, 1823, 1823, 1823, 1824, 1824, 1824, 1825, 1825, 1825, 1826, 1826, 1826, 1826, 1827, 1827, 1827, 1828, 1828, 1828,\
|
||||
1828, 1829, 1829, 1829, 1830, 1830, 1830, 1831, 1831, 1831, 1831, 1832, 1832, 1832, 1833, 1833, 1833, 1833, 1834, 1834, 1834,\
|
||||
1835, 1835, 1835, 1835, 1836, 1836, 1836, 1837, 1837, 1837, 1837, 1838, 1838, 1838, 1839, 1839, 1839, 1839, 1840, 1840, 1840,\
|
||||
1841, 1841, 1841, 1841, 1842, 1842, 1842, 1842, 1843, 1843, 1843, 1844, 1844, 1844, 1844, 1845, 1845, 1845, 1846, 1846, 1846,\
|
||||
1846, 1847, 1847, 1847, 1847, 1848, 1848, 1848, 1849, 1849, 1849, 1849, 1850, 1850, 1850, 1850, 1851, 1851, 1851, 1852, 1852,\
|
||||
1852, 1852, 1853, 1853, 1853, 1853, 1854, 1854, 1854, 1854, 1855, 1855, 1855, 1856, 1856, 1856, 1856, 1857, 1857, 1857, 1857,\
|
||||
1858, 1858, 1858, 1858, 1859, 1859, 1859, 1860, 1860, 1860, 1860, 1861, 1861, 1861, 1861, 1862, 1862, 1862, 1862, 1863, 1863,\
|
||||
1863, 1863, 1864, 1864, 1864, 1864, 1865, 1865, 1865, 1865, 1866, 1866, 1866, 1867, 1867, 1867, 1867, 1868, 1868, 1868, 1868,\
|
||||
1869, 1869, 1869, 1869, 1870, 1870, 1870, 1870, 1871, 1871, 1871, 1871, 1872, 1872, 1872, 1872, 1873, 1873, 1873, 1873, 1874,\
|
||||
1874, 1874, 1874, 1875, 1875, 1875, 1875, 1876, 1876, 1876, 1876, 1877, 1877, 1877, 1877, 1878, 1878, 1878, 1878, 1879, 1879,\
|
||||
1879, 1879, 1880, 1880, 1880, 1880, 1881, 1881, 1881, 1881, 1882, 1882, 1882, 1882, 1882, 1883, 1883, 1883, 1883, 1884, 1884,\
|
||||
1884, 1884, 1885, 1885, 1885, 1885, 1886, 1886, 1886, 1886, 1887, 1887, 1887, 1887, 1888, 1888, 1888, 1888, 1888, 1889, 1889,\
|
||||
1889, 1889, 1890, 1890, 1890, 1890, 1891, 1891, 1891, 1891, 1892, 1892, 1892, 1892, 1892, 1893, 1893, 1893, 1893, 1894, 1894,\
|
||||
1894, 1894, 1895, 1895, 1895, 1895, 1896, 1896, 1896, 1896, 1896, 1897, 1897, 1897, 1897, 1898, 1898, 1898, 1898, 1899, 1899,\
|
||||
1899, 1899, 1899, 1900, 1900, 1900, 1900, 1901, 1901, 1901, 1901, 1901, 1902, 1902, 1902, 1902, 1903, 1903, 1903, 1903, 1904,\
|
||||
1904, 1904, 1904, 1904, 1905, 1905, 1905, 1905, 1906, 1906, 1906, 1906, 1906, 1907, 1907, 1907, 1907, 1908, 1908, 1908, 1908,\
|
||||
1908, 1909, 1909, 1909, 1909, 1910, 1910, 1910, 1910, 1910, 1911, 1911, 1911, 1911, 1912, 1912, 1912, 1912, 1912, 1913, 1913,\
|
||||
1913, 1913, 1913, 1914, 1914, 1914, 1914, 1915, 1915, 1915, 1915, 1915, 1916, 1916, 1916, 1916, 1917, 1917, 1917, 1917, 1917,\
|
||||
1918, 1918, 1918, 1918, 1918, 1919, 1919, 1919, 1919, 1920, 1920, 1920, 1920, 1920, 1921, 1921, 1921, 1921, 1921, 1922, 1922,\
|
||||
1922, 1922, 1922, 1923, 1923, 1923, 1923, 1924, 1924, 1924, 1924, 1924, 1925, 1925, 1925, 1925, 1925, 1926, 1926, 1926, 1926,\
|
||||
1926, 1927, 1927, 1927, 1927, 1927, 1928, 1928, 1928, 1928, 1929, 1929, 1929, 1929, 1929, 1930, 1930, 1930, 1930, 1930, 1931,\
|
||||
1931, 1931, 1931, 1931, 1932, 1932, 1932, 1932, 1932, 1933, 1933, 1933, 1933, 1933, 1934, 1934, 1934, 1934, 1934, 1935, 1935,\
|
||||
1935, 1935, 1935, 1936, 1936, 1936, 1936, 1936, 1937, 1937, 1937, 1937, 1937, 1938, 1938, 1938, 1938, 1938, 1939, 1939, 1939,\
|
||||
1939, 1939, 1940, 1940, 1940, 1940, 1940, 1941, 1941, 1941, 1941, 1941, 1942, 1942, 1942, 1942, 1942, 1943, 1943, 1943, 1943,\
|
||||
1943, 1944, 1944, 1944, 1944, 1944, 1945, 1945, 1945, 1945, 1945, 1946, 1946, 1946, 1946, 1946, 1947, 1947, 1947, 1947, 1947,\
|
||||
1947, 1948, 1948, 1948, 1948, 1948, 1949, 1949, 1949, 1949, 1949, 1950, 1950, 1950, 1950, 1950, 1951, 1951, 1951, 1951, 1951,\
|
||||
1952, 1952, 1952, 1952, 1952, 1952, 1953, 1953, 1953, 1953, 1953, 1954, 1954, 1954, 1954, 1954, 1955, 1955, 1955, 1955, 1955,\
|
||||
1956, 1956, 1956, 1956, 1956, 1956, 1957, 1957, 1957, 1957, 1957, 1958, 1958, 1958, 1958, 1958, 1958, 1959, 1959, 1959, 1959,\
|
||||
1959, 1960, 1960, 1960, 1960, 1960, 1961, 1961, 1961, 1961, 1961, 1961, 1962, 1962, 1962, 1962, 1962, 1963, 1963, 1963, 1963,\
|
||||
1963, 1963, 1964, 1964, 1964, 1964, 1964, 1965, 1965, 1965, 1965, 1965, 1965, 1966, 1966, 1966, 1966, 1966, 1967, 1967, 1967,\
|
||||
1967, 1967, 1967, 1968, 1968, 1968, 1968, 1968, 1969, 1969, 1969, 1969, 1969, 1969, 1970, 1970, 1970, 1970, 1970, 1971, 1971,\
|
||||
1971, 1971, 1971, 1971, 1972, 1972, 1972, 1972, 1972, 1972, 1973, 1973, 1973, 1973, 1973, 1974, 1974, 1974, 1974, 1974, 1974,\
|
||||
1975, 1975, 1975, 1975, 1975, 1975, 1976, 1976, 1976, 1976, 1976, 1977, 1977, 1977, 1977, 1977, 1977, 1978, 1978, 1978, 1978,\
|
||||
1978, 1978, 1979, 1979, 1979, 1979, 1979, 1979, 1980, 1980, 1980, 1980, 1980, 1980, 1981, 1981, 1981, 1981, 1981, 1982, 1982,\
|
||||
1982, 1982, 1982, 1982, 1983, 1983, 1983, 1983, 1983, 1983, 1984, 1984, 1984, 1984, 1984, 1984, 1985, 1985, 1985, 1985, 1985,\
|
||||
1985, 1986, 1986, 1986, 1986, 1986, 1986, 1987, 1987, 1987, 1987, 1987, 1987, 1988, 1988, 1988, 1988, 1988, 1988, 1989, 1989,\
|
||||
1989, 1989, 1989, 1989, 1990, 1990, 1990, 1990, 1990, 1990, 1991, 1991, 1991, 1991, 1991, 1991, 1992, 1992, 1992, 1992, 1992,\
|
||||
1992, 1993, 1993, 1993, 1993, 1993, 1993, 1994, 1994, 1994, 1994, 1994, 1994, 1995, 1995, 1995, 1995, 1995, 1995, 1996, 1996,\
|
||||
1996, 1996, 1996, 1996, 1997, 1997, 1997, 1997, 1997, 1997, 1998, 1998, 1998, 1998, 1998, 1998, 1999, 1999, 1999, 1999, 1999,\
|
||||
1999, 1999, 2000, 2000, 2000, 2000, 2000, 2000, 2001, 2001, 2001, 2001, 2001, 2001, 2002, 2002, 2002, 2002, 2002, 2002, 2003,\
|
||||
2003, 2003, 2003, 2003, 2003, 2003, 2004, 2004, 2004, 2004, 2004, 2004, 2005, 2005, 2005, 2005, 2005, 2005, 2006, 2006, 2006,\
|
||||
2006, 2006, 2006, 2006, 2007, 2007, 2007, 2007, 2007, 2007, 2008, 2008, 2008, 2008, 2008, 2008, 2009, 2009, 2009, 2009, 2009,\
|
||||
2009, 2009, 2010, 2010, 2010, 2010, 2010, 2010, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2012, 2012, 2012, 2012, 2012, 2012,\
|
||||
2013, 2013, 2013, 2013, 2013, 2013, 2013, 2014, 2014, 2014, 2014, 2014, 2014, 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2016,\
|
||||
2016, 2016, 2016, 2016, 2016, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2018, 2018, 2018, 2018, 2018, 2018, 2019, 2019, 2019,\
|
||||
2019, 2019, 2019, 2019, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2021, 2021, 2021, 2021, 2021, 2021, 2022, 2022, 2022, 2022,\
|
||||
2022, 2022, 2022, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2024, 2024, 2024, 2024, 2024, 2024, 2024, 2025, 2025, 2025, 2025,\
|
||||
2025, 2025, 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2027, 2027, 2027, 2027, 2027, 2027, 2027, 2028, 2028, 2028, 2028, 2028,\
|
||||
2028, 2028, 2029, 2029, 2029, 2029, 2029, 2029, 2029, 2030, 2030, 2030, 2030, 2030, 2030, 2030, 2031, 2031, 2031, 2031, 2031,\
|
||||
2031, 2031, 2032, 2032, 2032, 2032, 2032, 2032, 2032, 2033, 2033, 2033, 2033, 2033, 2033, 2033, 2034, 2034, 2034, 2034, 2034,\
|
||||
2034, 2034, 2035, 2035, 2035, 2035, 2035, 2035, 2035, 2036, 2036, 2036, 2036, 2036, 2036, 2036, 2037, 2037, 2037, 2037, 2037,\
|
||||
2037, 2037, 2038, 2038, 2038, 2038, 2038, 2038, 2038, 2039, 2039, 2039, 2039, 2039, 2039, 2039, 2040, 2040, 2040, 2040};
|
||||
|
||||
static int dump_i2c_reg(struct ti_lmu_bl_chip *chip)
|
||||
{
|
||||
struct regmap *regmap = chip->lmu->regmap;
|
||||
int ret_val = 0;
|
||||
|
||||
regmap_read(regmap, 0x10, &ret_val);
|
||||
pr_err("[bkl] %s read 0x10 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x1A, &ret_val);
|
||||
pr_err("[bkl] %s read 0x1A = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x1C, &ret_val);
|
||||
pr_err("[bkl] %s read 0x1C = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x22, &ret_val);
|
||||
pr_err("[bkl] %s read 0x22 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x23, &ret_val);
|
||||
pr_err("[bkl] %s read 0x23 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x24, &ret_val);
|
||||
pr_err("[bkl] %s read 0x24 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x18, &ret_val);
|
||||
pr_err("[bkl] %s read 0x18 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x16, &ret_val);
|
||||
pr_err("[bkl] %s read 0x16 = 0x%x\n", __func__, ret_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ti_hbm_set(enum backlight_hbm_mode hbm_mode)
|
||||
{
|
||||
struct regmap *regmap = bl_chip->lmu->regmap;
|
||||
int value = 0;
|
||||
|
||||
pr_err("[bkl] %s enter\n", __func__);
|
||||
|
||||
switch (hbm_mode) {
|
||||
case HBM_MODE_DEFAULT:
|
||||
regmap_write(regmap, 0x18, 0x15);//21.8mA
|
||||
pr_err("This is hbm mode 1\n");
|
||||
break;
|
||||
case HBM_MODE_LEVEL1:
|
||||
regmap_write(regmap, 0x18, 0x19);//25mA
|
||||
pr_err("This is hbm mode 2\n");
|
||||
break;
|
||||
case HBM_MODE_LEVEL2:
|
||||
regmap_write(regmap, 0x18, 0x1C);//27.4mA
|
||||
pr_err("This is hbm mode 3\n");
|
||||
break;
|
||||
default:
|
||||
pr_err("This isn't hbm mode\n");
|
||||
break;
|
||||
}
|
||||
|
||||
regmap_read(regmap, 0x18, &value);
|
||||
pr_err("[bkl]%s hbm_mode = %d,regmap value=0x%x\n", __func__, hbm_mode, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_enable(struct ti_lmu_bl *lmu_bl, int enable)
|
||||
{
|
||||
struct ti_lmu_bl_chip *chip = lmu_bl->chip;
|
||||
struct regmap *regmap = chip->lmu->regmap;
|
||||
unsigned long enable_time = chip->cfg->reginfo->enable_usec;
|
||||
u8 *reg = chip->cfg->reginfo->enable;
|
||||
|
||||
if (!reg)
|
||||
return -EINVAL;
|
||||
|
||||
if (enable)
|
||||
return regmap_write(regmap, *reg, 0x02);
|
||||
else
|
||||
return regmap_write(regmap, *reg, 0x00);
|
||||
|
||||
if (enable_time > 0)
|
||||
usleep_range(enable_time, enable_time + 100);
|
||||
}
|
||||
|
||||
static void ti_lmu_backlight_pwm_ctrl(struct ti_lmu_bl *lmu_bl, int brightness,
|
||||
int max_brightness)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
unsigned int duty, period;
|
||||
|
||||
if (!lmu_bl->pwm) {
|
||||
pwm = devm_pwm_get(lmu_bl->chip->dev, DEFAULT_PWM_NAME);
|
||||
if (IS_ERR(pwm)) {
|
||||
dev_err(lmu_bl->chip->dev,
|
||||
"Can not get PWM device, err: %ld\n",
|
||||
PTR_ERR(pwm));
|
||||
return;
|
||||
}
|
||||
|
||||
lmu_bl->pwm = pwm;
|
||||
}
|
||||
|
||||
period = lmu_bl->pwm_period;
|
||||
duty = brightness * period / max_brightness;
|
||||
|
||||
pwm_config(lmu_bl->pwm, duty, period);
|
||||
if (duty)
|
||||
pwm_enable(lmu_bl->pwm);
|
||||
else
|
||||
pwm_disable(lmu_bl->pwm);
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_update_brightness_register(struct ti_lmu_bl *lmu_bl,
|
||||
int brightness)
|
||||
{
|
||||
const struct ti_lmu_bl_cfg *cfg = lmu_bl->chip->cfg;
|
||||
const struct ti_lmu_bl_reg *reginfo = cfg->reginfo;
|
||||
struct regmap *regmap = lmu_bl->chip->lmu->regmap;
|
||||
u8 reg, val;
|
||||
int ret;
|
||||
// int i = 0;
|
||||
|
||||
regmap_write(regmap, 0x13, 0x11);
|
||||
|
||||
if (lmu_bl->mode == BL_PWM_BASED) {
|
||||
switch (cfg->pwm_action) {
|
||||
case UPDATE_PWM_ONLY:
|
||||
/* No register update is required */
|
||||
return 0;
|
||||
case UPDATE_MAX_BRT:
|
||||
/*
|
||||
* PWM can start from any non-zero code and dim down
|
||||
* to zero. So, brightness register should be updated
|
||||
* even in PWM mode.
|
||||
*/
|
||||
if (brightness > 0)
|
||||
brightness = MAX_BRIGHTNESS_11BIT;
|
||||
else
|
||||
brightness = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Brightness register update
|
||||
*
|
||||
* 11 bit dimming: update LSB bits and write MSB byte.
|
||||
* MSB brightness should be shifted.
|
||||
* 8 bit dimming: write MSB byte.
|
||||
*/
|
||||
if (brightness < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!reginfo->brightness_msb)
|
||||
return -EINVAL;
|
||||
|
||||
if (cfg->max_brightness == MAX_BRIGHTNESS_11BIT) {
|
||||
if (!reginfo->brightness_lsb)
|
||||
return -EINVAL;
|
||||
|
||||
if(lmu_bl->map_type == EXPONENTIAL_TYPE && lmu_bl->led_current_align) {
|
||||
if(brightness) {
|
||||
pr_info("[bkl] %s brightness = %d, align = %d\n", __func__,
|
||||
brightness, lmu_bl->led_current_align);
|
||||
brightness = brightness*8383/10000+324;
|
||||
}
|
||||
}
|
||||
|
||||
reg = reginfo->brightness_lsb[lmu_bl->bank_id];
|
||||
ret = regmap_update_bits(regmap, reg,
|
||||
LMU_BACKLIGHT_11BIT_LSB_MASK,
|
||||
brightness);
|
||||
if (ret)
|
||||
return ret;
|
||||
pr_info("[bkl][after]11bit %s brightness = %d\n", __func__, brightness);
|
||||
val = (brightness >> LMU_BACKLIGHT_11BIT_MSB_SHIFT) & 0xFF;
|
||||
} else {
|
||||
val = brightness & 0xFF;
|
||||
pr_err("[bkl]8bit %s val = %d\n", __func__, val);
|
||||
}
|
||||
|
||||
reg = reginfo->brightness_msb[lmu_bl->bank_id];
|
||||
ret = regmap_write(regmap, reg, val);
|
||||
return ret;
|
||||
}
|
||||
static int ti_lmu_backlight_set_brightness(int brightness)
|
||||
{
|
||||
struct ti_lmu_bl *lmu_bl = bl_chip->lmu_bl;
|
||||
int ret;
|
||||
|
||||
if (brightness > 0)
|
||||
ret = ti_lmu_backlight_enable(lmu_bl, 1);
|
||||
else
|
||||
ret = ti_lmu_backlight_enable(lmu_bl, 0);
|
||||
|
||||
if (ret) {
|
||||
pr_err("[bkl] %s enable failed ret %d \n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ti_lmu_backlight_update_brightness_register(lmu_bl, brightness);
|
||||
}
|
||||
|
||||
int lm3697_set_brightness(int brightness)
|
||||
{
|
||||
printk(KERN_INFO "[bkl][before]%s brightness = %d\n", __func__, brightness);
|
||||
|
||||
return ti_lmu_backlight_set_brightness(brightness);
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_get_brightness(struct backlight_device *bl_dev)
|
||||
{
|
||||
return bl_dev->props.brightness;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_update_status(struct backlight_device *bl_dev)
|
||||
{
|
||||
struct ti_lmu_bl *lmu_bl = bl_get_data(bl_dev);
|
||||
int brightness = bl_dev->props.brightness;
|
||||
int ret;
|
||||
|
||||
if (bl_dev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
|
||||
brightness = 0;
|
||||
|
||||
if (brightness > 0)
|
||||
ret = ti_lmu_backlight_enable(lmu_bl, 1);
|
||||
else
|
||||
ret = ti_lmu_backlight_enable(lmu_bl, 0);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (lmu_bl->mode == BL_PWM_BASED)
|
||||
ti_lmu_backlight_pwm_ctrl(lmu_bl, brightness,
|
||||
bl_dev->props.max_brightness);
|
||||
|
||||
return ti_lmu_backlight_update_brightness_register(lmu_bl, brightness);
|
||||
}
|
||||
|
||||
static const struct backlight_ops lmu_backlight_ops = {
|
||||
.options = BL_CORE_SUSPENDRESUME,
|
||||
.update_status = ti_lmu_backlight_update_status,
|
||||
.get_brightness = ti_lmu_backlight_get_brightness,
|
||||
};
|
||||
|
||||
static int ti_lmu_backlight_of_get_ctrl_bank(struct device_node *np,
|
||||
struct ti_lmu_bl *lmu_bl)
|
||||
{
|
||||
const char *name;
|
||||
u32 *sources;
|
||||
int num_channels = lmu_bl->chip->cfg->num_channels;
|
||||
int ret, num_sources;
|
||||
|
||||
sources = devm_kzalloc(lmu_bl->chip->dev, num_channels, GFP_KERNEL);
|
||||
if (!sources)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!of_property_read_string(np, "label", &name))
|
||||
lmu_bl->name = name;
|
||||
else
|
||||
lmu_bl->name = np->name;
|
||||
|
||||
ret = of_property_count_u32_elems(np, "led-sources");
|
||||
if (ret < 0 || ret > num_channels)
|
||||
return -EINVAL;
|
||||
num_sources = ret;
|
||||
ret = of_property_read_u32_array(np, "led-sources", sources,
|
||||
num_sources);
|
||||
if (ret){
|
||||
return ret;
|
||||
}
|
||||
lmu_bl->led_sources = 0;
|
||||
while (num_sources--)
|
||||
set_bit(sources[num_sources], &lmu_bl->led_sources);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ti_lmu_backlight_of_get_light_properties(struct device_node *np,
|
||||
struct ti_lmu_bl *lmu_bl)
|
||||
{
|
||||
of_property_read_u32(np, "default-brightness-level",
|
||||
&lmu_bl->default_brightness);
|
||||
|
||||
of_property_read_u32(np, "ramp-up-msec", &lmu_bl->ramp_up_msec);
|
||||
of_property_read_u32(np, "ramp-down-msec", &lmu_bl->ramp_down_msec);
|
||||
|
||||
if(of_property_read_u32(np, "current-mode", &lmu_bl->led_current_mode)) {
|
||||
lmu_bl->led_current_mode = HBM_MODE_DEFAULT;
|
||||
pr_info("[bkl] %s led_current_mode default %d\n", __func__,
|
||||
lmu_bl->led_current_mode);
|
||||
}
|
||||
|
||||
if(of_property_read_u32(np, "boost-ovp", &lmu_bl->led_boost_ovp)) {
|
||||
lmu_bl->led_boost_ovp = BOOST_OVP_32V;
|
||||
pr_info("[bkl] %s led_boost_ovp default %d\n", __func__,
|
||||
lmu_bl->led_boost_ovp);
|
||||
}
|
||||
|
||||
if(of_property_read_u32(np, "boost-freq", &lmu_bl->led_boost_freq)) {
|
||||
lmu_bl->led_boost_freq = BOOST_FREQ_500K;
|
||||
pr_info("[bkl] %s led_boost_freq default %d\n", __func__,
|
||||
lmu_bl->led_boost_freq);
|
||||
}
|
||||
|
||||
|
||||
if(of_property_read_u32(np, "map-type", &lmu_bl->map_type)) {
|
||||
lmu_bl->map_type = LINEAR_TYPE;
|
||||
pr_info("[bkl] %s map_type default %d\n", __func__,
|
||||
lmu_bl->map_type);
|
||||
}
|
||||
|
||||
if(of_property_read_u32(np, "current-align-type", &lmu_bl->led_current_align)) {
|
||||
lmu_bl->led_current_align = ALIGN_NONE;
|
||||
pr_info("[bkl] %s led_current_align default %d, no align, keep as lm3697 exp mode\n", __func__,
|
||||
lmu_bl->led_current_align);
|
||||
}
|
||||
}
|
||||
|
||||
static void ti_lmu_backlight_of_get_brightness_mode(struct device_node *np,
|
||||
struct ti_lmu_bl *lmu_bl)
|
||||
{
|
||||
of_property_read_u32(np, "pwm-period", &lmu_bl->pwm_period);
|
||||
|
||||
if (lmu_bl->pwm_period > 0)
|
||||
lmu_bl->mode = BL_PWM_BASED;
|
||||
else
|
||||
lmu_bl->mode = BL_REGISTER_BASED;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_of_create(struct ti_lmu_bl_chip *chip,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct ti_lmu_bl *lmu_bl, *each;
|
||||
int ret, num_backlights;
|
||||
int i = 0;
|
||||
|
||||
num_backlights = of_get_child_count(np);
|
||||
if (num_backlights == 0) {
|
||||
dev_err(chip->dev, "No backlight strings\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* One chip can have mulitple backlight strings */
|
||||
lmu_bl = devm_kzalloc(chip->dev, sizeof(*lmu_bl) * num_backlights,
|
||||
GFP_KERNEL);
|
||||
if (!lmu_bl)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Child is mapped to LMU backlight control bank */
|
||||
for_each_child_of_node(np, child) {
|
||||
each = lmu_bl + i;
|
||||
each->bank_id = i;
|
||||
each->chip = chip;
|
||||
|
||||
ret = ti_lmu_backlight_of_get_ctrl_bank(child, each);
|
||||
if (ret) {
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ti_lmu_backlight_of_get_light_properties(child, each);
|
||||
ti_lmu_backlight_of_get_brightness_mode(child, each);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
chip->lmu_bl = lmu_bl;
|
||||
chip->num_backlights = num_backlights;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_update_ctrl_mode(struct ti_lmu_bl *lmu_bl)
|
||||
{
|
||||
struct regmap *regmap = lmu_bl->chip->lmu->regmap;
|
||||
u32 *reg = lmu_bl->chip->cfg->reginfo->mode + lmu_bl->bank_id;
|
||||
u8 val;
|
||||
|
||||
if (!reg)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Update PWM configuration register.
|
||||
* If the mode is register based, then clear the bit.
|
||||
*/
|
||||
if (lmu_bl->mode == BL_PWM_BASED)
|
||||
val = LMU_BL_GET_VAL(*reg);
|
||||
else
|
||||
val = 0;
|
||||
|
||||
return regmap_update_bits(regmap, LMU_BL_GET_ADDR(*reg),
|
||||
LMU_BL_GET_MASK(*reg), val);
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_convert_ramp_to_index(struct ti_lmu_bl *lmu_bl,
|
||||
enum ti_lmu_bl_ramp_mode mode)
|
||||
{
|
||||
const int *ramp_table = lmu_bl->chip->cfg->ramp_table;
|
||||
const int size = lmu_bl->chip->cfg->size_ramp;
|
||||
unsigned int msec;
|
||||
int i;
|
||||
|
||||
if (!ramp_table)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mode) {
|
||||
case BL_RAMP_UP:
|
||||
msec = lmu_bl->ramp_up_msec;
|
||||
break;
|
||||
case BL_RAMP_DOWN:
|
||||
msec = lmu_bl->ramp_down_msec;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (msec <= ramp_table[0])
|
||||
return 0;
|
||||
|
||||
if (msec > ramp_table[size - 1])
|
||||
return size - 1;
|
||||
|
||||
for (i = 1; i < size; i++) {
|
||||
if (msec == ramp_table[i])
|
||||
return i;
|
||||
|
||||
/* Find an approximate index by looking up the table */
|
||||
if (msec > ramp_table[i - 1] && msec < ramp_table[i]) {
|
||||
if (msec - ramp_table[i - 1] < ramp_table[i] - msec)
|
||||
return i - 1;
|
||||
else
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_set_ramp(struct ti_lmu_bl *lmu_bl)
|
||||
{
|
||||
struct regmap *regmap = lmu_bl->chip->lmu->regmap;
|
||||
const struct ti_lmu_bl_reg *reginfo = lmu_bl->chip->cfg->reginfo;
|
||||
int offset = reginfo->ramp_reg_offset;
|
||||
int i, ret, index;
|
||||
u32 reg;
|
||||
|
||||
for (i = BL_RAMP_UP; i <= BL_RAMP_DOWN; i++) {
|
||||
index = ti_lmu_backlight_convert_ramp_to_index(lmu_bl, i);
|
||||
if (index > 0) {
|
||||
if (!reginfo->ramp)
|
||||
break;
|
||||
|
||||
if (lmu_bl->bank_id == 0)
|
||||
reg = reginfo->ramp[i];
|
||||
else
|
||||
reg = reginfo->ramp[i] + offset;
|
||||
|
||||
/*
|
||||
* Note that the result of LMU_BL_GET_VAL() is
|
||||
* shift bit. So updated bit is shifted index value.
|
||||
*/
|
||||
ret = regmap_update_bits(regmap, LMU_BL_GET_ADDR(reg),
|
||||
LMU_BL_GET_MASK(reg),
|
||||
index << LMU_BL_GET_VAL(reg));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_configure(struct ti_lmu_bl *lmu_bl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ti_lmu_backlight_update_ctrl_mode(lmu_bl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ti_lmu_backlight_set_ramp(lmu_bl);
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_init(struct ti_lmu_bl_chip *chip)
|
||||
{
|
||||
struct regmap *regmap = chip->lmu->regmap;
|
||||
unsigned char boost_ctl;
|
||||
unsigned char brightness_cfg;
|
||||
pr_err("[bkl] %s enter\n", __func__);
|
||||
/*
|
||||
* 'init' register data consists of address, mask, value.
|
||||
* Driver can get each data by using LMU_BL_GET_ADDR(),
|
||||
* LMU_BL_GET_MASK(), LMU_BL_GET_VAL().
|
||||
*/
|
||||
|
||||
boost_ctl = (chip->lmu_bl->led_boost_ovp<<1) | chip->lmu_bl->led_boost_freq;
|
||||
brightness_cfg = chip->lmu_bl->map_type;
|
||||
|
||||
regmap_write(regmap, 0x10, 0x07);
|
||||
regmap_write(regmap, 0x12, 0x11);
|
||||
regmap_write(regmap, 0x16, brightness_cfg);
|
||||
regmap_write(regmap, 0x19, 0x07);
|
||||
regmap_write(regmap, 0x18, 0x15);//21.8mA default
|
||||
regmap_write(regmap, 0x1A, boost_ctl);
|
||||
regmap_write(regmap, 0x1C, 0x0E);
|
||||
//regmap_write(regmap, 0x22, 0x07);
|
||||
//regmap_write(regmap, 0x23, 0xFF);
|
||||
regmap_write(regmap, 0x24, 0x02);
|
||||
regmap_write(regmap, 0xB4, 0x03);
|
||||
|
||||
|
||||
pr_err("[bkl] %s finish\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_reload(struct ti_lmu_bl_chip *chip)
|
||||
{
|
||||
struct ti_lmu_bl *each;
|
||||
int i, ret;
|
||||
|
||||
ret = ti_lmu_backlight_init(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < chip->num_backlights; i++) {
|
||||
each = chip->lmu_bl + i;
|
||||
ret = ti_lmu_backlight_configure(each);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
backlight_update_status(each->bl_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_add_device(struct device *dev,
|
||||
struct ti_lmu_bl *lmu_bl)
|
||||
{
|
||||
struct backlight_device *bl_dev;
|
||||
struct backlight_properties props;
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.brightness = lmu_bl->default_brightness;
|
||||
props.max_brightness = lmu_bl->chip->cfg->max_brightness;
|
||||
|
||||
bl_dev = backlight_device_register(LM3697_NAME, dev, lmu_bl,
|
||||
&lmu_backlight_ops, &props);
|
||||
if (IS_ERR(bl_dev))
|
||||
return PTR_ERR(bl_dev);
|
||||
|
||||
lmu_bl->bl_dev = bl_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t i2c_reg_dump_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct regmap *regmap = bl_chip->lmu->regmap;
|
||||
int ret_val = 0;
|
||||
|
||||
regmap_read(regmap, 0x00, &ret_val);
|
||||
pr_err("[bkl] %s read 0x00 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x01, &ret_val);
|
||||
pr_err("[bkl] %s read 0x01 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x10, &ret_val);
|
||||
pr_err("[bkl] %s read 0x10 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x11, &ret_val);
|
||||
pr_err("[bkl] %s read 0x11 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x12, &ret_val);
|
||||
pr_err("[bkl] %s read 0x12 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x13, &ret_val);
|
||||
pr_err("[bkl] %s read 0x13 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x14, &ret_val);
|
||||
pr_err("[bkl] %s read 0x14 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x15, &ret_val);
|
||||
pr_err("[bkl] %s read 0x15 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x16, &ret_val);
|
||||
pr_err("[bkl] %s read 0x16 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x17, &ret_val);
|
||||
pr_err("[bkl] %s read 0x17 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x18, &ret_val);
|
||||
pr_err("[bkl] %s read 0x18 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x19, &ret_val);
|
||||
pr_err("[bkl] %s read 0x19 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x1A, &ret_val);
|
||||
pr_err("[bkl] %s read 0x1A = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x1B, &ret_val);
|
||||
pr_err("[bkl] %s read 0x1B = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x1C, &ret_val);
|
||||
pr_err("[bkl] %s read 0x1C = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x20, &ret_val);
|
||||
pr_err("[bkl] %s read 0x20 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x21, &ret_val);
|
||||
pr_err("[bkl] %s read 0x21 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x22, &ret_val);
|
||||
pr_err("[bkl] %s read 0x22 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x23, &ret_val);
|
||||
pr_err("[bkl] %s read 0x23 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0x24, &ret_val);
|
||||
pr_err("[bkl] %s read 0x24 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0xB0, &ret_val);
|
||||
pr_err("[bkl] %s read 0xB0 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0xB2, &ret_val);
|
||||
pr_err("[bkl] %s read 0xB2 = 0x%x\n", __func__, ret_val);
|
||||
regmap_read(regmap, 0xB4, &ret_val);
|
||||
pr_err("[bkl] %s read 0xB4 = 0x%x\n", __func__, ret_val);
|
||||
|
||||
ret = snprintf(buf, PAGE_SIZE, "reg dump done \n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEVICE_ATTR(i2c_reg_dump, S_IRUGO, i2c_reg_dump_show, NULL);
|
||||
|
||||
static int ti_lm3697_read_chipid(struct ti_lmu_bl_chip *chip)
|
||||
{
|
||||
int ret_val = 0;
|
||||
unsigned char cnt = 0;
|
||||
struct regmap *regmap = chip->lmu->regmap;
|
||||
|
||||
while (cnt < 5)
|
||||
{
|
||||
regmap_read(regmap, 0x00, &ret_val);
|
||||
switch (ret_val)
|
||||
{
|
||||
case 0x01:
|
||||
pr_info("%s ti_lm3697 detected\n",__func__);
|
||||
return 0;
|
||||
default:
|
||||
pr_info("%s unsupported device revision (0x%x)\n",
|
||||
__func__, ret_val);
|
||||
break;
|
||||
}
|
||||
cnt++;
|
||||
msleep(2);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
static struct ti_lmu_bl_chip *
|
||||
ti_lmu_backlight_register(struct device *dev, struct ti_lmu *lmu,
|
||||
const struct ti_lmu_bl_cfg *cfg)
|
||||
{
|
||||
struct ti_lmu_bl_chip *chip;
|
||||
struct ti_lmu_bl *each;
|
||||
int i, ret;
|
||||
|
||||
pr_debug("[bkl] %s enter\n", __func__);
|
||||
|
||||
if (!cfg) {
|
||||
dev_err(dev, "Operation is not configured\n");
|
||||
goto err_ein;
|
||||
}
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), 0);
|
||||
if (!chip)
|
||||
goto err_eno;
|
||||
|
||||
chip->dev = dev;
|
||||
chip->lmu = lmu;
|
||||
chip->cfg = cfg;
|
||||
|
||||
ret = ti_lmu_backlight_of_create(chip, dev->of_node);
|
||||
if (ret){
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
ret = ti_lm3697_read_chipid(chip);
|
||||
if (ret < 0)
|
||||
{
|
||||
pr_err("%s : ID idenfy failed\n", __func__);
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
for (i = 0; i < chip->num_backlights; i++) {
|
||||
each = chip->lmu_bl + i;
|
||||
ret = ti_lmu_backlight_configure(each);
|
||||
if (ret) {
|
||||
dev_err(dev, "[bkl] Backlight config err: %d\n", ret);
|
||||
goto err_init;
|
||||
}
|
||||
ret = ti_lmu_backlight_add_device(dev, each);
|
||||
if (ret) {
|
||||
dev_err(dev, "[bkl] Backlight device err: %d\n", ret);
|
||||
goto err_init;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ti_lmu_backlight_init(chip);
|
||||
if (ret) {
|
||||
dev_err(dev, "Backlight init err: %d\n", ret);
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
bl_chip = chip;
|
||||
|
||||
ti_hbm_set(chip->lmu_bl->led_current_mode);
|
||||
|
||||
dump_i2c_reg(chip);
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_i2c_reg_dump);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to create dev_attr_i2c_reg_dump\n");
|
||||
}
|
||||
|
||||
pr_err("[bkl] %s finish\n", __func__);
|
||||
|
||||
return chip;
|
||||
|
||||
err_init:
|
||||
if(chip->lmu_bl)
|
||||
devm_kfree(dev, chip->lmu_bl);
|
||||
if(chip)
|
||||
devm_kfree(dev, chip);
|
||||
err_ein:
|
||||
gpio_free(lmu->en_gpio);
|
||||
return ERR_PTR(-EINVAL);
|
||||
err_eno:
|
||||
gpio_free(lmu->en_gpio);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static void ti_lmu_backlight_unregister(struct ti_lmu_bl_chip *chip)
|
||||
{
|
||||
struct ti_lmu_bl *each;
|
||||
int i;
|
||||
|
||||
/* Turn off the brightness */
|
||||
for (i = 0; i < chip->num_backlights; i++) {
|
||||
each = chip->lmu_bl + i;
|
||||
each->bl_dev->props.brightness = 0;
|
||||
backlight_update_status(each->bl_dev);
|
||||
backlight_device_unregister(each->bl_dev);
|
||||
}
|
||||
device_remove_file(chip->dev, &dev_attr_i2c_reg_dump);
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_monitor_notifier(struct notifier_block *nb,
|
||||
unsigned long action, void *unused)
|
||||
{
|
||||
struct ti_lmu_bl_chip *chip = container_of(nb, struct ti_lmu_bl_chip,
|
||||
nb);
|
||||
|
||||
if (action == LMU_EVENT_MONITOR_DONE) {
|
||||
if (ti_lmu_backlight_reload(chip))
|
||||
return NOTIFY_STOP;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ti_lmu *lmu = dev_get_drvdata(dev->parent);
|
||||
struct ti_lmu_bl_chip *chip;
|
||||
int ret;
|
||||
|
||||
pr_err("[bkl] %s enter\n", __func__);
|
||||
|
||||
|
||||
chip = ti_lmu_backlight_register(dev, lmu, &lmu_bl_cfg[pdev->id]);
|
||||
if (IS_ERR(chip)) {
|
||||
pr_err("[bkl] %s error bkl register\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
/*
|
||||
* Notifier callback is required because backlight device needs
|
||||
* reconfiguration after fault detection procedure is done by
|
||||
* ti-lmu-fault-monitor driver.
|
||||
*/
|
||||
if (chip->cfg->fault_monitor_used) {
|
||||
chip->nb.notifier_call = ti_lmu_backlight_monitor_notifier;
|
||||
ret = blocking_notifier_chain_register(&chip->lmu->notifier,
|
||||
&chip->nb);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
pr_err("[bkl] %s finish\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_lmu_backlight_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ti_lmu_bl_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
if (chip->cfg->fault_monitor_used)
|
||||
blocking_notifier_chain_unregister(&chip->lmu->notifier,
|
||||
&chip->nb);
|
||||
|
||||
ti_lmu_backlight_unregister(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ti_lmu_backlight_driver = {
|
||||
.probe = ti_lmu_backlight_probe,
|
||||
.remove = ti_lmu_backlight_remove,
|
||||
.driver = {
|
||||
.name = "ti-lmu-backlight",
|
||||
},
|
||||
};
|
||||
|
||||
int ti_lmu_backlight_device_init(void)
|
||||
{
|
||||
return platform_driver_register(&ti_lmu_backlight_driver);
|
||||
}
|
||||
EXPORT_SYMBOL(ti_lmu_backlight_device_init);
|
||||
void ti_lmu_backlight_exit(void)
|
||||
{
|
||||
return platform_driver_unregister(&ti_lmu_backlight_driver);
|
||||
}
|
||||
EXPORT_SYMBOL(ti_lmu_backlight_exit);
|
||||
// module_platform_driver(ti_lmu_backlight_driver)
|
||||
|
||||
MODULE_DESCRIPTION("TI LMU Backlight Driver");
|
||||
MODULE_AUTHOR("Milo Kim");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:ti-lmu-backlight");
|
82
drivers/backlight/lm3697/ti_lm3697_backlight_data.c
Normal file
82
drivers/backlight/lm3697/ti_lm3697_backlight_data.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* TI LMU (Lighting Management Unit) Backlight Device Data
|
||||
*
|
||||
* Copyright 2016 Texas Instruments
|
||||
*
|
||||
* Author: Milo Kim <milo.kim@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include "ti_lm3697.h"
|
||||
#include "ti_lm3697_regulator.h"
|
||||
#include "ti-lmu.h"
|
||||
|
||||
/* LM3697 */
|
||||
static u32 lm3697_init_regs[] = {
|
||||
//LM3697_INIT_RAMP_SELECT,
|
||||
LM3697_REG_HVLED_OUTPUT_CFG,
|
||||
LM3697_REG_BOOST_CFG,
|
||||
LM3697_REG_PWM_CFG,
|
||||
LM3697_REG_BRT_B_LSB,
|
||||
LM3697_REG_BRT_B_MSB,
|
||||
LM3697_REG_ENABLE,
|
||||
};
|
||||
|
||||
static u32 lm3697_channel_regs[] = {
|
||||
LM3697_CHANNEL_1,
|
||||
LM3697_CHANNEL_2,
|
||||
LM3697_CHANNEL_3,
|
||||
};
|
||||
|
||||
static u32 lm3697_mode_regs[] = {
|
||||
LM3697_MODE_PWM_B,
|
||||
};
|
||||
|
||||
static u32 lm3697_ramp_regs[] = {
|
||||
LM3697_RAMPUP,
|
||||
LM3697_RAMPDN,
|
||||
};
|
||||
|
||||
static u8 lm3697_enable_reg = LM3697_REG_ENABLE;
|
||||
|
||||
static u8 lm3697_brightness_msb_regs[] = {
|
||||
LM3697_REG_BRT_B_MSB,
|
||||
};
|
||||
|
||||
static u8 lm3697_brightness_lsb_regs[] = {
|
||||
LM3697_REG_BRT_B_LSB,
|
||||
};
|
||||
|
||||
static const struct ti_lmu_bl_reg lm3697_reg_info = {
|
||||
.init = lm3697_init_regs,
|
||||
.num_init = ARRAY_SIZE(lm3697_init_regs),
|
||||
.channel = lm3697_channel_regs,
|
||||
.mode = lm3697_mode_regs,
|
||||
.ramp = lm3697_ramp_regs,
|
||||
.ramp_reg_offset = 1, /* For LM3697_REG_BL1_RAMPUP/DN */
|
||||
.enable = &lm3697_enable_reg,
|
||||
.brightness_msb = lm3697_brightness_msb_regs,
|
||||
.brightness_lsb = lm3697_brightness_lsb_regs,
|
||||
};
|
||||
|
||||
static int common_ramp_table[] = {
|
||||
2, 250, 500, 1000, 2000, 4000, 8000, 16000,
|
||||
};
|
||||
|
||||
struct ti_lmu_bl_cfg lmu_bl_cfg[LMU_MAX_ID] = {
|
||||
{
|
||||
.reginfo = &lm3697_reg_info,
|
||||
.num_channels = LM3697_MAX_CHANNELS,
|
||||
.max_brightness = MAX_BRIGHTNESS_11BIT,
|
||||
.pwm_action = UPDATE_PWM_AND_BRT_REGISTER,
|
||||
.ramp_table = common_ramp_table,
|
||||
.size_ramp = ARRAY_SIZE(common_ramp_table),
|
||||
.fault_monitor_used = true,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(lmu_bl_cfg);
|
63
drivers/backlight/lm3697/ti_lm3697_regulator.h
Normal file
63
drivers/backlight/lm3697/ti_lm3697_regulator.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* TI LMU (Lighting Management Unit) Device Register Map
|
||||
*
|
||||
* Copyright 2017 Texas Instruments
|
||||
*
|
||||
* Author: Milo Kim <milo.kim@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __MFD_TI_LMU_REGISTER_H__
|
||||
#define __MFD_TI_LMU_REGISTER_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* LM3697 */
|
||||
#define LM3697_REG_HVLED_OUTPUT_CFG 0x10
|
||||
#define LM3697_HVLED1_CFG_MASK BIT(0)
|
||||
#define LM3697_HVLED2_CFG_MASK BIT(1)
|
||||
#define LM3697_HVLED3_CFG_MASK BIT(2)
|
||||
#define LM3697_HVLED1_CFG_SHIFT 0
|
||||
#define LM3697_HVLED2_CFG_SHIFT 1
|
||||
#define LM3697_HVLED3_CFG_SHIFT 2
|
||||
|
||||
#define LM3697_REG_BL0_RAMP 0x11
|
||||
#define LM3697_REG_BL1_RAMP 0x12
|
||||
#define LM3697_RAMPUP_MASK 0xF0
|
||||
#define LM3697_RAMPUP_SHIFT 4
|
||||
#define LM3697_RAMPDN_MASK 0x0F
|
||||
#define LM3697_RAMPDN_SHIFT 0
|
||||
|
||||
#define LM3697_REG_RAMP_CONF 0x14
|
||||
#define LM3697_RAMP_MASK 0x0F
|
||||
#define LM3697_RAMP_EACH 0x05
|
||||
|
||||
#define LM3697_REG_BOOST_CFG 0x1A
|
||||
|
||||
#define LM3697_REG_PWM_CFG 0x1C
|
||||
#define LM3697_PWM_A_MASK BIT(0)
|
||||
#define LM3697_PWM_B_MASK BIT(1)
|
||||
|
||||
#define LM3697_REG_IMAX_A 0x17
|
||||
#define LM3697_REG_IMAX_B 0x18
|
||||
|
||||
#define LM3697_REG_FEEDBACK_ENABLE 0x19
|
||||
|
||||
#define LM3697_REG_BRT_A_LSB 0x20
|
||||
#define LM3697_REG_BRT_A_MSB 0x21
|
||||
#define LM3697_REG_BRT_B_LSB 0x22
|
||||
#define LM3697_REG_BRT_B_MSB 0x23
|
||||
|
||||
#define LM3697_REG_ENABLE 0x24
|
||||
|
||||
#define LM3697_REG_OPEN_FAULT_STATUS 0xB0
|
||||
|
||||
#define LM3697_REG_SHORT_FAULT_STATUS 0xB2
|
||||
|
||||
#define LM3697_REG_MONITOR_ENABLE 0xB4
|
||||
|
||||
#define LM3697_MAX_REG 0xB4
|
||||
#endif
|
8
drivers/backlight/sm5350/Android.mk
Normal file
8
drivers/backlight/sm5350/Android.mk
Normal file
|
@ -0,0 +1,8 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := sm5350_bl.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
5
drivers/backlight/sm5350/Kbuild
Normal file
5
drivers/backlight/sm5350/Kbuild
Normal file
|
@ -0,0 +1,5 @@
|
|||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
|
||||
|
||||
obj-m += sm5350_bl.o
|
||||
|
523
drivers/backlight/sm5350/sm5350_bl.c
Normal file
523
drivers/backlight/sm5350/sm5350_bl.c
Normal file
|
@ -0,0 +1,523 @@
|
|||
/*
|
||||
* SM5350 BL Driver
|
||||
*
|
||||
* SiliconMitus SM5350 Backlight driver chip
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/backlight.h>
|
||||
|
||||
#define SM5350_NAME "sm5350-bl"
|
||||
|
||||
#define MAX_BRIGHTNESS (2047)
|
||||
#define BANK_NONE 0x00
|
||||
#define BANK_A 0x01
|
||||
#define BANK_B 0x02
|
||||
|
||||
#define SM5350_HVLED_CURR_SINK_OUT_CFG 0x07
|
||||
#define SM5350_BRIGHTNESS_CFG 0x01
|
||||
|
||||
#define SM5350_REVISION_REG 0x00
|
||||
#define SM5350_SW_RESET_REG 0x01
|
||||
#define SM5350_HVLED_CURR_SINK_OUT_CFG_REG 0x10
|
||||
#define SM5350_CTL_A_RAMP_TIME_REG 0x11
|
||||
#define SM5350_CTL_B_RAMP_TIME_REG 0x12
|
||||
#define SM5350_CTL_RUNTIME_RAMP_TIME_REG 0x13
|
||||
#define SM5350_CTL_RUNTIME_RAMP_CFG_REG 0x14
|
||||
#define SM5350_BRIGHTNESS_CFG_REG 0x16
|
||||
#define SM5350_CTL_A_FULL_SCALE_CURR_REG 0x17
|
||||
#define SM5350_CTL_B_FULL_SCALE_CURR_REG 0x18
|
||||
#define SM5350_HVLED_CURR_SINK_FEEDBACK_REG 0x19
|
||||
#define SM5350_BOOST_CTL_REG 0x1A
|
||||
#define SM5350_AUTO_FREQ_THRESHOLD_REG 0x1B
|
||||
#define SM5350_PWM_CFG_REG 0x1C
|
||||
#define SM5350_CTL_A_BRIGHTNESS_LSB_REG 0x20
|
||||
#define SM5350_CTL_A_BRIGHTNESS_MSB_REG 0x21
|
||||
#define SM5350_CTL_B_BRIGHTNESS_LSB_REG 0x22
|
||||
#define SM5350_CTL_B_BRIGHTNESS_MSB_REG 0x23
|
||||
#define SM5350_CTL_B_BANK_EN_REG 0x24
|
||||
#define SM5350_HVLED_OPEN_FAULTS_REG 0xB0
|
||||
#define SM5350_HVLED_SHORT_FAULTS_REG 0xB2
|
||||
#define SM5350_LED_FAULT_ENABLES_REG 0xB4
|
||||
|
||||
enum backlight_exp_current_align {
|
||||
ALIGN_NONE,
|
||||
ALIGN_AW99703
|
||||
};
|
||||
|
||||
struct sm5350_data {
|
||||
struct i2c_client *client;
|
||||
struct i2c_adapter *adapter;
|
||||
unsigned short addr;
|
||||
struct work_struct work;
|
||||
bool enable;
|
||||
bool bank_A;
|
||||
bool bank_B;
|
||||
u8 ctl_bank_en;
|
||||
u8 pwm_cfg;
|
||||
u8 boost_ctl;
|
||||
u8 full_scale_current;
|
||||
u8 map_mode;
|
||||
unsigned int led_current_align; /* Align boost current to AW chip */
|
||||
unsigned int default_brightness;
|
||||
bool brt_code_enable;
|
||||
u16 *brt_code_table;
|
||||
int en_gpio;
|
||||
struct backlight_device *bl_dev;
|
||||
};
|
||||
|
||||
struct sm5350_data *g_sm5350_data;
|
||||
|
||||
static int platform_read_i2c_block(struct i2c_client *client, char *writebuf,
|
||||
int writelen, char *readbuf, int readlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (writelen > 0) {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 2);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: i2c read error.\n",
|
||||
__func__);
|
||||
} else {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s:i2c read error.\n", __func__);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm5350_read_reg(struct i2c_client *client, u8 addr, u8 *val)
|
||||
{
|
||||
return platform_read_i2c_block(client, &addr, 1, val, 1);
|
||||
}
|
||||
|
||||
static int platform_write_i2c_block(struct i2c_client *client, char *writebuf, int writelen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: i2c write error.\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sm5350_write_reg(struct i2c_client *client, u8 addr, const u8 val)
|
||||
{
|
||||
u8 buf[2] = {0};
|
||||
|
||||
buf[0] = addr;
|
||||
buf[1] = val;
|
||||
return platform_write_i2c_block(client, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int sm5350_init_registers(struct sm5350_data *drvdata)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
sm5350_write_reg(drvdata->client, SM5350_BOOST_CTL_REG, drvdata->boost_ctl);
|
||||
sm5350_write_reg(drvdata->client, SM5350_PWM_CFG_REG, drvdata->pwm_cfg);
|
||||
sm5350_write_reg(drvdata->client, SM5350_CTL_B_BANK_EN_REG, drvdata->ctl_bank_en);
|
||||
sm5350_write_reg(drvdata->client, SM5350_BRIGHTNESS_CFG_REG, drvdata->map_mode);
|
||||
sm5350_write_reg(drvdata->client, SM5350_HVLED_CURR_SINK_OUT_CFG_REG, SM5350_HVLED_CURR_SINK_OUT_CFG);
|
||||
sm5350_write_reg(drvdata->client, SM5350_CTL_B_FULL_SCALE_CURR_REG, drvdata->full_scale_current);
|
||||
|
||||
drvdata->enable = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sm5350_bl_get_brightness(struct backlight_device *bl_dev)
|
||||
{
|
||||
return bl_dev->props.brightness;
|
||||
}
|
||||
|
||||
int sm5350_set_brightness(struct sm5350_data *drvdata, int brt_val)
|
||||
{
|
||||
u8 brt_LSB = 0;
|
||||
u8 brt_MSB = 0;
|
||||
int index = 0, remainder;
|
||||
int code, code1, code2;
|
||||
printk("%s backlight_val = %d\n",__func__, brt_val);
|
||||
|
||||
if ((drvdata->map_mode == 0) && (drvdata->led_current_align == ALIGN_AW99703))
|
||||
brt_val = brt_val*8383/10000+324;
|
||||
|
||||
if (drvdata->brt_code_enable) {
|
||||
index = brt_val / 10;
|
||||
remainder = brt_val % 10;
|
||||
|
||||
code1 = drvdata->brt_code_table[index];
|
||||
code2 = drvdata->brt_code_table[index+1];
|
||||
|
||||
code = (code2 - code1) * remainder / 10 + code1;
|
||||
|
||||
brt_LSB = code % 0x7;
|
||||
brt_MSB = (code >> 3) & 0xFF;
|
||||
printk("brt_LSB_1 %x, brt_MSB_1 %x\n", brt_LSB, brt_MSB);
|
||||
} else {
|
||||
brt_LSB = brt_val & 0x7;
|
||||
brt_MSB = (brt_val >> 3) & 0xFF;
|
||||
}
|
||||
printk("brt_LSB %x, brt_MSB %x\n", brt_LSB, brt_MSB);
|
||||
|
||||
if (drvdata->enable == false)
|
||||
sm5350_init_registers(drvdata);
|
||||
|
||||
if (drvdata->bank_B) {
|
||||
sm5350_write_reg(drvdata->client, SM5350_CTL_B_BRIGHTNESS_LSB_REG, brt_LSB);
|
||||
sm5350_write_reg(drvdata->client, SM5350_CTL_B_BRIGHTNESS_MSB_REG, brt_MSB);
|
||||
}
|
||||
|
||||
if (brt_val == 0)
|
||||
drvdata->enable = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sm5350_bl_update_status(struct backlight_device *bl_dev)
|
||||
{
|
||||
struct sm5350_data *drvdata = bl_get_data(bl_dev);
|
||||
int brt;
|
||||
|
||||
if (bl_dev->props.state & BL_CORE_SUSPENDED)
|
||||
bl_dev->props.brightness = 0;
|
||||
|
||||
brt = bl_dev->props.brightness;
|
||||
/*
|
||||
* Brightness register should always be written
|
||||
* not only register based mode but also in PWM mode.
|
||||
*/
|
||||
return sm5350_set_brightness(drvdata, brt);
|
||||
}
|
||||
|
||||
static const struct backlight_ops sm5350_bl_ops = {
|
||||
.update_status = sm5350_bl_update_status,
|
||||
.get_brightness = sm5350_bl_get_brightness,
|
||||
};
|
||||
|
||||
static void dump_sm5350_regs(struct sm5350_data *drvdata)
|
||||
{
|
||||
u8 brt_LSB = 0;
|
||||
u8 brt_MSB = 0;
|
||||
u8 boost_ctl, pwm_cfg, ctl_bank_en, full_scale_current, revision;
|
||||
|
||||
sm5350_read_reg(drvdata->client, SM5350_BOOST_CTL_REG, &boost_ctl);
|
||||
sm5350_read_reg(drvdata->client, SM5350_PWM_CFG_REG, &pwm_cfg);
|
||||
sm5350_read_reg(drvdata->client, SM5350_CTL_B_BANK_EN_REG, &ctl_bank_en);
|
||||
sm5350_read_reg(drvdata->client, SM5350_CTL_A_FULL_SCALE_CURR_REG, &full_scale_current);
|
||||
sm5350_read_reg(drvdata->client, SM5350_CTL_B_BRIGHTNESS_LSB_REG, &brt_LSB);
|
||||
sm5350_read_reg(drvdata->client, SM5350_CTL_B_BRIGHTNESS_MSB_REG, &brt_MSB);
|
||||
sm5350_read_reg(drvdata->client, SM5350_REVISION_REG, &revision);
|
||||
|
||||
pr_err(">>-- boost_ctl(0x%x), pwm_cfg(0x%x), ctl_bank_en(0x%x), full_scale_current(0x%x), brt_LSB(0x%x), brt_MSB(0x%x), revision(0x%x).\n",
|
||||
boost_ctl, pwm_cfg, ctl_bank_en, full_scale_current, brt_LSB, brt_MSB, revision);
|
||||
}
|
||||
|
||||
static int sm5350_get_dt_data(struct device *dev, struct sm5350_data *drvdata)
|
||||
{
|
||||
int rc;
|
||||
u32 tmp;
|
||||
struct device_node *of_node = NULL;
|
||||
int len;
|
||||
const char *data;
|
||||
u32 *buf;
|
||||
int i = 0;
|
||||
|
||||
of_node = dev->of_node;
|
||||
|
||||
drvdata->en_gpio = of_get_named_gpio(of_node, "hwen-gpio", 0);
|
||||
if (drvdata->en_gpio < 0) {
|
||||
pr_err("%s,dt not get en_gpio, en_gpio = %d\n", __func__, drvdata->en_gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = of_property_read_u32(of_node, "boost-ctl", &tmp);
|
||||
if (rc) {
|
||||
pr_err("%s:%d, dt not specified\n",
|
||||
__func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
drvdata->boost_ctl = (!rc ? tmp : 0);
|
||||
pr_debug("%s : boost_ctl=0x%x\n",__func__, drvdata->boost_ctl);
|
||||
|
||||
rc = of_property_read_u32(of_node, "map-mode", &tmp);
|
||||
drvdata->map_mode= (!rc ? tmp : 1); /* 1: linear, 0: expo, linear as default*/
|
||||
pr_debug("%s : map_mode=0x%x\n",__func__, drvdata->map_mode);
|
||||
|
||||
if (of_property_read_u32(of_node, "current-align-type", &drvdata->led_current_align))
|
||||
drvdata->led_current_align = ALIGN_NONE;
|
||||
pr_debug("%s : led_current_align=0x%x\n",__func__, drvdata->led_current_align);
|
||||
|
||||
rc = of_property_read_u32(of_node, "sm5350,default-brightness", &tmp);
|
||||
drvdata->default_brightness= (!rc ? tmp : MAX_BRIGHTNESS);
|
||||
pr_debug("%s : default_brightness=0x%x\n",__func__, drvdata->default_brightness);
|
||||
|
||||
rc = of_property_read_u32(of_node, "pwm-cfg", &tmp);
|
||||
if (rc) {
|
||||
pr_err("%s:%d, dt not specified\n",
|
||||
__func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
drvdata->pwm_cfg = (!rc ? tmp : 0);
|
||||
pr_debug("%s : pwm_cfg=0x%x\n",__func__, drvdata->pwm_cfg);
|
||||
|
||||
rc = of_property_read_u32(of_node, "ctl-bank-en", &tmp);
|
||||
if (rc) {
|
||||
pr_err("%s:%d, dt not specified\n",
|
||||
__func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
drvdata->ctl_bank_en = (!rc ? tmp : 0);
|
||||
pr_debug("%s : ctl_bank_en=0x%x\n",__func__, drvdata->ctl_bank_en);
|
||||
|
||||
if (drvdata->ctl_bank_en & 0x01)
|
||||
drvdata->bank_A = true;
|
||||
if (drvdata->ctl_bank_en & 0x02)
|
||||
drvdata->bank_B = true;
|
||||
|
||||
pr_debug("%s : bank_A=%d bank_B=%d\n",__func__, drvdata->bank_A, drvdata->bank_B);
|
||||
|
||||
rc = of_property_read_u32(of_node, "full-scale-current", &tmp);
|
||||
if (rc) {
|
||||
pr_err("%s:%d, dt not specified\n",
|
||||
__func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
drvdata->full_scale_current = (!rc ? tmp : 0);
|
||||
|
||||
pr_info("bank_A = %d, bank_B = %d, pwm_cfg = 0x%x, full_scale_current = 0x%x, map_mode = 0x%x, boost_ctl = 0x%x.\n",
|
||||
drvdata->bank_A, drvdata->bank_B, drvdata->pwm_cfg, drvdata->full_scale_current, drvdata->map_mode, drvdata->boost_ctl);
|
||||
|
||||
drvdata->brt_code_enable = of_property_read_bool(of_node, "brt-code-enable");
|
||||
|
||||
if (drvdata->brt_code_enable == false) {
|
||||
pr_info("%s : brt_code_enable = %d, rc = %d.\n",__func__, drvdata->brt_code_enable, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
data = of_get_property(of_node, "brt-code-table", &len);
|
||||
if (!data) {
|
||||
pr_err("%s: read brt-code-table failed\n", __func__);
|
||||
//return -ENOMEM;
|
||||
}
|
||||
|
||||
len /= sizeof(u32);
|
||||
|
||||
buf = kzalloc(len * sizeof(u32), GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = of_property_read_u32_array(of_node, "brt-code-table", buf, len);
|
||||
if (rc) {
|
||||
pr_err("%s:%d, dt not specified\n",__func__, __LINE__);
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
drvdata->brt_code_table = kzalloc(len * sizeof(u16), GFP_KERNEL);
|
||||
if (!drvdata->brt_code_table) {
|
||||
pr_err("%s:%d, allocate memory failed\n",__func__, __LINE__);
|
||||
rc = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i=0; i < len; i++) {
|
||||
drvdata->brt_code_table[i] = (u16) buf[i];
|
||||
pr_debug("%s : buf=%d i=%d\n",__func__, buf[i], i);
|
||||
}
|
||||
end:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sm5350_bl_enable_hw(struct sm5350_data *drvdata){
|
||||
|
||||
return gpio_request_one(drvdata->en_gpio, GPIOF_OUT_INIT_HIGH, "sm5350_hwen");
|
||||
|
||||
}
|
||||
|
||||
static int sm5350_read_revision(struct sm5350_data *drvdata)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 value = 0;
|
||||
unsigned char cnt = 0;
|
||||
|
||||
while (cnt < 5) {
|
||||
ret = sm5350_read_reg(drvdata->client, SM5350_REVISION_REG, &value);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to read reg SM5350_REVISION_REG: %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
switch (value) {
|
||||
case 0x00:
|
||||
pr_info("%s sm5350 detected\n", __func__);
|
||||
return 0;
|
||||
default:
|
||||
pr_info("%s unsupported device revision (0x%x)\n",
|
||||
__func__, value);
|
||||
break;
|
||||
}
|
||||
cnt++;
|
||||
|
||||
msleep(2);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int sm5350_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct sm5350_data *drvdata;
|
||||
struct backlight_device *bl_dev;
|
||||
struct backlight_properties props;
|
||||
int err = 0;
|
||||
|
||||
printk("%s entry\n", __func__);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
pr_err("%s : I2C_FUNC_I2C not supported\n", __func__);
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (!client->dev.of_node) {
|
||||
pr_err("%s : no device node\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
drvdata = kzalloc(sizeof(struct sm5350_data), GFP_KERNEL);
|
||||
if (drvdata == NULL) {
|
||||
pr_err("%s : kzalloc failed\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
drvdata->client = client;
|
||||
drvdata->adapter = client->adapter;
|
||||
drvdata->addr = client->addr;
|
||||
drvdata->enable = true;
|
||||
|
||||
g_sm5350_data = drvdata;
|
||||
|
||||
err = sm5350_get_dt_data(&client->dev, drvdata);
|
||||
if(err < 0) {
|
||||
pr_err("%s : get dt failed\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto err_init;
|
||||
}
|
||||
err = sm5350_bl_enable_hw(drvdata);
|
||||
if (err)
|
||||
goto err_init;
|
||||
|
||||
i2c_set_clientdata(client, drvdata);
|
||||
|
||||
/*sm5350 read revision*/
|
||||
err = sm5350_read_revision(drvdata);
|
||||
if (err < 0) {
|
||||
pr_err("%s : ID idenfy failed\n", __func__);
|
||||
goto err_init;
|
||||
}
|
||||
/*sm5350 read revision*/
|
||||
printk("sm-sm5350 detected success\n");
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.brightness = MAX_BRIGHTNESS;
|
||||
props.max_brightness = MAX_BRIGHTNESS;
|
||||
bl_dev = backlight_device_register(SM5350_NAME, &client->dev,
|
||||
drvdata, &sm5350_bl_ops, &props);
|
||||
|
||||
if (IS_ERR(bl_dev))
|
||||
return PTR_ERR(bl_dev);
|
||||
drvdata->bl_dev = bl_dev;
|
||||
sm5350_init_registers(drvdata);
|
||||
dump_sm5350_regs(drvdata);
|
||||
sm5350_set_brightness(drvdata, drvdata->default_brightness);
|
||||
|
||||
printk("sm-sm5350 probe okay\n");
|
||||
return 0;
|
||||
|
||||
err_init:
|
||||
kfree(drvdata);
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sm5350_remove(struct i2c_client *client)
|
||||
{
|
||||
struct sm5350_data *drvdata = i2c_get_clientdata(client);
|
||||
|
||||
backlight_device_unregister(drvdata->bl_dev);
|
||||
kfree(drvdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sm5350_id[] = {
|
||||
{SM5350_NAME, 0},
|
||||
{}
|
||||
};
|
||||
static struct of_device_id match_table[] = {
|
||||
{.compatible = "sm-sm5350",}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, sm5350_id);
|
||||
|
||||
static struct i2c_driver sm5350_i2c_driver = {
|
||||
.probe = sm5350_probe,
|
||||
.remove = sm5350_remove,
|
||||
.id_table = sm5350_id,
|
||||
.driver = {
|
||||
.name = SM5350_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_i2c_driver(sm5350_i2c_driver);
|
||||
MODULE_DESCRIPTION("Back Light driver for SM5350");
|
||||
MODULE_LICENSE("GPL v2");
|
8
drivers/ese/st54x/Android.mk
Normal file
8
drivers/ese/st54x/Android.mk
Normal file
|
@ -0,0 +1,8 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := st54spi.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
6
drivers/ese/st54x/Kbuild
Normal file
6
drivers/ese/st54x/Kbuild
Normal file
|
@ -0,0 +1,6 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include
|
||||
|
||||
obj-m += st54spi.o
|
||||
|
16
drivers/ese/st54x/Makefile
Normal file
16
drivers/ese/st54x/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
|||
all: modules
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install
|
||||
|
||||
%:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers
|
||||
rm -rf .tmp_versions
|
||||
|
||||
|
1240
drivers/ese/st54x/st54spi.c
Normal file
1240
drivers/ese/st54x/st54spi.c
Normal file
File diff suppressed because it is too large
Load diff
10
drivers/fm/Android.mk
Normal file
10
drivers/fm/Android.mk
Normal file
|
@ -0,0 +1,10 @@
|
|||
ifeq ($(BOARD_HAS_FM_ELNA), true)
|
||||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := fm_ctrl.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
endif
|
4
drivers/fm/Kbuild
Normal file
4
drivers/fm/Kbuild
Normal file
|
@ -0,0 +1,4 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
|
||||
obj-m += fm_ctrl.o
|
11
drivers/fm/Makefile
Normal file
11
drivers/fm/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
||||
|
236
drivers/fm/fm_ctrl.c
Normal file
236
drivers/fm/fm_ctrl.c
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Motorola Mobility LLC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
|
||||
#define DRIVER_VERSION "0.0.1"
|
||||
|
||||
struct fm_ctrl_drvdata {
|
||||
struct device *dev;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pstate_default;
|
||||
struct pinctrl_state *pstate_active;
|
||||
struct pinctrl_state *pstate_suspend;
|
||||
bool factory_mode;
|
||||
};
|
||||
|
||||
|
||||
static bool mmi_factory_check(void)
|
||||
{
|
||||
struct device_node *np = of_find_node_by_path("/chosen");
|
||||
bool factory = false;
|
||||
|
||||
if (np)
|
||||
factory = of_property_read_bool(np, "mmi,factory-cable");
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
static ssize_t device_name_read(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fm_ctrl_drvdata *data = dev_get_drvdata(dev);
|
||||
|
||||
if (!data) {
|
||||
pr_err("fm_ctrl drvdata is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "moto fm control intf\n");
|
||||
}
|
||||
|
||||
|
||||
static ssize_t elna_en_read(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fm_ctrl_drvdata *data = dev_get_drvdata(dev);
|
||||
|
||||
if (!data) {
|
||||
pr_err("fm_ctrl drvdata is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "fm_ctrl: not support!\n");
|
||||
}
|
||||
|
||||
static ssize_t elna_en_write(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct fm_ctrl_drvdata *data = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
unsigned int res = 0;
|
||||
|
||||
if (!data) {
|
||||
pr_err("fm_ctrl drvdata is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = kstrtouint(buf, 0, &res);
|
||||
if(ret) {
|
||||
pr_err("fm_ctrl failed to get data, set as default!\n");
|
||||
}
|
||||
if(1 == res) {
|
||||
ret = pinctrl_select_state(data->pinctrl, data->pstate_active);
|
||||
}
|
||||
else {
|
||||
ret = pinctrl_select_state(data->pinctrl, data->pstate_suspend);
|
||||
}
|
||||
if(ret) {
|
||||
pr_err("fm_ctrl failed to set pinctrl!\n");
|
||||
}
|
||||
else {
|
||||
pr_info("fm_ctrl set elan=%u\n", res);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_ATTR(device_name, 0444, device_name_read, NULL);
|
||||
static DEVICE_ATTR(elna_en, 0644, elna_en_read, elna_en_write);
|
||||
|
||||
static struct attribute *fm_ctrl_sysfs_attrs[] = {
|
||||
&dev_attr_device_name.attr,
|
||||
&dev_attr_elna_en.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group fm_ctrl_sysfs_attr_grp = {
|
||||
.attrs = fm_ctrl_sysfs_attrs,
|
||||
};
|
||||
|
||||
|
||||
static int fm_ctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct fm_ctrl_drvdata *drvdata;
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s begin\n", __func__);
|
||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
drvdata->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, drvdata);
|
||||
|
||||
/* Get pinctrl if target uses pinctrl */
|
||||
drvdata->pinctrl = devm_pinctrl_get(dev);
|
||||
if (IS_ERR_OR_NULL(drvdata->pinctrl)) {
|
||||
ret = PTR_ERR(drvdata->pinctrl);
|
||||
pr_err("%s: Pincontrol DT property returned %X\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drvdata->pstate_default = pinctrl_lookup_state(drvdata->pinctrl,
|
||||
"default");
|
||||
if (IS_ERR_OR_NULL(drvdata->pstate_default)) {
|
||||
ret = PTR_ERR(drvdata->pstate_default);
|
||||
pr_err("Can not lookup default pinstate %d\n", ret);
|
||||
return -ENOENT;
|
||||
}
|
||||
drvdata->pstate_active = pinctrl_lookup_state(drvdata->pinctrl,
|
||||
"elna_active");
|
||||
if (IS_ERR_OR_NULL(drvdata->pstate_active)) {
|
||||
ret = PTR_ERR(drvdata->pstate_active);
|
||||
pr_err("Can not lookup active pinstate %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
drvdata->pstate_suspend = pinctrl_lookup_state(drvdata->pinctrl,
|
||||
"elna_suspend");
|
||||
if (IS_ERR_OR_NULL(drvdata->pstate_suspend)) {
|
||||
ret = PTR_ERR(drvdata->pstate_suspend);
|
||||
pr_err("Can not lookup suspend pinstate %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
drvdata->factory_mode = mmi_factory_check();
|
||||
if(drvdata->factory_mode) {
|
||||
ret = pinctrl_select_state(drvdata->pinctrl, drvdata->pstate_active);
|
||||
if(ret) {
|
||||
pr_err("fm_ctrl failed to set pinctrl @factory mode!\n");
|
||||
}
|
||||
else {
|
||||
pr_info("fm_ctrl enable elan @ factory mode\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = pinctrl_select_state(drvdata->pinctrl, drvdata->pstate_default);
|
||||
if(ret) {
|
||||
pr_err("fm_ctrl failed to set pinctrl as default!\n");
|
||||
}
|
||||
else {
|
||||
pr_info("fm_ctrl disable elan as default.\n");
|
||||
}
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&dev->kobj, &fm_ctrl_sysfs_attr_grp);
|
||||
if (ret) {
|
||||
pr_err("%s: sysfs group creation failed %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
dev_info(&pdev->dev, "probe: All success !\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fm_ctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct of_device_id fm_ctrl_match[] = {
|
||||
{ .compatible = "moto,fmctrl" },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver fm_ctrl_plat_driver = {
|
||||
.probe = fm_ctrl_probe,
|
||||
.remove = fm_ctrl_remove,
|
||||
.driver = {
|
||||
.name = "fm_ctrl",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = fm_ctrl_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(fm_ctrl_plat_driver);
|
||||
|
||||
|
||||
MODULE_AUTHOR("Motorola Mobiity");
|
||||
MODULE_DESCRIPTION("FMRadio control interface driver");
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
8
drivers/gpio/pcal6408/Android.mk
Executable file
8
drivers/gpio/pcal6408/Android.mk
Executable file
|
@ -0,0 +1,8 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := gpio-pcal6408.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
9
drivers/gpio/pcal6408/Kbuild
Executable file
9
drivers/gpio/pcal6408/Kbuild
Executable file
|
@ -0,0 +1,9 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
|
||||
|
||||
ifeq ($(TARGET_BUILD_VARIANT),userdebug)
|
||||
EXTRA_CFLAGS += -DGPIOI2C_USER_DEBUG
|
||||
endif
|
||||
|
||||
obj-m += gpio-pcal6408.o
|
616
drivers/gpio/pcal6408/gpio-pcal6408.c
Executable file
616
drivers/gpio/pcal6408/gpio-pcal6408.c
Executable file
|
@ -0,0 +1,616 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Motorola Mobility, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#define PCAL6408_DBG(msg, ...) \
|
||||
pr_debug("pcal6048: [%s] "msg, __func__, ##__VA_ARGS__)
|
||||
#define PCAL6408_ERR(msg, ...) \
|
||||
pr_err("pcal6048: [%s] "msg, __func__, ##__VA_ARGS__)
|
||||
#define PCAL6408_LOG(msg, ...) \
|
||||
pr_info("pcal6048: [%s] "msg, __func__, ##__VA_ARGS__)
|
||||
|
||||
#define PCAL6408_ADDR_INPUT 0x00
|
||||
#define PCAL6408_ADDR_OUTPUT 0x01
|
||||
#define PCAL6408_ADDR_CONFIG 0x03
|
||||
#define PCAL6408_ADDR_PULL_EN 0x43
|
||||
#define PCAL6408_ADDR_PULL_CFG 0x44
|
||||
|
||||
#define TCA6418_ADDR_INPUT 0x14
|
||||
#define TCA6418_ADDR_OUTPUT 0x17
|
||||
#define TCA6418_ADDR_CONFIG 0x23
|
||||
#define TCA6418_ADDR_PULL_CFG 0x2C
|
||||
|
||||
#define BIAS_PULL_UP 0
|
||||
#define BIAS_PULL_DOWN 1
|
||||
#define BIAS_NO_PULL 2
|
||||
|
||||
struct pcal6048_dev;
|
||||
|
||||
struct pcal6048_config {
|
||||
char *name;
|
||||
int nr_gpio;
|
||||
int dir_out_val;
|
||||
int direction;
|
||||
int output;
|
||||
int input;
|
||||
int (*get_bit)(int);
|
||||
int (*set_pulldown)(int, struct pcal6048_dev *);
|
||||
int (*set_pullup)(int, struct pcal6048_dev *);
|
||||
int (*set_nopull)(int, struct pcal6048_dev *);
|
||||
int (*get_pull)(int, struct pcal6048_dev *);
|
||||
};
|
||||
|
||||
struct pcal6048_dev {
|
||||
const char *name;
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct gpio_chip gpio_chip;
|
||||
const struct pcal6048_config *conf;
|
||||
struct pinctrl_desc ctrldesc;
|
||||
struct pinctrl_dev *pctl_dev;
|
||||
struct pinctrl_gpio_range grange;
|
||||
int reset_gpio;
|
||||
};
|
||||
|
||||
static int pcal6048_set_reg(struct pcal6048_dev *chip, int gpio, int reg);
|
||||
static int pcal6048_clear_reg(struct pcal6048_dev *chip, int gpio, int reg);
|
||||
static int pcal6048_read_reg(struct pcal6048_dev *chip, int gpio, int reg);
|
||||
|
||||
static int pcal6408_get_bit(int gpio)
|
||||
{
|
||||
return gpio;
|
||||
}
|
||||
|
||||
static int pcal6408_set_pulldown(int gpio, struct pcal6048_dev *chip)
|
||||
{
|
||||
if (pcal6048_clear_reg(chip, gpio, PCAL6408_ADDR_PULL_CFG)) {
|
||||
PCAL6408_ERR("Failed to set pulldown for gpio %d\n", gpio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pcal6048_set_reg(chip, gpio, PCAL6408_ADDR_PULL_EN)) {
|
||||
PCAL6408_ERR("Failed to set pulldown for gpio %d\n", gpio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcal6408_set_pullup(int gpio, struct pcal6048_dev *chip)
|
||||
{
|
||||
if (pcal6048_set_reg(chip, gpio, PCAL6408_ADDR_PULL_CFG)) {
|
||||
PCAL6408_ERR("Failed to set pulldown for gpio %d\n", gpio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pcal6048_set_reg(chip, gpio, PCAL6408_ADDR_PULL_EN)) {
|
||||
PCAL6408_ERR("Failed to set pulldown for gpio %d\n", gpio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcal6408_set_nopull(int gpio, struct pcal6048_dev *chip)
|
||||
{
|
||||
if (pcal6048_clear_reg(chip, gpio, PCAL6408_ADDR_PULL_EN)) {
|
||||
PCAL6408_ERR("Failed to set pulldown for gpio %d\n", gpio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcal6408_get_pull(int gpio, struct pcal6048_dev *chip)
|
||||
{
|
||||
if (!pcal6048_read_reg(chip, gpio, PCAL6408_ADDR_PULL_EN))
|
||||
return BIAS_NO_PULL;
|
||||
else if (pcal6048_read_reg(chip, gpio, PCAL6408_ADDR_PULL_CFG))
|
||||
return BIAS_PULL_UP;
|
||||
else
|
||||
return BIAS_PULL_DOWN;
|
||||
}
|
||||
|
||||
static const struct pcal6048_config pcal6408a_conf = {
|
||||
.name = "pcal6408a_conf",
|
||||
.nr_gpio = 8,
|
||||
.set_pulldown = pcal6408_set_pulldown,
|
||||
.set_pullup = pcal6408_set_pullup,
|
||||
.set_nopull = pcal6408_set_nopull,
|
||||
.get_pull = pcal6408_get_pull,
|
||||
.get_bit = pcal6408_get_bit,
|
||||
.dir_out_val = 0, /* Set 0 to direction for output */
|
||||
.direction = PCAL6408_ADDR_CONFIG,
|
||||
.output = PCAL6408_ADDR_OUTPUT,
|
||||
.input = PCAL6408_ADDR_INPUT,
|
||||
};
|
||||
|
||||
static int tca6418_get_bit(int gpio)
|
||||
{
|
||||
/* Bitmapping is strange, gpio7 is bit 0 of first addr,
|
||||
* but gpio8 is bit 0 of second addr, gpio 16 is bit 0
|
||||
* of third addr
|
||||
*/
|
||||
if (gpio <= 7)
|
||||
return (7 - gpio);
|
||||
else if (gpio > 7 && gpio <= 15)
|
||||
return gpio - 8;
|
||||
else
|
||||
return gpio - 16;
|
||||
}
|
||||
|
||||
static int tca6418_set_pulldown(int gpio, struct pcal6048_dev *chip)
|
||||
{
|
||||
if (pcal6048_clear_reg(chip, gpio, TCA6418_ADDR_PULL_CFG)) {
|
||||
PCAL6408_ERR("Failed to set pulldown for gpio %d\n", gpio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tca6418_set_nopull(int gpio, struct pcal6048_dev *chip)
|
||||
{
|
||||
if (pcal6048_set_reg(chip, gpio, TCA6418_ADDR_PULL_CFG)) {
|
||||
PCAL6408_ERR("Failed to set pulldown for gpio %d\n", gpio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tca6418_get_pull(int gpio, struct pcal6048_dev *chip)
|
||||
{
|
||||
if (!pcal6048_read_reg(chip, gpio, TCA6418_ADDR_PULL_CFG))
|
||||
return BIAS_PULL_DOWN;
|
||||
else
|
||||
return BIAS_NO_PULL;
|
||||
}
|
||||
|
||||
static const struct pcal6048_config tca6418e_conf = {
|
||||
.name = "tca6418e_conf",
|
||||
.nr_gpio = 18,
|
||||
.set_pulldown = tca6418_set_pulldown,
|
||||
.set_pullup = NULL,
|
||||
.set_nopull = tca6418_set_nopull,
|
||||
.get_pull = tca6418_get_pull,
|
||||
.get_bit = tca6418_get_bit,
|
||||
.dir_out_val = 1, /* Set 1 to direction for output */
|
||||
.direction = TCA6418_ADDR_CONFIG,
|
||||
.output = TCA6418_ADDR_OUTPUT,
|
||||
.input = TCA6418_ADDR_INPUT,
|
||||
};
|
||||
|
||||
static int pcal6048_read_reg(struct pcal6048_dev *chip, int gpio, int reg)
|
||||
{
|
||||
int bit_num = chip->conf->get_bit(gpio);
|
||||
uint8_t bit = BIT(bit_num);
|
||||
int reg_off = (gpio / 8);
|
||||
int val;
|
||||
int ret = -1;
|
||||
|
||||
PCAL6408_DBG("%s (gpio %d), read bit %d from 0x%x\n",
|
||||
chip->conf->name, gpio, bit_num, reg + reg_off);
|
||||
|
||||
ret = regmap_read(chip->regmap, reg + reg_off, &val);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
return !!(val & bit);
|
||||
}
|
||||
|
||||
static int pcal6048_set_reg(struct pcal6048_dev *chip, int gpio, int reg)
|
||||
{
|
||||
int bit_num = chip->conf->get_bit(gpio);
|
||||
uint8_t bit = BIT(bit_num);
|
||||
int reg_off = (gpio / 8);
|
||||
|
||||
PCAL6408_DBG("%s (gpio %d), set bit %d in 0x%x\n",
|
||||
chip->conf->name, gpio, bit_num, reg + reg_off);
|
||||
|
||||
return regmap_write_bits(chip->regmap, reg + reg_off, bit, bit);
|
||||
}
|
||||
|
||||
static int pcal6048_clear_reg(struct pcal6048_dev *chip, int gpio, int reg)
|
||||
{
|
||||
int bit_num = chip->conf->get_bit(gpio);
|
||||
uint8_t bit = BIT(bit_num);
|
||||
int reg_off = (gpio / 8);
|
||||
|
||||
PCAL6408_DBG("%s (gpio %d), clear bit %d in 0x%x\n",
|
||||
chip->conf->name, gpio, bit_num, reg + reg_off);
|
||||
|
||||
return regmap_write_bits(chip->regmap, reg + reg_off, bit, 0);
|
||||
}
|
||||
|
||||
static int pcal6048_direction_in(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pcal6048_dev *chip = gpiochip_get_data(gc);
|
||||
int ret;
|
||||
|
||||
if (!chip->conf->dir_out_val)
|
||||
ret = pcal6048_set_reg(chip, offset, chip->conf->direction);
|
||||
else
|
||||
ret = pcal6048_clear_reg(chip, offset, chip->conf->direction);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pcal6048_set_gpio(struct gpio_chip *gc, unsigned offset, int value)
|
||||
{
|
||||
struct pcal6048_dev *chip = gpiochip_get_data(gc);
|
||||
|
||||
if (value)
|
||||
pcal6048_set_reg(chip, offset, chip->conf->output);
|
||||
else
|
||||
pcal6048_clear_reg(chip, offset, chip->conf->output);
|
||||
}
|
||||
|
||||
static int pcal6048_direction_out(struct gpio_chip *gc, unsigned offset, int value)
|
||||
{
|
||||
struct pcal6048_dev *chip = gpiochip_get_data(gc);
|
||||
int ret;
|
||||
|
||||
ret = pcal6048_set_reg(chip, offset, chip->conf->output);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (chip->conf->dir_out_val)
|
||||
ret = pcal6048_set_reg(chip, offset, chip->conf->direction);
|
||||
else
|
||||
ret = pcal6048_clear_reg(chip, offset, chip->conf->direction);
|
||||
|
||||
pcal6048_set_gpio(gc, offset, value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 0 is out, 1 is in */
|
||||
static int pcal6048_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pcal6048_dev *chip = gpiochip_get_data(gc);
|
||||
int val = pcal6048_read_reg(chip, offset, chip->conf->direction);
|
||||
|
||||
if (val == chip->conf->dir_out_val)
|
||||
return 0;
|
||||
else;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pcal6048_get_gpio(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pcal6048_dev *chip = gpiochip_get_data(gc);
|
||||
|
||||
/* TODO do I need to read twice to make sure it is cleared? (TCA6418e pg 12) */
|
||||
return pcal6048_read_reg(chip, offset, chip->conf->input);
|
||||
}
|
||||
|
||||
static int pcal6048_set_config(struct gpio_chip *gc, unsigned int offset, unsigned long config)
|
||||
{
|
||||
struct pcal6048_dev *chip = gpiochip_get_data(gc);
|
||||
unsigned arg = pinconf_to_config_argument(config);
|
||||
unsigned param = pinconf_to_config_param(config);
|
||||
|
||||
PCAL6408_DBG("Set config for gpio %d!\n", offset);
|
||||
|
||||
switch (param) {
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
if (chip->conf->set_pullup)
|
||||
return chip->conf->set_pullup(offset, chip);
|
||||
else
|
||||
return -ENOTSUPP;
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
if (chip->conf->set_pulldown)
|
||||
return chip->conf->set_pulldown(offset, chip);
|
||||
else
|
||||
return -ENOTSUPP;
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
if (chip->conf->set_nopull)
|
||||
return chip->conf->set_nopull(offset, chip);
|
||||
else
|
||||
return -ENOTSUPP;
|
||||
case PIN_CONFIG_INPUT_ENABLE:
|
||||
return pcal6048_direction_in(gc, offset);
|
||||
case PIN_CONFIG_OUTPUT_ENABLE:
|
||||
return pcal6048_direction_out(gc, offset, 1);
|
||||
case PIN_CONFIG_OUTPUT:
|
||||
return pcal6048_direction_out(gc, offset, !!arg);
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void pcal6048_dbg_show(struct seq_file *s, struct gpio_chip *gc)
|
||||
{
|
||||
struct pcal6048_dev *chip = gpiochip_get_data(gc);
|
||||
unsigned gpio = gc->base;
|
||||
unsigned i;
|
||||
int dir = 0;
|
||||
int pull = 0;
|
||||
|
||||
for (i = 0; i < gc->ngpio; i++, gpio++) {
|
||||
seq_printf(s, " gpio%d:", i);
|
||||
|
||||
dir = pcal6048_get_direction(gc, i);
|
||||
/* Input is 1 */
|
||||
if (dir)
|
||||
seq_printf(s, " in %d", pcal6048_get_gpio(gc, i));
|
||||
else
|
||||
seq_printf(s, " out (set to %d)",
|
||||
pcal6048_read_reg(chip, i, chip->conf->output));
|
||||
|
||||
if (chip->conf->get_pull) {
|
||||
pull = chip->conf->get_pull(i, chip);
|
||||
switch(pull) {
|
||||
case BIAS_NO_PULL:
|
||||
seq_printf(s, " bias-no-pull");
|
||||
break;
|
||||
case BIAS_PULL_DOWN:
|
||||
seq_printf(s, " bias-pull-down");
|
||||
break;
|
||||
case BIAS_PULL_UP:
|
||||
seq_printf(s, " bias-pull-up");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void pcal6048_setup_gpio_chip(struct pcal6048_dev *chip)
|
||||
{
|
||||
struct gpio_chip *gc;
|
||||
|
||||
gc = &chip->gpio_chip;
|
||||
|
||||
gc->label = chip->conf->name;
|
||||
gc->base = -1;
|
||||
gc->ngpio = chip->conf->nr_gpio;
|
||||
gc->parent = chip->dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->direction_input = pcal6048_direction_in;
|
||||
gc->direction_output = pcal6048_direction_out;
|
||||
gc->get_direction = pcal6048_get_direction;
|
||||
gc->get = pcal6048_get_gpio;
|
||||
gc->set = pcal6048_set_gpio;
|
||||
gc->set_config = pcal6048_set_config;
|
||||
gc->dbg_show = pcal6048_dbg_show;
|
||||
gc->can_sleep = true;
|
||||
}
|
||||
|
||||
static int pcal6048_pinconf_get(struct pinctrl_dev *pctldev,
|
||||
unsigned pin, unsigned long *config)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int pcal6048_pinconf_set(struct pinctrl_dev *pctldev,
|
||||
unsigned int pin, unsigned long *configs,
|
||||
unsigned int num_configs)
|
||||
{
|
||||
struct pcal6048_dev *chip = pinctrl_dev_get_drvdata(pctldev);
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_configs; i++) {
|
||||
chip->gpio_chip.set_config(&chip->gpio_chip, pin, configs[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcal6048_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct pcal6048_dev *chip = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
return chip->conf->nr_gpio;
|
||||
}
|
||||
|
||||
static const char *pcal6048_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct pcal6048_dev *chip = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
return chip->conf->name;
|
||||
}
|
||||
|
||||
static const struct pinctrl_ops pcal6048_pctl_ops = {
|
||||
.get_groups_count = pcal6048_get_groups_count,
|
||||
.get_group_name = pcal6048_get_group_name,
|
||||
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
|
||||
};
|
||||
|
||||
static const struct pinconf_ops pcal6048_pinconf_ops = {
|
||||
.is_generic = true,
|
||||
.pin_config_get = pcal6048_pinconf_get,
|
||||
.pin_config_set = pcal6048_pinconf_set,
|
||||
};
|
||||
|
||||
static int pcal6048_register_pinctrl(struct pcal6048_dev *chip)
|
||||
{
|
||||
struct pinctrl_desc *ctrldesc = &chip->ctrldesc;
|
||||
struct pinctrl_pin_desc *pindesc, *pdesc;
|
||||
int pin;
|
||||
|
||||
ctrldesc->name = chip->conf->name;
|
||||
ctrldesc->owner = THIS_MODULE;
|
||||
ctrldesc->confops = &pcal6048_pinconf_ops;
|
||||
ctrldesc->pctlops = &pcal6048_pctl_ops;
|
||||
|
||||
pindesc = devm_kcalloc(chip->dev,
|
||||
chip->conf->nr_gpio, sizeof(*pindesc),
|
||||
GFP_KERNEL);
|
||||
|
||||
ctrldesc->pins = pindesc;
|
||||
ctrldesc->npins = chip->conf->nr_gpio;
|
||||
|
||||
pdesc = pindesc;
|
||||
for (pin = 0; pin < chip->conf->nr_gpio; pin++) {
|
||||
pdesc->number = pin;
|
||||
pdesc->name = kasprintf(GFP_KERNEL, "gpio%d", pin);
|
||||
pdesc++;
|
||||
}
|
||||
|
||||
chip->pctl_dev = devm_pinctrl_register(chip->dev, ctrldesc, chip);
|
||||
|
||||
if (IS_ERR(chip->pctl_dev)) {
|
||||
PCAL6408_ERR("Failed to register pinctrl\n");
|
||||
return PTR_ERR(chip->pctl_dev);
|
||||
}
|
||||
|
||||
chip->grange.base = chip->gpio_chip.base;
|
||||
chip->grange.npins = chip->conf->nr_gpio;
|
||||
chip->grange.gc = &chip->gpio_chip;
|
||||
|
||||
pinctrl_add_gpio_range(chip->pctl_dev, &chip->grange);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config pcal6048_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xFF,
|
||||
};
|
||||
|
||||
static const struct of_device_id pcal6048_match_table[] = {
|
||||
{ .compatible = "ti,tca6418e", .data = &tca6418e_conf },
|
||||
{ .compatible = "nxp,pcal6408a", .data = &pcal6408a_conf },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int pcal6048_config_reset(struct pcal6048_dev *chip)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
chip->reset_gpio = of_get_gpio(chip->dev->of_node, 0);
|
||||
if (gpio_is_valid(chip->reset_gpio)) {
|
||||
err = devm_gpio_request(chip->dev, chip->reset_gpio, "pcal6048_reset");
|
||||
if (err) {
|
||||
PCAL6408_ERR("Reset gpio request failed\n");
|
||||
return err;
|
||||
} else {
|
||||
/* Active low, so set it high */
|
||||
err = gpio_direction_output(chip->reset_gpio, 1);
|
||||
if (err) {
|
||||
PCAL6408_ERR("Reset gpio set failed\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else
|
||||
PCAL6408_LOG("No reset gpio set in dtb\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcal6048_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int rc = 0;
|
||||
struct pcal6048_dev *chip;
|
||||
const struct of_device_id *match;
|
||||
|
||||
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->client = client;
|
||||
chip->dev = &client->dev;
|
||||
chip->name = "pcal6048";
|
||||
|
||||
chip->regmap = regmap_init_i2c(client, &pcal6048_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
PCAL6408_ERR("Couldn't initialize register regmap rc = %ld\n",
|
||||
PTR_ERR(chip->regmap));
|
||||
rc = PTR_ERR(chip->regmap);
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
match = of_match_device(pcal6048_match_table, chip->dev);
|
||||
if (!match || !match->data) {
|
||||
PCAL6408_ERR("Missing config data!\n");
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
chip->conf = match->data;
|
||||
PCAL6408_DBG("Using config %s\n", chip->conf->name);
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
dev_set_drvdata(chip->dev, chip);
|
||||
|
||||
pcal6048_setup_gpio_chip(chip);
|
||||
pcal6048_config_reset(chip);
|
||||
|
||||
rc = devm_gpiochip_add_data(chip->dev, &chip->gpio_chip, chip);
|
||||
if (rc) {
|
||||
PCAL6408_ERR("Couldn't add gpio chip rc=%d\n", rc);
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
pcal6048_register_pinctrl(chip);
|
||||
|
||||
return 0;
|
||||
|
||||
free_mem:
|
||||
devm_kfree(chip->dev, chip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pcal6048_remove(struct i2c_client *client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver pcal6048_driver = {
|
||||
.driver = {
|
||||
.name = "pcal6048",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = pcal6048_match_table,
|
||||
},
|
||||
.probe = pcal6048_probe,
|
||||
.remove = pcal6048_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(pcal6048_driver);
|
||||
|
||||
MODULE_DESCRIPTION("pcal6048");
|
||||
MODULE_LICENSE("GPL v2");
|
11
drivers/gud/MobiCoreDriver/Android.mk
Normal file
11
drivers/gud/MobiCoreDriver/Android.mk
Normal file
|
@ -0,0 +1,11 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mcDrvModule.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
ifeq ($(RSU_SELECT_INTERNAL_CLOCK), true)
|
||||
KERNEL_CFLAGS += RSU_INTERNAL_CLOCK=y
|
||||
endif
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
49
drivers/gud/MobiCoreDriver/Kbuild
Normal file
49
drivers/gud/MobiCoreDriver/Kbuild
Normal file
|
@ -0,0 +1,49 @@
|
|||
#/*
|
||||
# * Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
# * All Rights Reserved.
|
||||
# *
|
||||
# * This program is free software; you can redistribute it and/or
|
||||
# * modify it under the terms of the GNU General Public License
|
||||
# * version 2 as published by the Free Software Foundation.
|
||||
# *
|
||||
# * This program is distributed in the hope that it will be useful,
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# * GNU General Public License for more details.
|
||||
# */
|
||||
#
|
||||
# Makefile for the Kinibi core driver
|
||||
#
|
||||
|
||||
|
||||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -DNDEBUG
|
||||
EXTRA_CFLAGS += -Wno-declaration-after-statement
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/drivers/gud/MobiCoreDriver
|
||||
|
||||
ifneq ($(filter m y,$(RSU_INTERNAL_CLOCK)),)
|
||||
EXTRA_CFLAGS += -DRSU_INTERNAL_CLOCK
|
||||
endif
|
||||
|
||||
obj-m += mcDrvModule.o
|
||||
|
||||
|
||||
mcDrvModule-y := \
|
||||
admin.o \
|
||||
client.o \
|
||||
clientlib.o \
|
||||
clock.o \
|
||||
fastcall.o \
|
||||
iwp.o \
|
||||
logging.o \
|
||||
main.o \
|
||||
mcp.o \
|
||||
mmu.o \
|
||||
nq.o \
|
||||
session.o \
|
||||
teeclientapi.o \
|
||||
user.o \
|
||||
xen_be.o \
|
||||
xen_common.o \
|
||||
xen_fe.o
|
11
drivers/gud/MobiCoreDriver/Makefile
Normal file
11
drivers/gud/MobiCoreDriver/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
||||
|
1186
drivers/gud/MobiCoreDriver/admin.c
Normal file
1186
drivers/gud/MobiCoreDriver/admin.c
Normal file
File diff suppressed because it is too large
Load diff
33
drivers/gud/MobiCoreDriver/admin.h
Normal file
33
drivers/gud/MobiCoreDriver/admin.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_ADMIN_H_
|
||||
#define _MC_ADMIN_H_
|
||||
|
||||
struct cdev;
|
||||
struct mc_uuid_t;
|
||||
struct tee_object;
|
||||
|
||||
int mc_admin_init(struct cdev *cdev, int (*tee_start_cb)(void),
|
||||
void (*tee_stop_cb)(void));
|
||||
void mc_admin_exit(void);
|
||||
|
||||
struct tee_object *tee_object_select(const struct mc_uuid_t *uuid);
|
||||
struct tee_object *tee_object_get(const struct mc_uuid_t *uuid, bool is_gp);
|
||||
struct tee_object *tee_object_copy(uintptr_t address, size_t length);
|
||||
struct tee_object *tee_object_read(u32 spid, uintptr_t address, size_t length);
|
||||
void tee_object_free(struct tee_object *object);
|
||||
|
||||
#endif /* _MC_ADMIN_H_ */
|
89
drivers/gud/MobiCoreDriver/arm.h
Normal file
89
drivers/gud/MobiCoreDriver/arm.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef _MC_ARM_H_
|
||||
#define _MC_ARM_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
static inline bool has_security_extensions(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool is_secure_mode(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* ARM Trustzone specific masks and modes
|
||||
* Vanilla Linux is unaware of TrustZone extension.
|
||||
* I.e. arch/arm/include/asm/ptrace.h does not define monitor mode.
|
||||
* Also TZ bits in cpuid are not defined, ARM port uses magic numbers,
|
||||
* see arch/arm/kernel/setup.c
|
||||
*/
|
||||
#define ARM_MONITOR_MODE (0x16) /*(0b10110)*/
|
||||
#define ARM_SECURITY_EXTENSION_MASK (0x30)
|
||||
|
||||
/* check if CPU supports the ARM TrustZone Security Extensions */
|
||||
static inline bool has_security_extensions(void)
|
||||
{
|
||||
u32 fea = 0;
|
||||
|
||||
asm volatile(
|
||||
"mrc p15, 0, %[fea], cr0, cr1, 0" :
|
||||
[fea]"=r" (fea));
|
||||
|
||||
mc_dev_devel("CPU Features: 0x%X", fea);
|
||||
|
||||
/*
|
||||
* If the CPU features ID has 0 for security features then the CPU
|
||||
* doesn't support TrustZone at all!
|
||||
*/
|
||||
if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* check if running in secure mode */
|
||||
static inline bool is_secure_mode(void)
|
||||
{
|
||||
u32 cpsr = 0;
|
||||
u32 nsacr = 0;
|
||||
|
||||
asm volatile(
|
||||
"mrc p15, 0, %[nsacr], cr1, cr1, 2\n"
|
||||
"mrs %[cpsr], cpsr\n" :
|
||||
[nsacr]"=r" (nsacr),
|
||||
[cpsr]"=r"(cpsr));
|
||||
|
||||
mc_dev_devel("CPRS.M = set to 0x%X", cpsr & MODE_MASK);
|
||||
mc_dev_devel("SCR.NS = set to 0x%X", nsacr);
|
||||
|
||||
/*
|
||||
* If the NSACR contains the reset value(=0) then most likely we are
|
||||
* running in Secure MODE.
|
||||
* If the cpsr mode is set to monitor mode then we cannot load!
|
||||
*/
|
||||
if (nsacr == 0 || ((cpsr & MODE_MASK) == ARM_MONITOR_MODE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MC_ARM_H_ */
|
18
drivers/gud/MobiCoreDriver/build_tag.h
Normal file
18
drivers/gud/MobiCoreDriver/build_tag.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef MOBICORE_COMPONENT_BUILD_TAG
|
||||
#define MOBICORE_COMPONENT_BUILD_TAG \
|
||||
"t-base-QC8996-Android-410a-V108-20211010_233907_31049_105441"
|
||||
#endif
|
1486
drivers/gud/MobiCoreDriver/client.c
Normal file
1486
drivers/gud/MobiCoreDriver/client.c
Normal file
File diff suppressed because it is too large
Load diff
126
drivers/gud/MobiCoreDriver/client.h
Normal file
126
drivers/gud/MobiCoreDriver/client.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _CLIENT_H_
|
||||
#define _CLIENT_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/sched.h> /* TASK_COMM_LEN */
|
||||
|
||||
#include "mc_user.h" /* many types */
|
||||
|
||||
struct tee_client;
|
||||
struct mcp_open_info;
|
||||
struct tee_mmu;
|
||||
struct interworld_session;
|
||||
|
||||
/* Client */
|
||||
struct tee_client *client_create(bool is_from_kernel);
|
||||
void client_get(struct tee_client *client);
|
||||
int client_put(struct tee_client *client);
|
||||
bool client_has_sessions(struct tee_client *client);
|
||||
void client_close(struct tee_client *client);
|
||||
void client_cleanup(void);
|
||||
|
||||
/* MC */
|
||||
int client_mc_open_session(struct tee_client *client,
|
||||
const struct mc_uuid_t *uuid,
|
||||
uintptr_t tci_va, size_t tci_len, u32 *session_id);
|
||||
int client_mc_open_trustlet(struct tee_client *client,
|
||||
u32 spid, uintptr_t ta_va, size_t ta_len,
|
||||
uintptr_t tci_va, size_t tci_len, u32 *session_id);
|
||||
int client_mc_open_common(struct tee_client *client, struct mcp_open_info *info,
|
||||
u32 *session_id);
|
||||
int client_remove_session(struct tee_client *client, u32 session_id);
|
||||
int client_notify_session(struct tee_client *client, u32 session_id);
|
||||
int client_waitnotif_session(struct tee_client *client, u32 session_id,
|
||||
s32 timeout, bool silent_expiry);
|
||||
int client_get_session_exitcode(struct tee_client *client, u32 session_id,
|
||||
s32 *exit_code);
|
||||
int client_mc_map(struct tee_client *client, u32 session_id,
|
||||
struct tee_mmu *mmu, struct mc_ioctl_buffer *buf);
|
||||
int client_mc_unmap(struct tee_client *client, u32 session_id,
|
||||
const struct mc_ioctl_buffer *buf);
|
||||
|
||||
/* GP */
|
||||
int client_gp_initialize_context(struct tee_client *client,
|
||||
struct gp_return *gp_ret);
|
||||
int client_gp_register_shared_mem(struct tee_client *client,
|
||||
struct tee_mmu *mmu, u32 *sva,
|
||||
const struct gp_shared_memory *memref,
|
||||
struct gp_return *gp_ret);
|
||||
int client_gp_release_shared_mem(struct tee_client *client,
|
||||
const struct gp_shared_memory *memref);
|
||||
int client_gp_open_session(struct tee_client *client,
|
||||
const struct mc_uuid_t *uuid,
|
||||
struct gp_operation *operation,
|
||||
const struct mc_identity *identity,
|
||||
struct gp_return *gp_ret,
|
||||
u32 *session_id);
|
||||
int client_gp_open_session_domu(struct tee_client *client,
|
||||
const struct mc_uuid_t *uuid, u64 started,
|
||||
struct interworld_session *iws,
|
||||
struct tee_mmu **mmus,
|
||||
struct gp_return *gp_ret);
|
||||
int client_gp_close_session(struct tee_client *client, u32 session_id);
|
||||
int client_gp_invoke_command(struct tee_client *client, u32 session_id,
|
||||
u32 command_id,
|
||||
struct gp_operation *operation,
|
||||
struct gp_return *gp_ret);
|
||||
int client_gp_invoke_command_domu(struct tee_client *client, u32 session_id,
|
||||
u64 started, struct interworld_session *iws,
|
||||
struct tee_mmu **mmus,
|
||||
struct gp_return *gp_ret);
|
||||
void client_gp_request_cancellation(struct tee_client *client, u64 started);
|
||||
|
||||
/* Contiguous buffer */
|
||||
int client_cbuf_create(struct tee_client *client, u32 len, uintptr_t *addr,
|
||||
struct vm_area_struct *vmarea);
|
||||
int client_cbuf_free(struct tee_client *client, uintptr_t addr);
|
||||
|
||||
/* GP internal */
|
||||
struct client_gp_operation {
|
||||
struct list_head list;
|
||||
u64 started;
|
||||
u64 slot;
|
||||
int cancelled;
|
||||
};
|
||||
|
||||
/* Called from session when a new operation starts/ends */
|
||||
bool client_gp_operation_add(struct tee_client *client,
|
||||
struct client_gp_operation *operation);
|
||||
void client_gp_operation_remove(struct tee_client *client,
|
||||
struct client_gp_operation *operation);
|
||||
|
||||
/* MMU */
|
||||
struct cbuf;
|
||||
|
||||
struct tee_mmu *client_mmu_create(struct tee_client *client,
|
||||
const struct mc_ioctl_buffer *buf_in,
|
||||
struct cbuf **cbuf_p);
|
||||
void tee_cbuf_put(struct cbuf *cbuf);
|
||||
|
||||
/* Buffer shared with SWd at client level */
|
||||
u32 client_get_cwsm_sva(struct tee_client *client,
|
||||
const struct gp_shared_memory *memref);
|
||||
void client_put_cwsm_sva(struct tee_client *client, u32 sva);
|
||||
|
||||
/* Global */
|
||||
void client_init(void);
|
||||
|
||||
/* Debug */
|
||||
int clients_debug_structs(struct kasnprintf_buf *buf);
|
||||
|
||||
#endif /* _CLIENT_H_ */
|
439
drivers/gud/MobiCoreDriver/clientlib.c
Normal file
439
drivers/gud/MobiCoreDriver/clientlib.c
Normal file
|
@ -0,0 +1,439 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "mc_user.h"
|
||||
#include "mc_admin.h"
|
||||
#include "mobicore_driver_api.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "client.h"
|
||||
|
||||
static enum mc_result convert(int err)
|
||||
{
|
||||
switch (-err) {
|
||||
case 0:
|
||||
return MC_DRV_OK;
|
||||
case ENOMSG:
|
||||
return MC_DRV_NO_NOTIFICATION;
|
||||
case EBADMSG:
|
||||
return MC_DRV_ERR_NOTIFICATION;
|
||||
case EAGAIN:
|
||||
return MC_DRV_ERR_OUT_OF_RESOURCES;
|
||||
case EHOSTDOWN:
|
||||
return MC_DRV_ERR_INIT;
|
||||
case ENODEV:
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
case ENXIO:
|
||||
return MC_DRV_ERR_UNKNOWN_SESSION;
|
||||
case EPERM:
|
||||
return MC_DRV_ERR_INVALID_OPERATION;
|
||||
case EBADE:
|
||||
return MC_DRV_ERR_INVALID_RESPONSE;
|
||||
case ETIME:
|
||||
return MC_DRV_ERR_TIMEOUT;
|
||||
case ENOMEM:
|
||||
return MC_DRV_ERR_NO_FREE_MEMORY;
|
||||
case EUCLEAN:
|
||||
return MC_DRV_ERR_FREE_MEMORY_FAILED;
|
||||
case ENOTEMPTY:
|
||||
return MC_DRV_ERR_SESSION_PENDING;
|
||||
case EHOSTUNREACH:
|
||||
return MC_DRV_ERR_DAEMON_UNREACHABLE;
|
||||
case ENOENT:
|
||||
return MC_DRV_ERR_INVALID_DEVICE_FILE;
|
||||
case EINVAL:
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
case EPROTO:
|
||||
return MC_DRV_ERR_KERNEL_MODULE;
|
||||
case ECOMM:
|
||||
return MC_DRV_INFO_NOTIFICATION;
|
||||
case EUNATCH:
|
||||
return MC_DRV_ERR_NQ_FAILED;
|
||||
case ERESTARTSYS:
|
||||
return MC_DRV_ERR_INTERRUPTED_BY_SIGNAL;
|
||||
default:
|
||||
mc_dev_devel("error is %d", err);
|
||||
return MC_DRV_ERR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool is_valid_device(u32 device_id)
|
||||
{
|
||||
return device_id == MC_DEVICE_ID_DEFAULT;
|
||||
}
|
||||
|
||||
static struct tee_client *client;
|
||||
static int open_count;
|
||||
static DEFINE_MUTEX(dev_mutex); /* Lock for the device */
|
||||
|
||||
static bool clientlib_client_get(void)
|
||||
{
|
||||
int ret = true;
|
||||
|
||||
mutex_lock(&dev_mutex);
|
||||
if (!client)
|
||||
ret = false;
|
||||
else
|
||||
client_get(client);
|
||||
|
||||
mutex_unlock(&dev_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void clientlib_client_put(void)
|
||||
{
|
||||
mutex_lock(&dev_mutex);
|
||||
if (client_put(client))
|
||||
client = NULL;
|
||||
|
||||
mutex_unlock(&dev_mutex);
|
||||
}
|
||||
|
||||
enum mc_result mc_open_device(u32 device_id)
|
||||
{
|
||||
enum mc_result mc_result = MC_DRV_OK;
|
||||
int ret;
|
||||
|
||||
/* Check parameters */
|
||||
if (!is_valid_device(device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
mutex_lock(&dev_mutex);
|
||||
/* Make sure TEE was started */
|
||||
ret = mc_wait_tee_start();
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "TEE failed to start, now or in the past");
|
||||
mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!open_count)
|
||||
client = client_create(true);
|
||||
|
||||
if (client) {
|
||||
open_count++;
|
||||
mc_dev_devel("successfully opened the device");
|
||||
} else {
|
||||
mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
|
||||
mc_dev_err(-ENOMEM, "could not open device");
|
||||
}
|
||||
|
||||
end:
|
||||
mutex_unlock(&dev_mutex);
|
||||
return mc_result;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_open_device);
|
||||
|
||||
enum mc_result mc_close_device(u32 device_id)
|
||||
{
|
||||
enum mc_result mc_result = MC_DRV_OK;
|
||||
|
||||
/* Check parameters */
|
||||
if (!is_valid_device(device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
mutex_lock(&dev_mutex);
|
||||
if (open_count > 1) {
|
||||
open_count--;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check sessions and freeze client */
|
||||
if (client_has_sessions(client)) {
|
||||
mc_result = MC_DRV_ERR_SESSION_PENDING;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Close the device */
|
||||
client_close(client);
|
||||
open_count = 0;
|
||||
|
||||
end:
|
||||
mutex_unlock(&dev_mutex);
|
||||
clientlib_client_put();
|
||||
return mc_result;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_close_device);
|
||||
|
||||
enum mc_result mc_open_session(struct mc_session_handle *session,
|
||||
const struct mc_uuid_t *uuid,
|
||||
u8 *tci_va, u32 tci_len)
|
||||
{
|
||||
enum mc_result ret;
|
||||
|
||||
/* Check parameters */
|
||||
if (!session || !uuid)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!is_valid_device(session->device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
ret = convert(
|
||||
client_mc_open_session(client, uuid, (uintptr_t)tci_va, tci_len,
|
||||
&session->session_id));
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_open_session);
|
||||
|
||||
enum mc_result mc_open_trustlet(struct mc_session_handle *session, u32 spid,
|
||||
u8 *ta_va, u32 ta_len, u8 *tci_va, u32 tci_len)
|
||||
{
|
||||
enum mc_result ret;
|
||||
|
||||
/* Check parameters */
|
||||
if (!session || !ta_va || !ta_len)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!is_valid_device(session->device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
ret = convert(
|
||||
client_mc_open_trustlet(client, spid, (uintptr_t)ta_va, ta_len,
|
||||
(uintptr_t)tci_va, tci_len,
|
||||
&session->session_id));
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_open_trustlet);
|
||||
|
||||
enum mc_result mc_close_session(struct mc_session_handle *session)
|
||||
{
|
||||
enum mc_result ret;
|
||||
|
||||
/* Check parameters */
|
||||
if (!session)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!is_valid_device(session->device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
ret = convert(client_remove_session(client, session->session_id));
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_close_session);
|
||||
|
||||
enum mc_result mc_notify(struct mc_session_handle *session)
|
||||
{
|
||||
enum mc_result ret;
|
||||
|
||||
/* Check parameters */
|
||||
if (!session)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!is_valid_device(session->device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
ret = convert(client_notify_session(client, session->session_id));
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_notify);
|
||||
|
||||
enum mc_result mc_wait_notification(struct mc_session_handle *session,
|
||||
s32 timeout)
|
||||
{
|
||||
enum mc_result ret;
|
||||
|
||||
/* Check parameters */
|
||||
if (!session)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!is_valid_device(session->device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
do {
|
||||
ret = convert(client_waitnotif_session(client,
|
||||
session->session_id,
|
||||
timeout, false));
|
||||
} while ((timeout == MC_INFINITE_TIMEOUT) &&
|
||||
(ret == MC_DRV_ERR_INTERRUPTED_BY_SIGNAL));
|
||||
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_wait_notification);
|
||||
|
||||
enum mc_result mc_malloc_wsm(u32 device_id, u32 align, u32 len, u8 **wsm,
|
||||
u32 wsm_flags)
|
||||
{
|
||||
enum mc_result ret;
|
||||
uintptr_t va;
|
||||
|
||||
/* Check parameters */
|
||||
if (!is_valid_device(device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!len)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!wsm)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
ret = convert(client_cbuf_create(client, len, &va, NULL));
|
||||
if (ret == MC_DRV_OK)
|
||||
*wsm = (u8 *)va;
|
||||
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_malloc_wsm);
|
||||
|
||||
enum mc_result mc_free_wsm(u32 device_id, u8 *wsm)
|
||||
{
|
||||
enum mc_result ret;
|
||||
uintptr_t va = (uintptr_t)wsm;
|
||||
|
||||
/* Check parameters */
|
||||
if (!is_valid_device(device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
ret = convert(client_cbuf_free(client, va));
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_free_wsm);
|
||||
|
||||
enum mc_result mc_map(struct mc_session_handle *session, void *address,
|
||||
u32 length, struct mc_bulk_map *map_info)
|
||||
{
|
||||
enum mc_result ret;
|
||||
struct mc_ioctl_buffer buf = {
|
||||
.va = (uintptr_t)address,
|
||||
.len = length,
|
||||
.flags = MC_IO_MAP_INPUT_OUTPUT,
|
||||
};
|
||||
|
||||
/* Check parameters */
|
||||
if (!session)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!is_valid_device(session->device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!map_info)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
ret = convert(client_mc_map(client, session->session_id, NULL, &buf));
|
||||
if (ret == MC_DRV_OK) {
|
||||
map_info->secure_virt_addr = buf.sva;
|
||||
map_info->secure_virt_len = buf.len;
|
||||
}
|
||||
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_map);
|
||||
|
||||
enum mc_result mc_unmap(struct mc_session_handle *session, void *address,
|
||||
struct mc_bulk_map *map_info)
|
||||
{
|
||||
enum mc_result ret;
|
||||
struct mc_ioctl_buffer buf = {
|
||||
.va = (uintptr_t)address,
|
||||
.flags = MC_IO_MAP_INPUT_OUTPUT,
|
||||
};
|
||||
|
||||
/* Check parameters */
|
||||
if (!session)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!is_valid_device(session->device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!map_info)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
buf.len = map_info->secure_virt_len;
|
||||
buf.sva = map_info->secure_virt_addr;
|
||||
|
||||
ret = convert(client_mc_unmap(client, session->session_id, &buf));
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_unmap);
|
||||
|
||||
enum mc_result mc_get_session_error_code(struct mc_session_handle *session,
|
||||
s32 *exit_code)
|
||||
{
|
||||
enum mc_result ret;
|
||||
|
||||
/* Check parameters */
|
||||
if (!session)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!is_valid_device(session->device_id))
|
||||
return MC_DRV_ERR_UNKNOWN_DEVICE;
|
||||
|
||||
if (!exit_code)
|
||||
return MC_DRV_ERR_INVALID_PARAMETER;
|
||||
|
||||
if (!clientlib_client_get())
|
||||
return MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN;
|
||||
|
||||
/* Call core api */
|
||||
ret = convert(client_get_session_exitcode(client, session->session_id,
|
||||
exit_code));
|
||||
clientlib_client_put();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mc_get_session_error_code);
|
202
drivers/gud/MobiCoreDriver/clock.c
Normal file
202
drivers/gud/MobiCoreDriver/clock.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "clock.h"
|
||||
|
||||
static struct clk_context {
|
||||
struct clk *mc_ce_iface_clk;
|
||||
struct clk *mc_ce_core_clk;
|
||||
struct clk *mc_ce_bus_clk;
|
||||
struct clk *mc_ce_core_src_clk;
|
||||
/* Clocks are managed by Linux Kernel. No need to do anything */
|
||||
bool no_clock_support;
|
||||
} clk_ctx;
|
||||
|
||||
int mc_clock_init(void)
|
||||
{
|
||||
int ret;
|
||||
#ifdef MC_CLOCK_CORESRC_DEFAULTRATE
|
||||
int core_src_rate = MC_CLOCK_CORESRC_DEFAULTRATE;
|
||||
#ifdef MC_CRYPTO_CLOCK_CORESRC_PROPNAME
|
||||
u32 of_core_src_rate = MC_CLOCK_CORESRC_DEFAULTRATE;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef TT_CRYPTO_NO_CLOCK_SUPPORT_FEATURE
|
||||
struct device_node *np;
|
||||
|
||||
np = of_find_node_by_name(NULL, TT_CLOCK_DEVICE_NAME);
|
||||
if (!np) {
|
||||
ret = -ENOENT;
|
||||
mc_dev_err(ret, "cannot get clock device from DT");
|
||||
goto error;
|
||||
}
|
||||
|
||||
clk_ctx.no_clock_support =
|
||||
of_property_read_bool(np, TT_CRYPTO_NO_CLOCK_SUPPORT_FEATURE);
|
||||
if (clk_ctx.no_clock_support)
|
||||
return 0;
|
||||
#endif /* TT_CRYPTO_NO_CLOCK_SUPPORT_FEATURE */
|
||||
|
||||
#ifdef MC_CLOCK_CORESRC_DEFAULTRATE
|
||||
#ifdef MC_CRYPTO_CLOCK_CORESRC_PROPNAME
|
||||
/* Get core clk src */
|
||||
clk_ctx.mc_ce_core_src_clk = clk_get(g_ctx.mcd, "core_clk_src");
|
||||
if (IS_ERR_OR_NULL(clk_ctx.mc_ce_core_src_clk)) {
|
||||
ret = PTR_ERR(clk_ctx.mc_ce_core_src_clk);
|
||||
mc_dev_err(ret, "cannot get core src clock");
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MC_CRYPTO_CLOCK_CORESRC_PROPNAME
|
||||
ret = of_property_read_u32(g_ctx.mcd->of_node,
|
||||
MC_CRYPTO_CLOCK_CORESRC_PROPNAME,
|
||||
&of_core_src_rate);
|
||||
if (ret) {
|
||||
core_src_rate = MC_CLOCK_CORESRC_DEFAULTRATE;
|
||||
mc_dev_info("cannot get clock frequency from DT, use %d",
|
||||
core_src_rate);
|
||||
} else {
|
||||
core_src_rate = of_core_src_rate;
|
||||
}
|
||||
|
||||
#endif /* MC_CRYPTO_CLOCK_CORESRC_PROPNAME */
|
||||
|
||||
ret = clk_set_rate(clk_ctx.mc_ce_core_src_clk, core_src_rate);
|
||||
if (ret) {
|
||||
clk_put(clk_ctx.mc_ce_core_src_clk);
|
||||
clk_ctx.mc_ce_core_src_clk = NULL;
|
||||
mc_dev_err(ret, "cannot set core clock src rate");
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
}
|
||||
#endif /* MC_CLOCK_CORESRC_DEFAULTRATE */
|
||||
|
||||
/* Get core clk */
|
||||
clk_ctx.mc_ce_core_clk = clk_get(g_ctx.mcd, "core_clk");
|
||||
if (IS_ERR(clk_ctx.mc_ce_core_clk)) {
|
||||
ret = PTR_ERR(clk_ctx.mc_ce_core_clk);
|
||||
mc_dev_err(ret, "cannot get core clock");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get Interface clk */
|
||||
clk_ctx.mc_ce_iface_clk = clk_get(g_ctx.mcd, "iface_clk");
|
||||
if (IS_ERR(clk_ctx.mc_ce_iface_clk)) {
|
||||
clk_put(clk_ctx.mc_ce_core_clk);
|
||||
ret = PTR_ERR(clk_ctx.mc_ce_iface_clk);
|
||||
mc_dev_err(ret, "cannot get iface clock");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get AXI clk */
|
||||
clk_ctx.mc_ce_bus_clk = clk_get(g_ctx.mcd, "bus_clk");
|
||||
if (IS_ERR(clk_ctx.mc_ce_bus_clk)) {
|
||||
clk_put(clk_ctx.mc_ce_iface_clk);
|
||||
clk_put(clk_ctx.mc_ce_core_clk);
|
||||
ret = PTR_ERR(clk_ctx.mc_ce_bus_clk);
|
||||
mc_dev_err(ret, "cannot get AXI bus clock");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
clk_ctx.mc_ce_core_clk = NULL;
|
||||
clk_ctx.mc_ce_iface_clk = NULL;
|
||||
clk_ctx.mc_ce_bus_clk = NULL;
|
||||
clk_ctx.mc_ce_core_src_clk = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mc_clock_exit(void)
|
||||
{
|
||||
if (clk_ctx.no_clock_support)
|
||||
return;
|
||||
|
||||
if (clk_ctx.mc_ce_iface_clk)
|
||||
clk_put(clk_ctx.mc_ce_iface_clk);
|
||||
|
||||
if (clk_ctx.mc_ce_core_clk)
|
||||
clk_put(clk_ctx.mc_ce_core_clk);
|
||||
|
||||
if (clk_ctx.mc_ce_bus_clk)
|
||||
clk_put(clk_ctx.mc_ce_bus_clk);
|
||||
|
||||
if (clk_ctx.mc_ce_core_src_clk)
|
||||
clk_put(clk_ctx.mc_ce_core_src_clk);
|
||||
}
|
||||
|
||||
int mc_clock_enable(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (clk_ctx.no_clock_support)
|
||||
return 0;
|
||||
|
||||
ret = clk_prepare_enable(clk_ctx.mc_ce_core_clk);
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "cannot enable core clock");
|
||||
goto err_core;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(clk_ctx.mc_ce_iface_clk);
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "cannot enable interface clock");
|
||||
goto err_iface;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(clk_ctx.mc_ce_bus_clk);
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "cannot enable bus clock");
|
||||
goto err_bus;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_bus:
|
||||
clk_disable_unprepare(clk_ctx.mc_ce_iface_clk);
|
||||
err_iface:
|
||||
clk_disable_unprepare(clk_ctx.mc_ce_core_clk);
|
||||
err_core:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mc_clock_disable(void)
|
||||
{
|
||||
if (clk_ctx.no_clock_support)
|
||||
return;
|
||||
|
||||
if (clk_ctx.mc_ce_iface_clk)
|
||||
clk_disable_unprepare(clk_ctx.mc_ce_iface_clk);
|
||||
|
||||
if (clk_ctx.mc_ce_core_clk)
|
||||
clk_disable_unprepare(clk_ctx.mc_ce_core_clk);
|
||||
|
||||
if (clk_ctx.mc_ce_bus_clk)
|
||||
clk_disable_unprepare(clk_ctx.mc_ce_bus_clk);
|
||||
}
|
||||
|
||||
#endif /* MC_CRYPTO_CLOCK_MANAGEMENT */
|
54
drivers/gud/MobiCoreDriver/clock.h
Normal file
54
drivers/gud/MobiCoreDriver/clock.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_CLOCK_H_
|
||||
#define _MC_CLOCK_H_
|
||||
|
||||
#include "platform.h" /* MC_CRYPTO_CLOCK_MANAGEMENT */
|
||||
|
||||
#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
|
||||
|
||||
/* Initialize secure crypto clocks */
|
||||
int mc_clock_init(void);
|
||||
/* Free secure crypto clocks */
|
||||
void mc_clock_exit(void);
|
||||
/* Enable secure crypto clocks */
|
||||
int mc_clock_enable(void);
|
||||
/* Disable secure crypto clocks */
|
||||
void mc_clock_disable(void);
|
||||
|
||||
#else /* MC_CRYPTO_CLOCK_MANAGEMENT */
|
||||
|
||||
static inline int mc_clock_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mc_clock_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mc_clock_enable(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mc_clock_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !MC_CRYPTO_CLOCK_MANAGEMENT */
|
||||
|
||||
#endif /* _MC_CLOCK_H_ */
|
379
drivers/gud/MobiCoreDriver/fastcall.c
Normal file
379
drivers/gud/MobiCoreDriver/fastcall.c
Normal file
|
@ -0,0 +1,379 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/sched.h> /* local_clock */
|
||||
#include <linux/version.h>
|
||||
#if KERNEL_VERSION(4, 11, 0) <= LINUX_VERSION_CODE
|
||||
#include <linux/sched/clock.h> /* local_clock */
|
||||
#endif
|
||||
|
||||
#include "mcifc.h"
|
||||
|
||||
#include "platform.h" /* MC_SMC_FASTCALL */
|
||||
#include "main.h"
|
||||
#include "fastcall.h"
|
||||
|
||||
/* Use the arch_extension sec pseudo op before switching to secure world */
|
||||
#if defined(__GNUC__) && \
|
||||
defined(__GNUC_MINOR__) && \
|
||||
defined(__GNUC_PATCHLEVEL__) && \
|
||||
((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)) \
|
||||
>= 40502
|
||||
#ifndef CONFIG_ARM64
|
||||
#define MC_ARCH_EXTENSION_SEC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Base for all fastcalls, do not use outside of other structs */
|
||||
union fc_common {
|
||||
struct {
|
||||
u32 cmd;
|
||||
u32 param[3];
|
||||
} in;
|
||||
|
||||
struct {
|
||||
u32 resp;
|
||||
u32 ret;
|
||||
u32 param[2];
|
||||
} out;
|
||||
};
|
||||
|
||||
union fc_init {
|
||||
union fc_common common;
|
||||
|
||||
struct {
|
||||
u32 cmd;
|
||||
u32 base;
|
||||
u32 nq_info;
|
||||
u32 mcp_info;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
u32 resp;
|
||||
u32 ret;
|
||||
u32 flags;
|
||||
u32 rfu;
|
||||
} out;
|
||||
};
|
||||
|
||||
union fc_info {
|
||||
union fc_common common;
|
||||
|
||||
struct {
|
||||
u32 cmd;
|
||||
u32 ext_info_id;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
u32 resp;
|
||||
u32 ret;
|
||||
u32 state;
|
||||
u32 ext_info;
|
||||
} out;
|
||||
};
|
||||
|
||||
union fc_trace {
|
||||
union fc_common common;
|
||||
|
||||
struct {
|
||||
u32 cmd;
|
||||
u32 buffer_low;
|
||||
u32 buffer_high;
|
||||
u32 size;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
u32 resp;
|
||||
u32 ret;
|
||||
} out;
|
||||
};
|
||||
|
||||
union fc_nsiq {
|
||||
union fc_common common;
|
||||
|
||||
struct {
|
||||
u32 cmd;
|
||||
u32 debug_ret;
|
||||
u32 debug_session_id;
|
||||
u32 debug_payload;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
u32 resp;
|
||||
u32 ret;
|
||||
} out;
|
||||
};
|
||||
|
||||
union fc_yield {
|
||||
union fc_common common;
|
||||
|
||||
struct {
|
||||
u32 cmd;
|
||||
u32 debug_ret;
|
||||
u32 debug_timeslice;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
u32 resp;
|
||||
u32 ret;
|
||||
} out;
|
||||
};
|
||||
|
||||
/* Structure to log SMC calls */
|
||||
struct smc_log_entry {
|
||||
u64 cpu_clk;
|
||||
int cpu_id;
|
||||
union fc_common fc;
|
||||
};
|
||||
|
||||
#define SMC_LOG_SIZE 1024
|
||||
static struct smc_log_entry smc_log[SMC_LOG_SIZE];
|
||||
static int smc_log_index;
|
||||
|
||||
/*
|
||||
* convert fast call return code to linux driver module error code
|
||||
*/
|
||||
static int convert_fc_ret(u32 ret)
|
||||
{
|
||||
switch (ret) {
|
||||
case MC_FC_RET_OK:
|
||||
return 0;
|
||||
case MC_FC_RET_ERR_INVALID:
|
||||
return -EINVAL;
|
||||
case MC_FC_RET_ERR_ALREADY_INITIALIZED:
|
||||
return -EBUSY;
|
||||
default:
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* __smc() - fast call to MobiCore
|
||||
*
|
||||
* @data: pointer to fast call data
|
||||
*/
|
||||
static inline int __smc(union fc_common *fc, const char *func)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Log SMC call */
|
||||
smc_log[smc_log_index].cpu_clk = local_clock();
|
||||
smc_log[smc_log_index].cpu_id = raw_smp_processor_id();
|
||||
smc_log[smc_log_index].fc = *fc;
|
||||
if (++smc_log_index >= SMC_LOG_SIZE)
|
||||
smc_log_index = 0;
|
||||
|
||||
#ifdef MC_SMC_FASTCALL
|
||||
ret = smc_fastcall(fc, sizeof(*fc));
|
||||
#else /* MC_SMC_FASTCALL */
|
||||
{
|
||||
#ifdef CONFIG_ARM64
|
||||
/* SMC expect values in x0-x3 */
|
||||
register u64 reg0 __asm__("x0") = fc->in.cmd;
|
||||
register u64 reg1 __asm__("x1") = fc->in.param[0];
|
||||
register u64 reg2 __asm__("x2") = fc->in.param[1];
|
||||
register u64 reg3 __asm__("x3") = fc->in.param[2];
|
||||
|
||||
/*
|
||||
* According to AARCH64 SMC Calling Convention (ARM DEN 0028A),
|
||||
* section 3.1: registers x4-x17 are unpredictable/scratch
|
||||
* registers. So we have to make sure that the compiler does
|
||||
* not allocate any of those registers by letting him know that
|
||||
* the asm code might clobber them.
|
||||
*/
|
||||
__asm__ volatile (
|
||||
"smc #0\n"
|
||||
: "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
|
||||
:
|
||||
: "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11",
|
||||
"x12", "x13", "x14", "x15", "x16", "x17"
|
||||
);
|
||||
#else /* CONFIG_ARM64 */
|
||||
/* SMC expect values in r0-r3 */
|
||||
register u32 reg0 __asm__("r0") = fc->in.cmd;
|
||||
register u32 reg1 __asm__("r1") = fc->in.param[0];
|
||||
register u32 reg2 __asm__("r2") = fc->in.param[1];
|
||||
register u32 reg3 __asm__("r3") = fc->in.param[2];
|
||||
|
||||
__asm__ volatile (
|
||||
#ifdef MC_ARCH_EXTENSION_SEC
|
||||
/*
|
||||
* This pseudo op is supported and required from
|
||||
* binutils 2.21 on
|
||||
*/
|
||||
".arch_extension sec\n"
|
||||
#endif /* MC_ARCH_EXTENSION_SEC */
|
||||
"smc #0\n"
|
||||
: "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
|
||||
);
|
||||
|
||||
#endif /* !CONFIG_ARM64 */
|
||||
|
||||
/* set response */
|
||||
fc->out.resp = reg0;
|
||||
fc->out.ret = reg1;
|
||||
fc->out.param[0] = reg2;
|
||||
fc->out.param[1] = reg3;
|
||||
}
|
||||
#endif /* !MC_SMC_FASTCALL */
|
||||
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "failed for %s", func);
|
||||
} else {
|
||||
ret = convert_fc_ret(fc->out.ret);
|
||||
if (ret)
|
||||
mc_dev_err(ret, "%s failed (%x)", func, fc->out.ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define smc(__fc__) __smc(__fc__.common, __func__)
|
||||
|
||||
int fc_init(uintptr_t addr, ptrdiff_t off, size_t q_len, size_t buf_len)
|
||||
{
|
||||
union fc_init fc;
|
||||
#ifdef CONFIG_ARM64
|
||||
u32 addr_high = (u32)(addr >> 32);
|
||||
#else
|
||||
u32 addr_high = 0;
|
||||
#endif
|
||||
|
||||
/* Call the INIT fastcall to setup MobiCore initialization */
|
||||
memset(&fc, 0, sizeof(fc));
|
||||
fc.in.cmd = MC_FC_INIT;
|
||||
/* base address of mci buffer PAGE_SIZE (default is 4KB) aligned */
|
||||
fc.in.base = (u32)addr;
|
||||
/* notification buffer start/length [16:16] [start, length] */
|
||||
fc.in.nq_info = (u32)(((addr_high & 0xFFFF) << 16) | (q_len & 0xFFFF));
|
||||
/* mcp buffer start/length [16:16] [start, length] */
|
||||
fc.in.mcp_info = (u32)((off << 16) | (buf_len & 0xFFFF));
|
||||
mc_dev_devel("cmd=0x%08x, base=0x%08x, nq_info=0x%08x, mcp_info=0x%08x",
|
||||
fc.in.cmd, fc.in.base, fc.in.nq_info,
|
||||
fc.in.mcp_info);
|
||||
return smc(&fc);
|
||||
}
|
||||
|
||||
int fc_info(u32 ext_info_id, u32 *state, u32 *ext_info)
|
||||
{
|
||||
union fc_info fc;
|
||||
int ret = 0;
|
||||
|
||||
memset(&fc, 0, sizeof(fc));
|
||||
fc.in.cmd = MC_FC_INFO;
|
||||
fc.in.ext_info_id = ext_info_id;
|
||||
ret = smc(&fc);
|
||||
if (ret) {
|
||||
if (state)
|
||||
*state = MC_STATUS_NOT_INITIALIZED;
|
||||
|
||||
if (ext_info)
|
||||
*ext_info = 0;
|
||||
|
||||
mc_dev_err(ret, "failed for index %d", ext_info_id);
|
||||
} else {
|
||||
if (state)
|
||||
*state = fc.out.state;
|
||||
|
||||
if (ext_info)
|
||||
*ext_info = fc.out.ext_info;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fc_trace_init(phys_addr_t buffer, u32 size)
|
||||
{
|
||||
union fc_trace fc;
|
||||
|
||||
memset(&fc, 0, sizeof(fc));
|
||||
fc.in.cmd = MC_FC_MEM_TRACE;
|
||||
fc.in.buffer_low = (u32)buffer;
|
||||
#ifdef CONFIG_ARM64
|
||||
fc.in.buffer_high = (u32)(buffer >> 32);
|
||||
#endif
|
||||
fc.in.size = size;
|
||||
return smc(&fc);
|
||||
}
|
||||
|
||||
int fc_trace_deinit(void)
|
||||
{
|
||||
return fc_trace_init(0, 0);
|
||||
}
|
||||
|
||||
/* sid, payload only used for debug purpose */
|
||||
int fc_nsiq(u32 session_id, u32 payload)
|
||||
{
|
||||
union fc_nsiq fc;
|
||||
|
||||
memset(&fc, 0, sizeof(fc));
|
||||
fc.in.cmd = MC_SMC_N_SIQ;
|
||||
fc.in.debug_session_id = session_id;
|
||||
fc.in.debug_payload = payload;
|
||||
return smc(&fc);
|
||||
}
|
||||
|
||||
/* timeslice only used for debug purpose */
|
||||
int fc_yield(u32 timeslice)
|
||||
{
|
||||
union fc_yield fc;
|
||||
|
||||
memset(&fc, 0, sizeof(fc));
|
||||
fc.in.cmd = MC_SMC_N_YIELD;
|
||||
fc.in.debug_timeslice = timeslice;
|
||||
return smc(&fc);
|
||||
}
|
||||
|
||||
static int show_smc_log_entry(struct kasnprintf_buf *buf,
|
||||
struct smc_log_entry *entry)
|
||||
{
|
||||
return kasnprintf(buf, "%20llu %10d 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
entry->cpu_clk, entry->cpu_id, entry->fc.in.cmd,
|
||||
entry->fc.in.param[0], entry->fc.in.param[1],
|
||||
entry->fc.in.param[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump SMC log circular buffer, starting from oldest command. It is assumed
|
||||
* nothing goes in any more at this point.
|
||||
*/
|
||||
int mc_fastcall_debug_smclog(struct kasnprintf_buf *buf)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
ret = kasnprintf(buf, "%10s %20s %10s %-10s %-10s %-10s\n", "CPU id",
|
||||
"CPU clock", "command", "param1", "param2", "param3");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (smc_log[smc_log_index].cpu_clk)
|
||||
/* Buffer has wrapped around, dump end (oldest records) */
|
||||
for (i = smc_log_index; i < SMC_LOG_SIZE; i++) {
|
||||
ret = show_smc_log_entry(buf, &smc_log[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Dump first records */
|
||||
for (i = 0; i < smc_log_index; i++) {
|
||||
ret = show_smc_log_entry(buf, &smc_log[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
28
drivers/gud/MobiCoreDriver/fastcall.h
Normal file
28
drivers/gud/MobiCoreDriver/fastcall.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _TBASE_FASTCALL_H_
|
||||
#define _TBASE_FASTCALL_H_
|
||||
|
||||
int fc_init(uintptr_t base_pa, ptrdiff_t off, size_t q_len, size_t buf_len);
|
||||
int fc_info(u32 ext_info_id, u32 *state, u32 *ext_info);
|
||||
int fc_trace_init(phys_addr_t buffer, u32 size);
|
||||
int fc_trace_deinit(void);
|
||||
int fc_nsiq(u32 session_id, u32 payload);
|
||||
int fc_yield(u32 timeslice);
|
||||
|
||||
int mc_fastcall_debug_smclog(struct kasnprintf_buf *buf);
|
||||
|
||||
#endif /* _TBASE_FASTCALL_H_ */
|
69
drivers/gud/MobiCoreDriver/gptci.h
Normal file
69
drivers/gud/MobiCoreDriver/gptci.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _GP_TCI_H_
|
||||
#define _GP_TCI_H_
|
||||
|
||||
struct tee_value {
|
||||
u32 a;
|
||||
u32 b;
|
||||
};
|
||||
|
||||
struct _teec_memory_reference_internal {
|
||||
u32 sva;
|
||||
u32 len;
|
||||
u32 output_size;
|
||||
};
|
||||
|
||||
union _teec_parameter_internal {
|
||||
struct tee_value value;
|
||||
struct _teec_memory_reference_internal memref;
|
||||
};
|
||||
|
||||
enum _teec_tci_type {
|
||||
_TA_OPERATION_OPEN_SESSION = 1,
|
||||
_TA_OPERATION_INVOKE_COMMAND = 2,
|
||||
_TA_OPERATION_CLOSE_SESSION = 3,
|
||||
};
|
||||
|
||||
struct _teec_operation_internal {
|
||||
enum _teec_tci_type type;
|
||||
u32 command_id;
|
||||
u32 param_types;
|
||||
union _teec_parameter_internal params[4];
|
||||
bool is_cancelled;
|
||||
u8 rfu_padding[3];
|
||||
};
|
||||
|
||||
struct _teec_tci {
|
||||
char header[8];
|
||||
struct teec_uuid destination;
|
||||
struct _teec_operation_internal operation;
|
||||
u32 ready;
|
||||
u32 return_origin;
|
||||
u32 return_status;
|
||||
};
|
||||
|
||||
/**
|
||||
* Termination codes
|
||||
*/
|
||||
#define TA_EXIT_CODE_PANIC 300
|
||||
#define TA_EXIT_CODE_TCI 301
|
||||
#define TA_EXIT_CODE_PARAMS 302
|
||||
#define TA_EXIT_CODE_FINISHED 303
|
||||
#define TA_EXIT_CODE_SESSIONSTATE 304
|
||||
#define TA_EXIT_CODE_CREATEFAILED 305
|
||||
|
||||
#endif /* _GP_TCI_H_ */
|
1218
drivers/gud/MobiCoreDriver/iwp.c
Normal file
1218
drivers/gud/MobiCoreDriver/iwp.c
Normal file
File diff suppressed because it is too large
Load diff
124
drivers/gud/MobiCoreDriver/iwp.h
Normal file
124
drivers/gud/MobiCoreDriver/iwp.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_IWP_H_
|
||||
#define _MC_IWP_H_
|
||||
|
||||
#include "mcloadformat.h" /* struct identity */
|
||||
|
||||
#include "nq.h"
|
||||
#include "mcp.h" /* mcp_buffer_map FIXME move to nq? */
|
||||
|
||||
struct iwp_session {
|
||||
/* Notification queue session */
|
||||
struct nq_session nq_session;
|
||||
/* Session ID */
|
||||
u32 sid;
|
||||
/* IWS slot */
|
||||
u64 slot;
|
||||
/* IWS other slot needed at open */
|
||||
u64 op_slot;
|
||||
/* Sessions list (protected by iwp sessions_lock) */
|
||||
struct list_head list;
|
||||
/* Notification waiter lock */
|
||||
struct mutex notif_wait_lock; /* Only one at a time */
|
||||
/* Notification received */
|
||||
struct completion completion;
|
||||
/* Interworld struct lock */
|
||||
struct mutex iws_lock;
|
||||
/* Session state (protected by iwp sessions_lock) */
|
||||
enum iwp_session_state {
|
||||
IWP_SESSION_RUNNING,
|
||||
IWP_SESSION_CLOSE_REQUESTED,
|
||||
IWP_SESSION_CLOSED,
|
||||
} state;
|
||||
/* GP TAs have login information */
|
||||
struct identity client_identity;
|
||||
};
|
||||
|
||||
struct iwp_buffer_map {
|
||||
struct mcp_buffer_map map;
|
||||
u32 sva;
|
||||
};
|
||||
|
||||
/* Private to iwp_session structure */
|
||||
void iwp_session_init(struct iwp_session *session,
|
||||
const struct identity *identity);
|
||||
|
||||
/* Getters */
|
||||
static inline u32 iwp_session_id(struct iwp_session *session)
|
||||
{
|
||||
return session->sid;
|
||||
}
|
||||
|
||||
static inline u64 iwp_session_slot(struct iwp_session *session)
|
||||
{
|
||||
return session->slot;
|
||||
}
|
||||
|
||||
/* Convert local errno to GP return values */
|
||||
int iwp_set_ret(int ret, struct gp_return *gp_ret);
|
||||
|
||||
/* Commands */
|
||||
int iwp_register_shared_mem(
|
||||
struct tee_mmu *mmu,
|
||||
u32 *sva,
|
||||
struct gp_return *gp_ret);
|
||||
int iwp_release_shared_mem(
|
||||
struct mcp_buffer_map *map);
|
||||
int iwp_open_session_prepare(
|
||||
struct iwp_session *session,
|
||||
struct gp_operation *operation,
|
||||
struct mc_ioctl_buffer *bufs,
|
||||
struct gp_shared_memory **parents,
|
||||
struct gp_return *gp_ret);
|
||||
void iwp_open_session_abort(
|
||||
struct iwp_session *iwp_session);
|
||||
int iwp_open_session(
|
||||
struct iwp_session *iwp_session,
|
||||
const struct mc_uuid_t *uuid,
|
||||
struct gp_operation *operation,
|
||||
const struct iwp_buffer_map *maps,
|
||||
struct interworld_session *iws,
|
||||
struct tee_mmu **mmus,
|
||||
struct gp_return *gp_ret);
|
||||
int iwp_close_session(
|
||||
struct iwp_session *iwp_session);
|
||||
int iwp_invoke_command_prepare(
|
||||
struct iwp_session *iwp_session,
|
||||
u32 command_id,
|
||||
struct gp_operation *operation,
|
||||
struct mc_ioctl_buffer *bufs,
|
||||
struct gp_shared_memory **parents,
|
||||
struct gp_return *gp_ret);
|
||||
void iwp_invoke_command_abort(
|
||||
struct iwp_session *iwp_session);
|
||||
int iwp_invoke_command(
|
||||
struct iwp_session *iwp_session,
|
||||
struct gp_operation *operation,
|
||||
const struct iwp_buffer_map *maps,
|
||||
struct interworld_session *iws,
|
||||
struct tee_mmu **mmus,
|
||||
struct gp_return *gp_ret);
|
||||
int iwp_request_cancellation(
|
||||
u64 slot);
|
||||
|
||||
/* Initialisation/cleanup */
|
||||
int iwp_init(void);
|
||||
void iwp_exit(void);
|
||||
int iwp_start(void);
|
||||
void iwp_stop(void);
|
||||
|
||||
#endif /* _MC_IWP_H_ */
|
261
drivers/gud/MobiCoreDriver/logging.c
Normal file
261
drivers/gud/MobiCoreDriver/logging.c
Normal file
|
@ -0,0 +1,261 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "logging.h"
|
||||
|
||||
/* Supported log buffer version */
|
||||
#define MC_LOG_VERSION 2
|
||||
|
||||
/* Default length of the log ring buffer 256KiB */
|
||||
#define LOG_BUF_ORDER 6
|
||||
|
||||
/* Max Len of a log line for printing */
|
||||
#define LOG_LINE_SIZE 256
|
||||
|
||||
/* Definitions for log version 2 */
|
||||
#define LOG_TYPE_MASK (0x0007)
|
||||
#define LOG_TYPE_CHAR 0
|
||||
#define LOG_TYPE_INTEGER 1
|
||||
|
||||
/* Field length */
|
||||
#define LOG_LENGTH_MASK (0x00F8)
|
||||
#define LOG_LENGTH_SHIFT 3
|
||||
|
||||
/* Extra attributes */
|
||||
#define LOG_EOL (0x0100)
|
||||
#define LOG_INTEGER_DECIMAL (0x0200)
|
||||
#define LOG_INTEGER_SIGNED (0x0400)
|
||||
|
||||
/* active cpu id */
|
||||
#define LOG_CPUID_MASK (0xF000)
|
||||
#define LOG_CPUID_SHIFT 12
|
||||
|
||||
struct mc_logmsg {
|
||||
u16 ctrl; /* Type and format of data */
|
||||
u16 source; /* Unique value for each event source */
|
||||
u32 log_data; /* Value, if any */
|
||||
};
|
||||
|
||||
/* MobiCore internal trace buffer structure. */
|
||||
struct mc_trace_buf {
|
||||
u32 version; /* version of trace buffer */
|
||||
u32 length; /* length of buff */
|
||||
u32 head; /* last write position */
|
||||
u8 buff[]; /* start of the log buffer */
|
||||
};
|
||||
|
||||
static struct logging_ctx {
|
||||
struct kthread_work work;
|
||||
struct kthread_worker worker;
|
||||
struct task_struct *thread;
|
||||
union {
|
||||
struct mc_trace_buf *trace_buf; /* Circular log buffer */
|
||||
unsigned long trace_page;
|
||||
};
|
||||
u32 tail; /* MobiCore log read position */
|
||||
int thread_err;
|
||||
u16 prev_source; /* Previous Log source */
|
||||
char line[LOG_LINE_SIZE + 1];/* Log Line buffer */
|
||||
u32 line_len; /* Log Line buffer current length */
|
||||
#if KERNEL_VERSION(4, 4, 0) > LINUX_VERSION_CODE
|
||||
u32 enabled; /* Log can be disabled via debugfs */
|
||||
#else
|
||||
bool enabled; /* Log can be disabled via debugfs */
|
||||
#endif
|
||||
bool dead;
|
||||
} log_ctx;
|
||||
|
||||
static inline void log_eol(u16 source, u32 cpuid)
|
||||
{
|
||||
if (!log_ctx.line_len)
|
||||
return;
|
||||
|
||||
if (log_ctx.prev_source)
|
||||
/* TEE user-space */
|
||||
dev_info(g_ctx.mcd, "%03x(%u)|%s\n", log_ctx.prev_source,
|
||||
cpuid, log_ctx.line);
|
||||
else
|
||||
/* TEE kernel */
|
||||
dev_info(g_ctx.mcd, "mtk(%u)|%s\n", cpuid, log_ctx.line);
|
||||
log_ctx.line[0] = '\0';
|
||||
log_ctx.line_len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect chars in log_ctx.line buffer and output the buffer when it is full.
|
||||
* No locking needed because only "mobicore_log" thread updates this buffer.
|
||||
*/
|
||||
static inline void log_char(char ch, u16 source, u32 cpuid)
|
||||
{
|
||||
if (ch == '\0')
|
||||
return;
|
||||
|
||||
if (ch == '\n' || ch == '\r') {
|
||||
log_eol(source, cpuid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (log_ctx.line_len >= LOG_LINE_SIZE || source != log_ctx.prev_source)
|
||||
log_eol(source, cpuid);
|
||||
|
||||
log_ctx.line[log_ctx.line_len++] = ch;
|
||||
log_ctx.line[log_ctx.line_len] = 0;
|
||||
log_ctx.prev_source = source;
|
||||
}
|
||||
|
||||
static inline void log_string(u32 ch, u16 source, u32 cpuid)
|
||||
{
|
||||
while (ch) {
|
||||
log_char(ch & 0xFF, source, cpuid);
|
||||
ch >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void log_number(u32 format, u32 value, u16 source, u32 cpuid)
|
||||
{
|
||||
int width = (format & LOG_LENGTH_MASK) >> LOG_LENGTH_SHIFT;
|
||||
char fmt[16];
|
||||
char buffer[32];
|
||||
const char *reader = buffer;
|
||||
|
||||
if (format & LOG_INTEGER_DECIMAL)
|
||||
if (format & LOG_INTEGER_SIGNED)
|
||||
snprintf(fmt, sizeof(fmt), "%%%ud", width);
|
||||
else
|
||||
snprintf(fmt, sizeof(fmt), "%%%uu", width);
|
||||
else
|
||||
snprintf(fmt, sizeof(fmt), "%%0%ux", width);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), fmt, value);
|
||||
while (*reader)
|
||||
log_char(*reader++, source, cpuid);
|
||||
}
|
||||
|
||||
static inline int log_msg(void *data)
|
||||
{
|
||||
struct mc_logmsg *msg = (struct mc_logmsg *)data;
|
||||
int log_type = msg->ctrl & LOG_TYPE_MASK;
|
||||
int cpuid = ((msg->ctrl & LOG_CPUID_MASK) >> LOG_CPUID_SHIFT);
|
||||
|
||||
switch (log_type) {
|
||||
case LOG_TYPE_CHAR:
|
||||
log_string(msg->log_data, msg->source, cpuid);
|
||||
break;
|
||||
case LOG_TYPE_INTEGER:
|
||||
log_number(msg->ctrl, msg->log_data, msg->source, cpuid);
|
||||
break;
|
||||
}
|
||||
if (msg->ctrl & LOG_EOL)
|
||||
log_eol(msg->source, cpuid);
|
||||
|
||||
return sizeof(*msg);
|
||||
}
|
||||
|
||||
static void logging_worker(struct kthread_work *work)
|
||||
{
|
||||
static DEFINE_MUTEX(local_mutex);
|
||||
|
||||
mutex_lock(&local_mutex);
|
||||
while (log_ctx.trace_buf->head != log_ctx.tail) {
|
||||
if (log_ctx.trace_buf->version != MC_LOG_VERSION) {
|
||||
mc_dev_err(-EINVAL, "Bad log data v%d (exp. v%d), stop",
|
||||
log_ctx.trace_buf->version, MC_LOG_VERSION);
|
||||
log_ctx.dead = true;
|
||||
break;
|
||||
}
|
||||
|
||||
log_ctx.tail += log_msg(&log_ctx.trace_buf->buff[log_ctx.tail]);
|
||||
/* Wrap over if no space left for a complete message */
|
||||
if ((log_ctx.tail + sizeof(struct mc_logmsg)) >
|
||||
log_ctx.trace_buf->length)
|
||||
log_ctx.tail = 0;
|
||||
}
|
||||
mutex_unlock(&local_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wake up the log reader thread
|
||||
* This should be called from the places where calls into MobiCore have
|
||||
* generated some logs(eg, yield, SIQ...)
|
||||
*/
|
||||
void logging_run(void)
|
||||
{
|
||||
if (log_ctx.enabled && !log_ctx.dead &&
|
||||
log_ctx.trace_buf->head != log_ctx.tail)
|
||||
#if KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE
|
||||
queue_kthread_work(&log_ctx.worker, &log_ctx.work);
|
||||
#else
|
||||
kthread_queue_work(&log_ctx.worker, &log_ctx.work);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup MobiCore kernel log. It assumes it's running on CORE 0!
|
||||
* The fastcall will complain if that is not the case!
|
||||
*/
|
||||
int logging_init(phys_addr_t *buffer, u32 *size)
|
||||
{
|
||||
/*
|
||||
* We are going to map this buffer into virtual address space in SWd.
|
||||
* To reduce complexity there, we use a contiguous buffer.
|
||||
*/
|
||||
log_ctx.trace_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO,
|
||||
LOG_BUF_ORDER);
|
||||
if (!log_ctx.trace_page)
|
||||
return -ENOMEM;
|
||||
|
||||
*buffer = virt_to_phys((void *)(log_ctx.trace_page));
|
||||
*size = BIT(LOG_BUF_ORDER) * PAGE_SIZE;
|
||||
|
||||
/* Logging thread */
|
||||
#if KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE
|
||||
init_kthread_work(&log_ctx.work, logging_worker);
|
||||
init_kthread_worker(&log_ctx.worker);
|
||||
#else
|
||||
kthread_init_work(&log_ctx.work, logging_worker);
|
||||
kthread_init_worker(&log_ctx.worker);
|
||||
#endif
|
||||
log_ctx.thread = kthread_create(kthread_worker_fn, &log_ctx.worker,
|
||||
"tee_log");
|
||||
if (IS_ERR(log_ctx.thread))
|
||||
return PTR_ERR(log_ctx.thread);
|
||||
|
||||
wake_up_process(log_ctx.thread);
|
||||
|
||||
/* Debugfs switch */
|
||||
log_ctx.enabled = true;
|
||||
debugfs_create_bool("swd_debug", 0600, g_ctx.debug_dir,
|
||||
&log_ctx.enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void logging_exit(bool buffer_busy)
|
||||
{
|
||||
/*
|
||||
* This is not racey as the only caller for logging_run is the
|
||||
* scheduler which gets stopped before us, and long before we exit.
|
||||
*/
|
||||
kthread_stop(log_ctx.thread);
|
||||
if (!buffer_busy)
|
||||
free_pages(log_ctx.trace_page, LOG_BUF_ORDER);
|
||||
}
|
23
drivers/gud/MobiCoreDriver/logging.h
Normal file
23
drivers/gud/MobiCoreDriver/logging.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_LOGGING_H_
|
||||
#define _MC_LOGGING_H_
|
||||
|
||||
void logging_run(void);
|
||||
int logging_init(phys_addr_t *buffer, u32 *size);
|
||||
void logging_exit(bool buffer_busy);
|
||||
|
||||
#endif /* _MC_LOGGING_H_ */
|
743
drivers/gud/MobiCoreDriver/main.c
Normal file
743
drivers/gud/MobiCoreDriver/main.c
Normal file
|
@ -0,0 +1,743 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2013-2020 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include "mc_user.h"
|
||||
#include "mc_admin.h" /* MC_ADMIN_DEVNODE */
|
||||
|
||||
#include "platform.h" /* MC_PM_RUNTIME */
|
||||
#include "main.h"
|
||||
#include "arm.h"
|
||||
#include "admin.h"
|
||||
#include "user.h"
|
||||
#include "iwp.h"
|
||||
#include "mcp.h"
|
||||
#include "nq.h"
|
||||
#include "client.h"
|
||||
#include "xen_be.h"
|
||||
#include "xen_fe.h"
|
||||
#include "build_tag.h"
|
||||
|
||||
/* Default entry for our driver in device tree */
|
||||
#ifndef MC_DEVICE_PROPNAME
|
||||
#define MC_DEVICE_PROPNAME "arm,mcd"
|
||||
#endif
|
||||
|
||||
/* Define a MobiCore device structure for use with dev_debug() etc */
|
||||
static struct device_driver driver = {
|
||||
.name = "Trustonic"
|
||||
};
|
||||
|
||||
static struct device device = {
|
||||
.driver = &driver
|
||||
};
|
||||
|
||||
struct mc_device_ctx g_ctx = {
|
||||
.mcd = &device
|
||||
};
|
||||
|
||||
static struct {
|
||||
/* Device tree compatibility */
|
||||
bool use_platform_driver;
|
||||
/* TEE start return code mutex */
|
||||
struct mutex start_mutex;
|
||||
/* TEE start return code */
|
||||
int start_ret;
|
||||
#ifdef MC_PM_RUNTIME
|
||||
/* Whether hibernation succeeded */
|
||||
bool did_hibernate;
|
||||
/* Reboot notifications */
|
||||
struct notifier_block reboot_notifier;
|
||||
/* PM notifications */
|
||||
struct notifier_block pm_notifier;
|
||||
#endif
|
||||
/* Devices */
|
||||
dev_t device;
|
||||
struct class *class;
|
||||
/* Admin device */
|
||||
struct cdev admin_cdev;
|
||||
/* User device */
|
||||
dev_t user_dev;
|
||||
struct cdev user_cdev;
|
||||
/* Debug counters */
|
||||
struct mutex struct_counters_buf_mutex;
|
||||
char struct_counters_buf[256];
|
||||
int struct_counters_buf_len;
|
||||
} main_ctx;
|
||||
|
||||
static int mobicore_start(void);
|
||||
static void mobicore_stop(void);
|
||||
|
||||
int kasnprintf(struct kasnprintf_buf *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int max_size = buf->size - buf->off;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
i = vsnprintf(buf->buf + buf->off, max_size, fmt, args);
|
||||
if (i >= max_size) {
|
||||
int new_size = PAGE_ALIGN(buf->size + i + 1);
|
||||
char *new_buf = krealloc(buf->buf, new_size, buf->gfp);
|
||||
|
||||
if (!new_buf) {
|
||||
i = -ENOMEM;
|
||||
} else {
|
||||
buf->buf = new_buf;
|
||||
buf->size = new_size;
|
||||
max_size = buf->size - buf->off;
|
||||
i = vsnprintf(buf->buf + buf->off, max_size, fmt, args);
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
buf->off += i;
|
||||
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void kasnprintf_buf_reset(struct kasnprintf_buf *buf)
|
||||
{
|
||||
kfree(buf->buf);
|
||||
buf->buf = NULL;
|
||||
buf->size = 0;
|
||||
buf->off = 0;
|
||||
}
|
||||
|
||||
ssize_t debug_generic_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos,
|
||||
int (*function)(struct kasnprintf_buf *buf))
|
||||
{
|
||||
struct kasnprintf_buf *buf = file->private_data;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&buf->mutex);
|
||||
/* Add/update buffer */
|
||||
if (!*ppos) {
|
||||
kasnprintf_buf_reset(buf);
|
||||
ret = function(buf);
|
||||
if (ret < 0) {
|
||||
kasnprintf_buf_reset(buf);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf->buf,
|
||||
buf->off);
|
||||
|
||||
end:
|
||||
mutex_unlock(&buf->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int debug_generic_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct kasnprintf_buf *buf;
|
||||
|
||||
file->private_data = kzalloc(sizeof(*buf), GFP_KERNEL);
|
||||
if (!file->private_data)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = file->private_data;
|
||||
mutex_init(&buf->mutex);
|
||||
buf->gfp = GFP_KERNEL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int debug_generic_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct kasnprintf_buf *buf = file->private_data;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
kasnprintf_buf_reset(buf);
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t debug_structs_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return debug_generic_read(file, user_buf, count, ppos,
|
||||
clients_debug_structs);
|
||||
}
|
||||
|
||||
static const struct file_operations debug_structs_ops = {
|
||||
.read = debug_structs_read,
|
||||
.llseek = default_llseek,
|
||||
.open = debug_generic_open,
|
||||
.release = debug_generic_release,
|
||||
};
|
||||
|
||||
static ssize_t debug_struct_counters_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
if (!*ppos) {
|
||||
int ret;
|
||||
|
||||
mutex_lock(&main_ctx.struct_counters_buf_mutex);
|
||||
ret = snprintf(main_ctx.struct_counters_buf,
|
||||
sizeof(main_ctx.struct_counters_buf),
|
||||
"clients: %d\n"
|
||||
"cbufs: %d\n"
|
||||
"cwsms: %d\n"
|
||||
"sessions: %d\n"
|
||||
"swsms: %d\n"
|
||||
"mmus: %d\n"
|
||||
"maps: %d\n"
|
||||
"slots: %d\n"
|
||||
"xen maps: %d\n"
|
||||
"xen fes: %d\n",
|
||||
atomic_read(&g_ctx.c_clients),
|
||||
atomic_read(&g_ctx.c_cbufs),
|
||||
atomic_read(&g_ctx.c_cwsms),
|
||||
atomic_read(&g_ctx.c_sessions),
|
||||
atomic_read(&g_ctx.c_wsms),
|
||||
atomic_read(&g_ctx.c_mmus),
|
||||
atomic_read(&g_ctx.c_maps),
|
||||
atomic_read(&g_ctx.c_slots),
|
||||
atomic_read(&g_ctx.c_xen_maps),
|
||||
atomic_read(&g_ctx.c_xen_fes));
|
||||
mutex_unlock(&main_ctx.struct_counters_buf_mutex);
|
||||
if (ret > 0)
|
||||
main_ctx.struct_counters_buf_len = ret;
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
main_ctx.struct_counters_buf,
|
||||
main_ctx.struct_counters_buf_len);
|
||||
}
|
||||
|
||||
static const struct file_operations debug_struct_counters_ops = {
|
||||
.read = debug_struct_counters_read,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static inline int device_user_init(void)
|
||||
{
|
||||
struct device *dev;
|
||||
int ret = 0;
|
||||
|
||||
main_ctx.user_dev = MKDEV(MAJOR(main_ctx.device), 1);
|
||||
/* Create the user node */
|
||||
mc_user_init(&main_ctx.user_cdev);
|
||||
ret = cdev_add(&main_ctx.user_cdev, main_ctx.user_dev, 1);
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "user cdev_add failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
main_ctx.user_cdev.owner = THIS_MODULE;
|
||||
dev = device_create(main_ctx.class, NULL, main_ctx.user_dev, NULL,
|
||||
MC_USER_DEVNODE);
|
||||
if (IS_ERR(dev)) {
|
||||
ret = PTR_ERR(dev);
|
||||
cdev_del(&main_ctx.user_cdev);
|
||||
mc_dev_err(ret, "user device_create failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create debugfs structs entry */
|
||||
debugfs_create_file("structs", 0400, g_ctx.debug_dir, NULL,
|
||||
&debug_structs_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void device_user_exit(void)
|
||||
{
|
||||
device_destroy(main_ctx.class, main_ctx.user_dev);
|
||||
cdev_del(&main_ctx.user_cdev);
|
||||
}
|
||||
|
||||
#ifdef MC_PM_RUNTIME
|
||||
static int reboot_notifier(struct notifier_block *nb, unsigned long event,
|
||||
void *dummy)
|
||||
{
|
||||
switch (event) {
|
||||
case SYS_HALT:
|
||||
case SYS_POWER_OFF:
|
||||
main_ctx.did_hibernate = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int suspend_notifier(struct notifier_block *nb, unsigned long event,
|
||||
void *dummy)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
main_ctx.did_hibernate = false;
|
||||
switch (event) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
return nq_suspend();
|
||||
case PM_POST_SUSPEND:
|
||||
return nq_resume();
|
||||
#ifdef TRUSTONIC_HIBERNATION_SUPPORT
|
||||
case PM_HIBERNATION_PREPARE:
|
||||
/* Try to stop the TEE nicely (ignore failure) */
|
||||
nq_stop();
|
||||
break;
|
||||
case PM_POST_HIBERNATION:
|
||||
if (main_ctx.did_hibernate) {
|
||||
/* Really did hibernate */
|
||||
client_cleanup();
|
||||
main_ctx.start_ret = TEE_START_NOT_TRIGGERED;
|
||||
return mobicore_start();
|
||||
}
|
||||
|
||||
/* Did not hibernate, just restart the TEE */
|
||||
ret = nq_start();
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* MC_PM_RUNTIME */
|
||||
|
||||
static inline int check_version(void)
|
||||
{
|
||||
struct mc_version_info version_info;
|
||||
int ret;
|
||||
|
||||
/* Must be called before creating the user device node to avoid race */
|
||||
ret = mcp_get_version(&version_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* CMP version is meaningless in this case and is thus not printed */
|
||||
mc_dev_info("\n"
|
||||
" product_id = %s\n"
|
||||
" version_mci = 0x%08x\n"
|
||||
" version_so = 0x%08x\n"
|
||||
" version_mclf = 0x%08x\n"
|
||||
" version_container = 0x%08x\n"
|
||||
" version_mc_config = 0x%08x\n"
|
||||
" version_tl_api = 0x%08x\n"
|
||||
" version_dr_api = 0x%08x\n"
|
||||
" version_nwd = 0x%08x\n",
|
||||
version_info.product_id,
|
||||
version_info.version_mci,
|
||||
version_info.version_so,
|
||||
version_info.version_mclf,
|
||||
version_info.version_container,
|
||||
version_info.version_mc_config,
|
||||
version_info.version_tl_api,
|
||||
version_info.version_dr_api,
|
||||
version_info.version_nwd);
|
||||
|
||||
/* Determine which features are supported */
|
||||
if (version_info.version_mci != MC_VERSION(1, 7)) {
|
||||
ret = -EHOSTDOWN;
|
||||
mc_dev_err(ret, "TEE incompatible with this driver");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mobicore_start_domu(void)
|
||||
{
|
||||
mutex_lock(&main_ctx.start_mutex);
|
||||
if (main_ctx.start_ret != TEE_START_NOT_TRIGGERED)
|
||||
goto end;
|
||||
|
||||
/* Must be called before creating the user device node to avoid race */
|
||||
main_ctx.start_ret = check_version();
|
||||
if (main_ctx.start_ret)
|
||||
goto end;
|
||||
|
||||
main_ctx.start_ret = device_user_init();
|
||||
end:
|
||||
mutex_unlock(&main_ctx.start_mutex);
|
||||
return main_ctx.start_ret;
|
||||
}
|
||||
|
||||
static int mobicore_start(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&main_ctx.start_mutex);
|
||||
if (main_ctx.start_ret != TEE_START_NOT_TRIGGERED)
|
||||
goto got_ret;
|
||||
|
||||
ret = nq_start();
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "NQ start failed");
|
||||
goto err_nq;
|
||||
}
|
||||
|
||||
ret = mcp_start();
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "MCP start failed");
|
||||
goto err_mcp;
|
||||
}
|
||||
|
||||
ret = iwp_start();
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "IWP start failed");
|
||||
goto err_iwp;
|
||||
}
|
||||
|
||||
/* Must be called before creating the user device node to avoid race */
|
||||
ret = check_version();
|
||||
if (ret)
|
||||
goto err_version;
|
||||
|
||||
#ifdef MC_PM_RUNTIME
|
||||
main_ctx.reboot_notifier.notifier_call = reboot_notifier;
|
||||
ret = register_reboot_notifier(&main_ctx.reboot_notifier);
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "reboot notifier registration failed");
|
||||
goto err_pm_notif;
|
||||
}
|
||||
|
||||
main_ctx.pm_notifier.notifier_call = suspend_notifier;
|
||||
ret = register_pm_notifier(&main_ctx.pm_notifier);
|
||||
if (ret) {
|
||||
unregister_reboot_notifier(&main_ctx.reboot_notifier);
|
||||
mc_dev_err(ret, "PM notifier register failed");
|
||||
goto err_pm_notif;
|
||||
}
|
||||
#if KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE
|
||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "Trustonic",
|
||||
nq_cpu_on, nq_cpu_off);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (is_xen_dom0()) {
|
||||
ret = xen_be_init();
|
||||
if (ret)
|
||||
goto err_xen_be;
|
||||
}
|
||||
|
||||
ret = device_user_init();
|
||||
if (ret)
|
||||
goto err_device_user;
|
||||
|
||||
main_ctx.start_ret = 0;
|
||||
goto got_ret;
|
||||
|
||||
err_device_user:
|
||||
if (is_xen_dom0())
|
||||
xen_be_exit();
|
||||
err_xen_be:
|
||||
#ifdef MC_PM_RUNTIME
|
||||
unregister_reboot_notifier(&main_ctx.reboot_notifier);
|
||||
unregister_pm_notifier(&main_ctx.pm_notifier);
|
||||
err_pm_notif:
|
||||
#endif
|
||||
err_version:
|
||||
iwp_stop();
|
||||
err_iwp:
|
||||
mcp_stop();
|
||||
err_mcp:
|
||||
nq_stop();
|
||||
err_nq:
|
||||
main_ctx.start_ret = ret;
|
||||
got_ret:
|
||||
mutex_unlock(&main_ctx.start_mutex);
|
||||
return main_ctx.start_ret;
|
||||
}
|
||||
|
||||
static void mobicore_stop(void)
|
||||
{
|
||||
device_user_exit();
|
||||
if (is_xen_dom0())
|
||||
xen_be_exit();
|
||||
|
||||
if (!is_xen_domu()) {
|
||||
#ifdef MC_PM_RUNTIME
|
||||
unregister_reboot_notifier(&main_ctx.reboot_notifier);
|
||||
unregister_pm_notifier(&main_ctx.pm_notifier);
|
||||
#endif
|
||||
iwp_stop();
|
||||
mcp_stop();
|
||||
nq_stop();
|
||||
}
|
||||
}
|
||||
|
||||
int mc_wait_tee_start(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&main_ctx.start_mutex);
|
||||
while (main_ctx.start_ret == TEE_START_NOT_TRIGGERED) {
|
||||
mutex_unlock(&main_ctx.start_mutex);
|
||||
ssleep(1);
|
||||
mutex_lock(&main_ctx.start_mutex);
|
||||
}
|
||||
|
||||
ret = main_ctx.start_ret;
|
||||
mutex_unlock(&main_ctx.start_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int device_common_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = alloc_chrdev_region(&main_ctx.device, 0, 2, "trustonic_tee");
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "alloc_chrdev_region failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
main_ctx.class = class_create(THIS_MODULE, "trustonic_tee");
|
||||
if (IS_ERR(main_ctx.class)) {
|
||||
ret = PTR_ERR(main_ctx.class);
|
||||
mc_dev_err(ret, "class_create failed");
|
||||
unregister_chrdev_region(main_ctx.device, 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void device_common_exit(void)
|
||||
{
|
||||
class_destroy(main_ctx.class);
|
||||
unregister_chrdev_region(main_ctx.device, 2);
|
||||
}
|
||||
|
||||
static inline int device_admin_init(void)
|
||||
{
|
||||
struct device *dev;
|
||||
int ret = 0;
|
||||
|
||||
/* Create the ADMIN node */
|
||||
ret = mc_admin_init(&main_ctx.admin_cdev, mobicore_start,
|
||||
mobicore_stop);
|
||||
if (ret)
|
||||
goto err_init;
|
||||
|
||||
ret = cdev_add(&main_ctx.admin_cdev, main_ctx.device, 1);
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "admin cdev_add failed");
|
||||
goto err_cdev;
|
||||
}
|
||||
|
||||
main_ctx.admin_cdev.owner = THIS_MODULE;
|
||||
dev = device_create(main_ctx.class, NULL, main_ctx.device, NULL,
|
||||
MC_ADMIN_DEVNODE);
|
||||
if (IS_ERR(dev)) {
|
||||
ret = PTR_ERR(dev);
|
||||
mc_dev_err(ret, "admin device_create failed");
|
||||
goto err_device;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_device:
|
||||
cdev_del(&main_ctx.admin_cdev);
|
||||
err_cdev:
|
||||
mc_admin_exit();
|
||||
err_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void device_admin_exit(void)
|
||||
{
|
||||
device_destroy(main_ctx.class, main_ctx.device);
|
||||
cdev_del(&main_ctx.admin_cdev);
|
||||
mc_admin_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by the kernel during startup or by a insmod command.
|
||||
* This device is installed and registered as cdev, then interrupt and
|
||||
* queue handling is set up
|
||||
*/
|
||||
static int mobicore_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (pdev)
|
||||
g_ctx.mcd->of_node = pdev->dev.of_node;
|
||||
|
||||
#ifdef MOBICORE_COMPONENT_BUILD_TAG
|
||||
mc_dev_info("MobiCore %s", MOBICORE_COMPONENT_BUILD_TAG);
|
||||
#endif
|
||||
/* Hardware does not support ARM TrustZone -> Cannot continue! */
|
||||
if (!is_xen_domu() && !has_security_extensions()) {
|
||||
ret = -ENODEV;
|
||||
mc_dev_err(ret, "Hardware doesn't support ARM TrustZone!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Running in secure mode -> Cannot load the driver! */
|
||||
if (is_secure_mode()) {
|
||||
ret = -ENODEV;
|
||||
mc_dev_err(ret, "Running in secure MODE!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Make sure we can create debugfs entries */
|
||||
g_ctx.debug_dir = debugfs_create_dir("trustonic_tee", NULL);
|
||||
|
||||
/* Initialize debug counters */
|
||||
atomic_set(&g_ctx.c_clients, 0);
|
||||
atomic_set(&g_ctx.c_cbufs, 0);
|
||||
atomic_set(&g_ctx.c_cwsms, 0);
|
||||
atomic_set(&g_ctx.c_sessions, 0);
|
||||
atomic_set(&g_ctx.c_wsms, 0);
|
||||
atomic_set(&g_ctx.c_mmus, 0);
|
||||
atomic_set(&g_ctx.c_maps, 0);
|
||||
atomic_set(&g_ctx.c_slots, 0);
|
||||
atomic_set(&g_ctx.c_xen_maps, 0);
|
||||
atomic_set(&g_ctx.c_xen_fes, 0);
|
||||
main_ctx.start_ret = TEE_START_NOT_TRIGGERED;
|
||||
mutex_init(&main_ctx.start_mutex);
|
||||
mutex_init(&main_ctx.struct_counters_buf_mutex);
|
||||
/* Create debugfs info entries */
|
||||
debugfs_create_file("structs_counters", 0400, g_ctx.debug_dir, NULL,
|
||||
&debug_struct_counters_ops);
|
||||
|
||||
/* Initialize common API layer */
|
||||
client_init();
|
||||
|
||||
/* Initialize plenty of nice features */
|
||||
ret = nq_init();
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "NQ init failed");
|
||||
goto fail_nq_init;
|
||||
}
|
||||
|
||||
ret = mcp_init();
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "MCP init failed");
|
||||
goto err_mcp;
|
||||
}
|
||||
|
||||
ret = iwp_init();
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "IWP init failed");
|
||||
goto err_iwp;
|
||||
}
|
||||
|
||||
ret = device_common_init();
|
||||
if (ret)
|
||||
goto err_common;
|
||||
|
||||
if (!is_xen_domu()) {
|
||||
/* Admin dev is for the daemon to communicate with the driver */
|
||||
ret = device_admin_init();
|
||||
if (ret)
|
||||
goto err_admin;
|
||||
|
||||
#ifndef MC_DELAYED_TEE_START
|
||||
ret = mobicore_start();
|
||||
#endif
|
||||
if (ret)
|
||||
goto err_start;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_start:
|
||||
device_admin_exit();
|
||||
err_admin:
|
||||
device_common_exit();
|
||||
err_common:
|
||||
iwp_exit();
|
||||
err_iwp:
|
||||
mcp_exit();
|
||||
err_mcp:
|
||||
nq_exit();
|
||||
fail_nq_init:
|
||||
debugfs_remove_recursive(g_ctx.debug_dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mobicore_probe_not_of(void)
|
||||
{
|
||||
return mobicore_probe(NULL);
|
||||
}
|
||||
|
||||
static const struct of_device_id of_match_table[] = {
|
||||
{ .compatible = MC_DEVICE_PROPNAME },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver mc_plat_driver = {
|
||||
.probe = mobicore_probe,
|
||||
.driver = {
|
||||
.name = "mcd",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_table,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init mobicore_init(void)
|
||||
{
|
||||
dev_set_name(g_ctx.mcd, "TEE");
|
||||
/*
|
||||
* Do not remove or change the following trace.
|
||||
* The string "MobiCore" is used to detect if the TEE is in of the image
|
||||
*/
|
||||
mc_dev_info("MobiCore mcDrvModuleApi version is %d.%d",
|
||||
MCDRVMODULEAPI_VERSION_MAJOR,
|
||||
MCDRVMODULEAPI_VERSION_MINOR);
|
||||
|
||||
/* In a Xen DomU, just register the front-end */
|
||||
if (is_xen_domu())
|
||||
return xen_fe_init(mobicore_probe_not_of, mobicore_start_domu);
|
||||
|
||||
main_ctx.use_platform_driver =
|
||||
of_find_compatible_node(NULL, NULL, MC_DEVICE_PROPNAME);
|
||||
if (main_ctx.use_platform_driver)
|
||||
return platform_driver_register(&mc_plat_driver);
|
||||
|
||||
return mobicore_probe_not_of();
|
||||
}
|
||||
|
||||
static void __exit mobicore_exit(void)
|
||||
{
|
||||
if (is_xen_domu())
|
||||
xen_fe_exit();
|
||||
|
||||
if (main_ctx.use_platform_driver)
|
||||
platform_driver_unregister(&mc_plat_driver);
|
||||
|
||||
if (!is_xen_domu())
|
||||
device_admin_exit();
|
||||
|
||||
device_common_exit();
|
||||
iwp_exit();
|
||||
mcp_exit();
|
||||
nq_exit();
|
||||
debugfs_remove_recursive(g_ctx.debug_dir);
|
||||
}
|
||||
|
||||
module_init(mobicore_init);
|
||||
module_exit(mobicore_exit);
|
||||
|
||||
MODULE_AUTHOR("Trustonic Limited");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("MobiCore driver");
|
123
drivers/gud/MobiCoreDriver/main.h
Normal file
123
drivers/gud/MobiCoreDriver/main.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_MAIN_H_
|
||||
#define _MC_MAIN_H_
|
||||
|
||||
#include <linux/device.h> /* dev_* macros */
|
||||
#include <linux/slab.h> /* gfp_t */
|
||||
#include <linux/fs.h> /* struct inode and struct file */
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/version.h>
|
||||
#include <xen/xen.h>
|
||||
|
||||
#define MC_VERSION(major, minor) \
|
||||
((((major) & 0x0000ffff) << 16) | ((minor) & 0x0000ffff))
|
||||
#define MC_VERSION_MAJOR(x) ((x) >> 16)
|
||||
#define MC_VERSION_MINOR(x) ((x) & 0xffff)
|
||||
|
||||
#define mc_dev_err(__ret__, fmt, ...) \
|
||||
dev_err(g_ctx.mcd, "ERROR %d %s: " fmt "\n", \
|
||||
__ret__, __func__, ##__VA_ARGS__)
|
||||
|
||||
#define mc_dev_info(fmt, ...) \
|
||||
dev_info(g_ctx.mcd, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define mc_dev_devel(fmt, ...) \
|
||||
dev_info(g_ctx.mcd, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
|
||||
#else /* DEBUG */
|
||||
#define mc_dev_devel(...) do {} while (0)
|
||||
#endif /* !DEBUG */
|
||||
|
||||
#define TEEC_TT_LOGIN_KERNEL 0x80000000
|
||||
|
||||
#define TEE_START_NOT_TRIGGERED 1
|
||||
|
||||
/* MobiCore Driver Kernel Module context data. */
|
||||
struct mc_device_ctx {
|
||||
struct device *mcd;
|
||||
/* debugfs root */
|
||||
struct dentry *debug_dir;
|
||||
|
||||
/* Debug counters */
|
||||
atomic_t c_clients;
|
||||
atomic_t c_cbufs;
|
||||
atomic_t c_cwsms;
|
||||
atomic_t c_sessions;
|
||||
atomic_t c_wsms;
|
||||
atomic_t c_mmus;
|
||||
atomic_t c_maps;
|
||||
atomic_t c_slots;
|
||||
atomic_t c_xen_maps;
|
||||
atomic_t c_xen_fes;
|
||||
};
|
||||
|
||||
extern struct mc_device_ctx g_ctx;
|
||||
|
||||
/* Debug stuff */
|
||||
struct kasnprintf_buf {
|
||||
struct mutex mutex; /* Protect buf/size/off access */
|
||||
gfp_t gfp;
|
||||
void *buf;
|
||||
int size;
|
||||
int off;
|
||||
};
|
||||
|
||||
/* Wait for TEE to start and get status */
|
||||
int mc_wait_tee_start(void);
|
||||
|
||||
extern __printf(2, 3)
|
||||
int kasnprintf(struct kasnprintf_buf *buf, const char *fmt, ...);
|
||||
ssize_t debug_generic_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos,
|
||||
int (*function)(struct kasnprintf_buf *buf));
|
||||
int debug_generic_open(struct inode *inode, struct file *file);
|
||||
int debug_generic_release(struct inode *inode, struct file *file);
|
||||
|
||||
#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE
|
||||
static inline unsigned int kref_read(struct kref *kref)
|
||||
{
|
||||
return atomic_read(&kref->refcount);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Xen support */
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
#if KERNEL_VERSION(4, 4, 0) <= LINUX_VERSION_CODE
|
||||
#define TRUSTONIC_XEN_DOMU
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static inline bool is_xen_dom0(void)
|
||||
{
|
||||
#if KERNEL_VERSION(3, 18, 0) <= LINUX_VERSION_CODE
|
||||
return xen_domain() && xen_initial_domain();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool is_xen_domu(void)
|
||||
{
|
||||
#ifdef TRUSTONIC_XEN_DOMU
|
||||
return xen_domain() && !xen_initial_domain();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _MC_MAIN_H_ */
|
86
drivers/gud/MobiCoreDriver/mc_admin.h
Normal file
86
drivers/gud/MobiCoreDriver/mc_admin.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __MC_ADMIN_IOCTL_H__
|
||||
#define __MC_ADMIN_IOCTL_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MC_ADMIN_DEVNODE "mobicore"
|
||||
|
||||
/* Driver/daemon commands */
|
||||
enum {
|
||||
/* Command 0 is reserved */
|
||||
MC_DRV_GET_ROOT_CONTAINER = 1,
|
||||
MC_DRV_GET_SP_CONTAINER = 2,
|
||||
MC_DRV_GET_TRUSTLET_CONTAINER = 3,
|
||||
MC_DRV_GET_TRUSTLET = 4,
|
||||
MC_DRV_SIGNAL_CRASH = 5,
|
||||
};
|
||||
|
||||
/* MobiCore IOCTL magic number */
|
||||
#define MC_IOC_MAGIC 'M'
|
||||
|
||||
struct mc_admin_request {
|
||||
__u32 request_id; /* Unique request identifier */
|
||||
__u32 command; /* Command to daemon */
|
||||
struct mc_uuid_t uuid; /* UUID of trustlet, if relevant */
|
||||
__u32 is_gp; /* Whether trustlet is GP */
|
||||
__u32 spid; /* SPID of trustlet, if relevant */
|
||||
};
|
||||
|
||||
struct mc_admin_response {
|
||||
__u32 request_id; /* Unique request identifier */
|
||||
__u32 error_no; /* Errno from daemon */
|
||||
__u32 spid; /* SPID of trustlet, if relevant */
|
||||
__u32 service_type; /* Type of trustlet being returned */
|
||||
__u32 length; /* Length of data to get */
|
||||
/* Any data follows */
|
||||
};
|
||||
|
||||
struct mc_admin_driver_info {
|
||||
/* Version, and something else..*/
|
||||
__u32 drv_version;
|
||||
__u32 initial_cmd_id;
|
||||
};
|
||||
|
||||
struct mc_admin_load_info {
|
||||
__u32 spid; /* SPID of trustlet, if relevant */
|
||||
__u64 address; /* Address of the data */
|
||||
__u32 length; /* Length of data to get */
|
||||
struct mc_uuid_t uuid; /* UUID of trustlet, if relevant */
|
||||
};
|
||||
|
||||
#define MC_ADMIN_IO_GET_DRIVER_REQUEST \
|
||||
_IOR(MC_IOC_MAGIC, 0, struct mc_admin_request)
|
||||
#define MC_ADMIN_IO_GET_INFO \
|
||||
_IOR(MC_IOC_MAGIC, 1, struct mc_admin_driver_info)
|
||||
#define MC_ADMIN_IO_LOAD_DRIVER \
|
||||
_IOW(MC_IOC_MAGIC, 2, struct mc_admin_load_info)
|
||||
#define MC_ADMIN_IO_LOAD_TOKEN \
|
||||
_IOW(MC_IOC_MAGIC, 3, struct mc_admin_load_info)
|
||||
#define MC_ADMIN_IO_LOAD_CHECK \
|
||||
_IOW(MC_IOC_MAGIC, 4, struct mc_admin_load_info)
|
||||
#define MC_ADMIN_IO_LOAD_KEY_SO \
|
||||
_IOW(MC_IOC_MAGIC, 5, struct mc_admin_load_info)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __MC_ADMIN_IOCTL_H__ */
|
30
drivers/gud/MobiCoreDriver/mc_linux_api.h
Normal file
30
drivers/gud/MobiCoreDriver/mc_linux_api.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2013-2019 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef _MC_LINUX_API_H_
|
||||
#define _MC_LINUX_API_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Manage dynamically switch TEE worker threads/TEE affinity to big core only.
|
||||
* Or default core affinity.
|
||||
* Warning: Both PLAT_DEFAULT_TEE_AFFINITY_MASK and
|
||||
* BIG_CORE_SWITCH_AFFINITY_MASK have to be defined
|
||||
*/
|
||||
#if defined(BIG_CORE_SWITCH_AFFINITY_MASK)
|
||||
void set_tee_worker_threads_on_big_core(bool big_core);
|
||||
#endif
|
||||
|
||||
#endif /* _MC_LINUX_API_H_ */
|
307
drivers/gud/MobiCoreDriver/mc_user.h
Normal file
307
drivers/gud/MobiCoreDriver/mc_user.h
Normal file
|
@ -0,0 +1,307 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_USER_H_
|
||||
#define _MC_USER_H_
|
||||
|
||||
#define MCDRVMODULEAPI_VERSION_MAJOR 7
|
||||
#define MCDRVMODULEAPI_VERSION_MINOR 0
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#define BIT(n) (1 << (n))
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#define MC_USER_DEVNODE "mobicore-user"
|
||||
|
||||
/** Maximum length of MobiCore product ID string. */
|
||||
#define MC_PRODUCT_ID_LEN 64
|
||||
|
||||
/** Number of buffers that can be mapped at once */
|
||||
#define MC_MAP_MAX 4
|
||||
|
||||
/* Max length for buffers */
|
||||
#define MC_MAX_TCI_LEN 0x100000
|
||||
#define BUFFER_LENGTH_MAX 0x40000000
|
||||
|
||||
/* Max length for objects */
|
||||
#define OBJECT_LENGTH_MAX 0x8000000
|
||||
|
||||
/* Flags for buffers to map (aligned on GP) */
|
||||
#define MC_IO_MAP_INPUT BIT(0)
|
||||
#define MC_IO_MAP_OUTPUT BIT(1)
|
||||
#define MC_IO_MAP_INPUT_OUTPUT (MC_IO_MAP_INPUT | MC_IO_MAP_OUTPUT)
|
||||
|
||||
/*
|
||||
* Universally Unique Identifier (UUID) according to ISO/IEC 11578.
|
||||
*/
|
||||
struct mc_uuid_t {
|
||||
__u8 value[16]; /* Value of the UUID */
|
||||
};
|
||||
|
||||
/*
|
||||
* GP TA login types.
|
||||
*/
|
||||
enum mc_login_type {
|
||||
LOGIN_PUBLIC = 0,
|
||||
LOGIN_USER,
|
||||
LOGIN_GROUP,
|
||||
LOGIN_APPLICATION = 4,
|
||||
LOGIN_USER_APPLICATION,
|
||||
LOGIN_GROUP_APPLICATION,
|
||||
};
|
||||
|
||||
/*
|
||||
* GP TA identity structure.
|
||||
*/
|
||||
struct mc_identity {
|
||||
enum mc_login_type login_type;
|
||||
union {
|
||||
__u8 login_data[16];
|
||||
gid_t gid; /* Requested group id */
|
||||
struct {
|
||||
uid_t euid;
|
||||
uid_t ruid;
|
||||
} uid;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_OPEN_SESSION ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_open_session {
|
||||
struct mc_uuid_t uuid; /* trustlet uuid */
|
||||
__u32 is_gp_uuid; /* uuid is for GP TA */
|
||||
__u32 sid; /* session id (out) */
|
||||
__u64 tci; /* tci buffer pointer */
|
||||
__u32 tcilen; /* tci length */
|
||||
struct mc_identity identity; /* GP TA identity */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_OPEN_TRUSTLET ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_open_trustlet {
|
||||
__u32 sid; /* session id (out) */
|
||||
__u32 spid; /* trustlet spid */
|
||||
__u64 buffer; /* trustlet binary pointer */
|
||||
__u32 tlen; /* binary length */
|
||||
__u64 tci; /* tci buffer pointer */
|
||||
__u32 tcilen; /* tci length */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_WAIT ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_wait {
|
||||
__u32 sid; /* session id (in) */
|
||||
__s32 timeout; /* notification timeout */
|
||||
__u32 partial; /* for proxy server to retry silently */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_ALLOC ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_alloc {
|
||||
__u32 len; /* buffer length */
|
||||
__u32 handle; /* user handle for the buffer (out) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Buffer mapping incoming and outgoing information.
|
||||
*/
|
||||
struct mc_ioctl_buffer {
|
||||
__u64 va; /* user space address of buffer */
|
||||
__u32 len; /* buffer length */
|
||||
__u64 sva; /* SWd virt address of buffer (out) */
|
||||
__u32 flags; /* buffer flags */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_MAP and MC_IO_UNMAP ioctl commands.
|
||||
*/
|
||||
struct mc_ioctl_map {
|
||||
__u32 sid; /* session id */
|
||||
struct mc_ioctl_buffer buf; /* buffers info */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_ERR ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_geterr {
|
||||
__u32 sid; /* session id */
|
||||
__s32 value; /* error value (out) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Global MobiCore Version Information.
|
||||
*/
|
||||
struct mc_version_info {
|
||||
char product_id[MC_PRODUCT_ID_LEN]; /* Product ID string */
|
||||
__u32 version_mci; /* Mobicore Control Interface */
|
||||
__u32 version_so; /* Secure Objects */
|
||||
__u32 version_mclf; /* MobiCore Load Format */
|
||||
__u32 version_container; /* MobiCore Container Format */
|
||||
__u32 version_mc_config; /* MobiCore Config. Block Format */
|
||||
__u32 version_tl_api; /* MobiCore Trustlet API */
|
||||
__u32 version_dr_api; /* MobiCore Driver API */
|
||||
__u32 version_nwd; /* This Driver */
|
||||
};
|
||||
|
||||
/*
|
||||
* GP TA operation structure.
|
||||
*/
|
||||
struct gp_value {
|
||||
__u32 a;
|
||||
__u32 b;
|
||||
};
|
||||
|
||||
struct gp_temp_memref {
|
||||
__u64 buffer;
|
||||
__u64 size;
|
||||
};
|
||||
|
||||
struct gp_shared_memory {
|
||||
__u64 buffer;
|
||||
__u64 size;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
struct gp_regd_memref {
|
||||
struct gp_shared_memory parent;
|
||||
__u64 size;
|
||||
__u64 offset;
|
||||
};
|
||||
|
||||
union gp_param {
|
||||
struct gp_temp_memref tmpref;
|
||||
struct gp_regd_memref memref;
|
||||
struct gp_value value;
|
||||
};
|
||||
|
||||
struct gp_operation {
|
||||
__u32 started;
|
||||
__u32 param_types;
|
||||
union gp_param params[4];
|
||||
};
|
||||
|
||||
struct gp_return {
|
||||
__u32 origin;
|
||||
__u32 value;
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_GP_INITIALIZE_CONTEXT ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_gp_initialize_context {
|
||||
struct gp_return ret; /* return origin/value (out) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_GP_REGISTER_SHARED_MEM ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_gp_register_shared_mem {
|
||||
struct gp_shared_memory memref;
|
||||
struct gp_return ret; /* return origin/value (out) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_GP_RELEASE_SHARED_MEM ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_gp_release_shared_mem {
|
||||
struct gp_shared_memory memref;
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_GP_OPEN_SESSION ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_gp_open_session {
|
||||
struct mc_uuid_t uuid; /* trustlet uuid */
|
||||
struct mc_identity identity; /* GP TA identity */
|
||||
struct gp_operation operation; /* set of parameters */
|
||||
struct gp_return ret; /* return origin/value (out) */
|
||||
__u32 session_id; /* session id (out) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_GP_CLOSE_SESSION ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_gp_close_session {
|
||||
__u32 session_id; /* session id */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_GP_INVOKE_COMMAND ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_gp_invoke_command {
|
||||
struct gp_operation operation; /* set of parameters */
|
||||
__u32 session_id; /* session id */
|
||||
__u32 command_id; /* ID of the command */
|
||||
struct gp_return ret; /* return origin/value (out) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data exchange structure of the MC_IO_GP_CANCEL ioctl command.
|
||||
*/
|
||||
struct mc_ioctl_gp_request_cancellation {
|
||||
struct gp_operation operation; /* set of parameters */
|
||||
};
|
||||
|
||||
/*
|
||||
* defines for the ioctl mobicore driver module function call from user space.
|
||||
*/
|
||||
/* MobiCore IOCTL magic number */
|
||||
#define MC_IOC_MAGIC 'M'
|
||||
|
||||
/*
|
||||
* Implement corresponding functions from user api
|
||||
*/
|
||||
#define MC_IO_OPEN_SESSION \
|
||||
_IOWR(MC_IOC_MAGIC, 0, struct mc_ioctl_open_session)
|
||||
#define MC_IO_OPEN_TRUSTLET \
|
||||
_IOWR(MC_IOC_MAGIC, 1, struct mc_ioctl_open_trustlet)
|
||||
#define MC_IO_CLOSE_SESSION \
|
||||
_IO(MC_IOC_MAGIC, 2)
|
||||
#define MC_IO_NOTIFY \
|
||||
_IO(MC_IOC_MAGIC, 3)
|
||||
#define MC_IO_WAIT \
|
||||
_IOW(MC_IOC_MAGIC, 4, struct mc_ioctl_wait)
|
||||
#define MC_IO_MAP \
|
||||
_IOWR(MC_IOC_MAGIC, 5, struct mc_ioctl_map)
|
||||
#define MC_IO_UNMAP \
|
||||
_IOW(MC_IOC_MAGIC, 6, struct mc_ioctl_map)
|
||||
#define MC_IO_ERR \
|
||||
_IOWR(MC_IOC_MAGIC, 7, struct mc_ioctl_geterr)
|
||||
#define MC_IO_HAS_SESSIONS \
|
||||
_IO(MC_IOC_MAGIC, 8)
|
||||
#define MC_IO_VERSION \
|
||||
_IOR(MC_IOC_MAGIC, 9, struct mc_version_info)
|
||||
#define MC_IO_GP_INITIALIZE_CONTEXT \
|
||||
_IOW(MC_IOC_MAGIC, 20, struct mc_ioctl_gp_initialize_context)
|
||||
#define MC_IO_GP_REGISTER_SHARED_MEM \
|
||||
_IOWR(MC_IOC_MAGIC, 21, struct mc_ioctl_gp_register_shared_mem)
|
||||
#define MC_IO_GP_RELEASE_SHARED_MEM \
|
||||
_IOW(MC_IOC_MAGIC, 23, struct mc_ioctl_gp_release_shared_mem)
|
||||
#define MC_IO_GP_OPEN_SESSION \
|
||||
_IOWR(MC_IOC_MAGIC, 24, struct mc_ioctl_gp_open_session)
|
||||
#define MC_IO_GP_CLOSE_SESSION \
|
||||
_IOW(MC_IOC_MAGIC, 25, struct mc_ioctl_gp_close_session)
|
||||
#define MC_IO_GP_INVOKE_COMMAND \
|
||||
_IOWR(MC_IOC_MAGIC, 26, struct mc_ioctl_gp_invoke_command)
|
||||
#define MC_IO_GP_REQUEST_CANCELLATION \
|
||||
_IOW(MC_IOC_MAGIC, 27, struct mc_ioctl_gp_request_cancellation)
|
||||
|
||||
#endif /* _MC_USER_H_ */
|
160
drivers/gud/MobiCoreDriver/mcifc.h
Normal file
160
drivers/gud/MobiCoreDriver/mcifc.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef MCIFC_H_
|
||||
#define MCIFC_H_
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
/** @name MobiCore FastCall Definition
|
||||
* Defines for the two different FastCall's.
|
||||
*/
|
||||
/**/
|
||||
|
||||
/* --- global ---- */
|
||||
#define MC_FC_INVALID ((u32)0) /**< Invalid FastCall ID */
|
||||
|
||||
#if (defined(CONFIG_ARM64) && !defined(MC_ARMV7_FC)) || (defined(MC_AARCH32_FC))
|
||||
|
||||
#define FASTCALL_OWNER_TZOS (0x3F000000)
|
||||
#define FASTCALL_ATOMIC_MASK BIT(31)
|
||||
/**Trusted OS Fastcalls SMC32 */
|
||||
#define MC_FC_STD32_BASE \
|
||||
((u32)(FASTCALL_OWNER_TZOS | FASTCALL_ATOMIC_MASK))
|
||||
/* SMC32 Trusted OS owned Fastcalls */
|
||||
#define MC_FC_STD32(x) ((u32)(MC_FC_STD32_BASE + (x)))
|
||||
|
||||
#define MC_FC_INIT MC_FC_STD32(1) /**< Initializing FastCall. */
|
||||
#define MC_FC_INFO MC_FC_STD32(2) /**< Info FastCall. */
|
||||
#define MC_FC_MEM_TRACE MC_FC_STD32(10) /**< Enable SWd tracing via memory */
|
||||
|
||||
#else
|
||||
|
||||
#define MC_FC_INIT ((u32)(-1)) /**< Initializing FastCall. */
|
||||
#define MC_FC_INFO ((u32)(-2)) /**< Info FastCall. */
|
||||
#define MC_FC_MEM_TRACE ((u32)(-31)) /**< Enable SWd tracing via memory */
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name MobiCore SMC Definition
|
||||
* Defines the different secure monitor calls (SMC) for world switching.
|
||||
*/
|
||||
/**< Yield to switch from NWd to SWd. */
|
||||
#define MC_SMC_N_YIELD 3
|
||||
/**< SIQ to switch from NWd to SWd. */
|
||||
#define MC_SMC_N_SIQ 4
|
||||
/** @} */
|
||||
|
||||
/** @name MobiCore status
|
||||
* MobiCore status information.
|
||||
*/
|
||||
/**< MobiCore is not yet initialized. FastCall FcInit() to set up MobiCore.*/
|
||||
#define MC_STATUS_NOT_INITIALIZED 0
|
||||
/**< Bad parameters have been passed in FcInit(). */
|
||||
#define MC_STATUS_BAD_INIT 1
|
||||
/**< MobiCore did initialize properly. */
|
||||
#define MC_STATUS_INITIALIZED 2
|
||||
/**< MobiCore kernel halted due to an unrecoverable exception. Further
|
||||
* information is available extended info
|
||||
*/
|
||||
#define MC_STATUS_HALT 3
|
||||
/** @} */
|
||||
|
||||
/** @name Extended Info Identifiers
|
||||
* Extended info parameters for MC_FC_INFO to obtain further information
|
||||
* depending on MobiCore state.
|
||||
*/
|
||||
/**< Version of the MobiCore Control Interface (MCI) */
|
||||
#define MC_EXT_INFO_ID_MCI_VERSION 0
|
||||
/**< MobiCore control flags */
|
||||
#define MC_EXT_INFO_ID_FLAGS 1
|
||||
/**< MobiCore halt condition code */
|
||||
#define MC_EXT_INFO_ID_HALT_CODE 2
|
||||
/**< MobiCore halt condition instruction pointer */
|
||||
#define MC_EXT_INFO_ID_HALT_IP 3
|
||||
/**< MobiCore fault counter */
|
||||
#define MC_EXT_INFO_ID_FAULT_CNT 4
|
||||
/**< MobiCore last fault cause */
|
||||
#define MC_EXT_INFO_ID_FAULT_CAUSE 5
|
||||
/**< MobiCore last fault meta */
|
||||
#define MC_EXT_INFO_ID_FAULT_META 6
|
||||
/**< MobiCore last fault threadid */
|
||||
#define MC_EXT_INFO_ID_FAULT_THREAD 7
|
||||
/**< MobiCore last fault instruction pointer */
|
||||
#define MC_EXT_INFO_ID_FAULT_IP 8
|
||||
/**< MobiCore last fault stack pointer */
|
||||
#define MC_EXT_INFO_ID_FAULT_SP 9
|
||||
/**< MobiCore last fault ARM arch information */
|
||||
#define MC_EXT_INFO_ID_FAULT_ARCH_DFSR 10
|
||||
/**< MobiCore last fault ARM arch information */
|
||||
#define MC_EXT_INFO_ID_FAULT_ARCH_ADFSR 11
|
||||
/**< MobiCore last fault ARM arch information */
|
||||
#define MC_EXT_INFO_ID_FAULT_ARCH_DFAR 12
|
||||
/**< MobiCore last fault ARM arch information */
|
||||
#define MC_EXT_INFO_ID_FAULT_ARCH_IFSR 13
|
||||
/**< MobiCore last fault ARM arch information */
|
||||
#define MC_EXT_INFO_ID_FAULT_ARCH_AIFSR 14
|
||||
/**< MobiCore last fault ARM arch information */
|
||||
#define MC_EXT_INFO_ID_FAULT_ARCH_IFAR 15
|
||||
/**< MobiCore configured by Daemon via fc_init flag */
|
||||
#define MC_EXT_INFO_ID_MC_CONFIGURED 16
|
||||
/**< MobiCore scheduling status: idle/non-idle */
|
||||
#define MC_EXT_INFO_ID_MC_SCHED_STATUS 17
|
||||
/**< MobiCore runtime status: initialized, halted */
|
||||
#define MC_EXT_INFO_ID_MC_STATUS 18
|
||||
/**< MobiCore exception handler last partner */
|
||||
#define MC_EXT_INFO_ID_MC_EXC_PARTNER 19
|
||||
/**< MobiCore exception handler last peer */
|
||||
#define MC_EXT_INFO_ID_MC_EXC_IPCPEER 20
|
||||
/**< MobiCore exception handler last IPC message */
|
||||
#define MC_EXT_INFO_ID_MC_EXC_IPCMSG 21
|
||||
/**< MobiCore exception handler last IPC data */
|
||||
#define MC_EXT_INFO_ID_MC_EXC_IPCDATA 22
|
||||
/**< MobiCore exception handler last UUID (uses 4 slots: 23 to 26) */
|
||||
#define MC_EXT_INFO_ID_MC_EXC_UUID 23
|
||||
#define MC_EXT_INFO_ID_MC_EXC_UUID1 24
|
||||
#define MC_EXT_INFO_ID_MC_EXC_UUID2 25
|
||||
#define MC_EXT_INFO_ID_MC_EXC_UUID3 26
|
||||
/**< MobiCore exception handler last crashing task offset */
|
||||
#define MC_EXT_INFO_ID_TASK_OFFSET 27
|
||||
/**< MobiCore exception handler last crashing task's mclib offset */
|
||||
#define MC_EXT_INFO_ID_MCLIB_OFFSET 28
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name FastCall return values
|
||||
* Return values of the MobiCore FastCalls.
|
||||
*/
|
||||
/**< No error. Everything worked fine. */
|
||||
#define MC_FC_RET_OK 0
|
||||
/**< FastCall was not successful. */
|
||||
#define MC_FC_RET_ERR_INVALID 1
|
||||
/**< MobiCore has already been initialized. */
|
||||
#define MC_FC_RET_ERR_ALREADY_INITIALIZED 5
|
||||
/**< Call is not allowed. */
|
||||
#define TEE_FC_RET_ERR_NOABILITY 6
|
||||
/** @} */
|
||||
|
||||
/** @name Init FastCall flags
|
||||
* Return flags of the Init FastCall.
|
||||
*/
|
||||
/**< SWd uses LPAE MMU table format. */
|
||||
#define MC_FC_INIT_FLAG_LPAE BIT(0)
|
||||
/** @} */
|
||||
|
||||
#endif /** MCIFC_H_ */
|
||||
|
||||
/** @} */
|
123
drivers/gud/MobiCoreDriver/mciiwp.h
Normal file
123
drivers/gud/MobiCoreDriver/mciiwp.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2016-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MCIIWP_H_
|
||||
#define MCIIWP_H_
|
||||
|
||||
#include "tee_client_types.h" /* teec_uuid FIXME it's all mixed up! */
|
||||
|
||||
/** Session ID for notifications for the Dragon CA-to-TA communication protocol
|
||||
*
|
||||
* Session ID are distinct from any valid MCP session identifier
|
||||
* and from the existing pseudo-session identifiers :
|
||||
* - SID_MCP = 0
|
||||
* - SID_INVALID = 0xffffffff
|
||||
*
|
||||
* A session ID is a thread ID, and since thread IDs have a nonzero task ID as
|
||||
* their lowest 16 bits, we can use values of the form 0x????0000
|
||||
*/
|
||||
#define SID_OPEN_SESSION (0x00010000)
|
||||
#define SID_INVOKE_COMMAND (0x00020000)
|
||||
#define SID_CLOSE_SESSION (0x00030000)
|
||||
#define SID_CANCEL_OPERATION (0x00040000)
|
||||
#define SID_MEMORY_REFERENCE (0x00050000)
|
||||
#define SID_OPEN_TA (0x00060000)
|
||||
#define SID_REQ_TA (0x00070000)
|
||||
|
||||
/* To quickly detect IWP notifications */
|
||||
#define SID_IWP_NOTIFICATION \
|
||||
(SID_OPEN_SESSION | SID_INVOKE_COMMAND | SID_CLOSE_SESSION | \
|
||||
SID_CANCEL_OPERATION | SID_MEMORY_REFERENCE | SID_OPEN_TA | SID_REQ_TA)
|
||||
|
||||
struct interworld_parameter_value {
|
||||
u32 a;
|
||||
u32 b;
|
||||
u8 unused[8];
|
||||
};
|
||||
|
||||
/** The API parameter type TEEC_MEMREF_WHOLE is translated into these types
|
||||
* and does not appear in the inter-world protocol.
|
||||
*
|
||||
* - memref_handle references a previously registered memory reference
|
||||
* 'offset' bytes <= memref_handle < 'offset + size' bytes
|
||||
*
|
||||
* These sizes must be contained within the memory reference.
|
||||
*/
|
||||
struct interworld_parameter_memref {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u32 memref_handle;
|
||||
u32 unused;
|
||||
};
|
||||
|
||||
/** This structure is used for the parameter types TEEC_MEMREF_TEMP_xxx.
|
||||
*
|
||||
* The parameter is located in World Shared Memory which is established
|
||||
* for the command and torn down afterwards.
|
||||
*
|
||||
* The number of pages to share is 'size + offset' divided by the page
|
||||
* size, rounded up.
|
||||
* Inside the shared pages, the buffer starts at address 'offset'
|
||||
* and ends after 'size' bytes.
|
||||
*
|
||||
* - wsm_type parameter may be WSM_CONTIGUOUS or WSM_L1.
|
||||
* - offset must be less than the page size (4096).
|
||||
* - size must be less than 0xfffff000.
|
||||
*/
|
||||
struct interworld_parameter_tmpref {
|
||||
u16 wsm_type;
|
||||
u16 offset;
|
||||
u32 size;
|
||||
u64 physical_address;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
union interworld_parameter {
|
||||
struct interworld_parameter_value value;
|
||||
struct interworld_parameter_memref memref;
|
||||
struct interworld_parameter_tmpref tmpref;
|
||||
};
|
||||
|
||||
/**
|
||||
* An inter-world session structure represents an active session between
|
||||
* a normal world client and RTM.
|
||||
* It is located in the MCI buffer, must be 8-byte aligned
|
||||
*
|
||||
* NB : since the session structure is in shared memory, it must have the
|
||||
* same layout on both sides (normal world kernel and RTM).
|
||||
* All types use platform endianness (specifically, the endianness used by
|
||||
* the secure world).
|
||||
*/
|
||||
struct interworld_session {
|
||||
u32 status;
|
||||
u32 return_origin;
|
||||
u16 session_handle;
|
||||
u16 param_types;
|
||||
|
||||
union {
|
||||
u32 command_id; /** invoke-command only */
|
||||
u32 login; /** open-session only */
|
||||
};
|
||||
|
||||
union interworld_parameter params[4];
|
||||
|
||||
/* The following fields are only used during open-session */
|
||||
struct teec_uuid target_uuid;
|
||||
struct teec_uuid client_uuid;
|
||||
};
|
||||
|
||||
#endif /** MCIIWP_H_ */
|
487
drivers/gud/MobiCoreDriver/mcimcp.h
Normal file
487
drivers/gud/MobiCoreDriver/mcimcp.h
Normal file
|
@ -0,0 +1,487 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MCP_H_
|
||||
#define MCP_H_
|
||||
|
||||
#include "mcloadformat.h"
|
||||
|
||||
/** Indicates a response */
|
||||
#define FLAG_RESPONSE BIT(31)
|
||||
|
||||
/** MobiCore Return Code Defines.
|
||||
* List of the possible MobiCore return codes.
|
||||
*/
|
||||
enum mcp_result {
|
||||
/** Memory has successfully been mapped */
|
||||
MC_MCP_RET_OK = 0,
|
||||
/** The session ID is invalid */
|
||||
MC_MCP_RET_ERR_INVALID_SESSION = 1,
|
||||
/** The UUID of the Trustlet is unknown */
|
||||
MC_MCP_RET_ERR_UNKNOWN_UUID = 2,
|
||||
/** The ID of the driver is unknown */
|
||||
MC_MCP_RET_ERR_UNKNOWN_DRIVER_ID = 3,
|
||||
/** No more session are allowed */
|
||||
MC_MCP_RET_ERR_NO_MORE_SESSIONS = 4,
|
||||
/** The container is invalid */
|
||||
MC_MCP_RET_ERR_CONTAINER_INVALID = 5,
|
||||
/** The Trustlet is invalid */
|
||||
MC_MCP_RET_ERR_TRUSTLET_INVALID = 6,
|
||||
/** The memory block has already been mapped before */
|
||||
MC_MCP_RET_ERR_ALREADY_MAPPED = 7,
|
||||
/** Alignment or length error in the command parameters */
|
||||
MC_MCP_RET_ERR_INVALID_PARAM = 8,
|
||||
/** No space left in the virtual address space of the session */
|
||||
MC_MCP_RET_ERR_OUT_OF_RESOURCES = 9,
|
||||
/** WSM type unknown or broken WSM */
|
||||
MC_MCP_RET_ERR_INVALID_WSM = 10,
|
||||
/** unknown error */
|
||||
MC_MCP_RET_ERR_UNKNOWN = 11,
|
||||
/** Length of map invalid */
|
||||
MC_MCP_RET_ERR_INVALID_MAPPING_LENGTH = 12,
|
||||
/** Map can only be applied to Trustlet session */
|
||||
MC_MCP_RET_ERR_MAPPING_TARGET = 13,
|
||||
/** Couldn't open crypto session */
|
||||
MC_MCP_RET_ERR_OUT_OF_CRYPTO_RESOURCES = 14,
|
||||
/** System Trustlet signature verification failed */
|
||||
MC_MCP_RET_ERR_SIGNATURE_VERIFICATION_FAILED = 15,
|
||||
/** System Trustlet public key is wrong */
|
||||
MC_MCP_RET_ERR_WRONG_PUBLIC_KEY = 16,
|
||||
/** Wrong containter type(s) */
|
||||
MC_MCP_RET_ERR_CONTAINER_TYPE_MISMATCH = 17,
|
||||
/** Container is locked (or not activated) */
|
||||
MC_MCP_RET_ERR_CONTAINER_LOCKED = 18,
|
||||
/** SPID is not registered with root container */
|
||||
MC_MCP_RET_ERR_SP_NO_CHILD = 19,
|
||||
/** UUID is not registered with sp container */
|
||||
MC_MCP_RET_ERR_TL_NO_CHILD = 20,
|
||||
/** Unwrapping of root container failed */
|
||||
MC_MCP_RET_ERR_UNWRAP_ROOT_FAILED = 21,
|
||||
/** Unwrapping of service provider container failed */
|
||||
MC_MCP_RET_ERR_UNWRAP_SP_FAILED = 22,
|
||||
/** Unwrapping of Trustlet container failed */
|
||||
MC_MCP_RET_ERR_UNWRAP_TRUSTLET_FAILED = 23,
|
||||
/** Container version mismatch */
|
||||
MC_MCP_RET_ERR_CONTAINER_VERSION_MISMATCH = 24,
|
||||
/** Decryption of service provider trustlet failed */
|
||||
MC_MCP_RET_ERR_SP_TL_DECRYPTION_FAILED = 25,
|
||||
/** Hash check of service provider trustlet failed */
|
||||
MC_MCP_RET_ERR_SP_TL_HASH_CHECK_FAILED = 26,
|
||||
/** Activation/starting of task failed */
|
||||
MC_MCP_RET_ERR_LAUNCH_TASK_FAILED = 27,
|
||||
/** Closing of task not yet possible, try again later */
|
||||
MC_MCP_RET_ERR_CLOSE_TASK_FAILED = 28,
|
||||
/**< Service is blocked and a session cannot be opened to it */
|
||||
MC_MCP_RET_ERR_SERVICE_BLOCKED = 29,
|
||||
/**< Service is locked and a session cannot be opened to it */
|
||||
MC_MCP_RET_ERR_SERVICE_LOCKED = 30,
|
||||
/**< Service was forcefully killed (due to an administrative command) */
|
||||
MC_MCP_RET_ERR_SERVICE_KILLED = 31,
|
||||
/**< Service version is lower than the one installed. */
|
||||
MC_MCP_RET_ERR_DOWNGRADE_NOT_AUTHORIZED = 32,
|
||||
/**< Filesystem not yet ready. */
|
||||
MC_MCP_RET_ERR_SYSTEM_NOT_READY = 33,
|
||||
/** The command is unknown */
|
||||
MC_MCP_RET_ERR_UNKNOWN_COMMAND = 50,
|
||||
/** The command data is invalid */
|
||||
MC_MCP_RET_ERR_INVALID_DATA = 51
|
||||
};
|
||||
|
||||
/** Possible MCP Command IDs
|
||||
* Command ID must be between 0 and 0x7FFFFFFF.
|
||||
*/
|
||||
enum cmd_id {
|
||||
/** Invalid command ID */
|
||||
MC_MCP_CMD_ID_INVALID = 0x00,
|
||||
/** Open a session */
|
||||
MC_MCP_CMD_OPEN_SESSION = 0x01,
|
||||
/** Close an existing session */
|
||||
MC_MCP_CMD_CLOSE_SESSION = 0x03,
|
||||
/** Map WSM to session */
|
||||
MC_MCP_CMD_MAP = 0x04,
|
||||
/** Unmap WSM from session */
|
||||
MC_MCP_CMD_UNMAP = 0x05,
|
||||
/** Prepare for suspend */
|
||||
MC_MCP_CMD_SUSPEND = 0x06,
|
||||
/** Resume from suspension */
|
||||
MC_MCP_CMD_RESUME = 0x07,
|
||||
/** Get MobiCore version information */
|
||||
MC_MCP_CMD_GET_MOBICORE_VERSION = 0x09,
|
||||
/** Close MCP and unmap MCI */
|
||||
MC_MCP_CMD_CLOSE_MCP = 0x0A,
|
||||
/** Load token for device attestation */
|
||||
MC_MCP_CMD_LOAD_TOKEN = 0x0B,
|
||||
/** Check that TA can be loaded */
|
||||
MC_MCP_CMD_CHECK_LOAD_TA = 0x0C,
|
||||
/** Load a decryption key */
|
||||
MC_MCP_CMD_LOAD_SYSENC_KEY_SO = 0x0D,
|
||||
};
|
||||
|
||||
/*
|
||||
* Types of WSM known to the MobiCore.
|
||||
*/
|
||||
#define WSM_TYPE_MASK 0xFF
|
||||
#define WSM_INVALID 0 /** Invalid memory type */
|
||||
#define WSM_L1 3 /** Buffer mapping uses fake L1 table */
|
||||
/**< Bitflag indicating that the buffer should be uncached */
|
||||
#define WSM_UNCACHED 0x100
|
||||
|
||||
/*
|
||||
* Magic number used to identify if Open Command supports GP client
|
||||
* authentication.
|
||||
*/
|
||||
#define MC_GP_CLIENT_AUTH_MAGIC 0x47504131 /* "GPA1" */
|
||||
|
||||
/*
|
||||
* Initialisation values flags
|
||||
*/
|
||||
/* Set if IRQ is present */
|
||||
#define MC_IV_FLAG_IRQ BIT(0)
|
||||
/* Set if GP TIME is supported */
|
||||
#define MC_IV_FLAG_TIME BIT(1)
|
||||
/* Set if GP client uses interworld session */
|
||||
#define MC_IV_FLAG_IWP BIT(2)
|
||||
|
||||
struct init_values {
|
||||
u32 flags;
|
||||
u32 irq;
|
||||
u32 time_ofs;
|
||||
u32 time_len;
|
||||
/* interworld session buffer offset in MCI */
|
||||
u32 iws_buf_ofs;
|
||||
/* interworld session buffer size */
|
||||
u32 iws_buf_size;
|
||||
u8 padding[8];
|
||||
};
|
||||
|
||||
/** Command header.
|
||||
* It just contains the command ID. Only values specified in cmd_id are
|
||||
* allowed as command IDs. If the command ID is unspecified the MobiCore
|
||||
* returns an empty response with the result set to
|
||||
* MC_MCP_RET_ERR_UNKNOWN_COMMAND.
|
||||
*/
|
||||
struct cmd_header {
|
||||
enum cmd_id cmd_id; /** Command ID of the command */
|
||||
};
|
||||
|
||||
/** Response header.
|
||||
* MobiCore will reply to every MCP command with an MCP response. Like the MCP
|
||||
* command the response consists of a header followed by response data. The
|
||||
* response is written to the same memory location as the MCP command.
|
||||
*/
|
||||
struct rsp_header {
|
||||
u32 rsp_id; /** Command ID | FLAG_RESPONSE */
|
||||
enum mcp_result result; /** Result of the command execution */
|
||||
};
|
||||
|
||||
/** @defgroup CMD MCP Commands
|
||||
*/
|
||||
|
||||
/** @defgroup ASMCMD Administrative Commands
|
||||
*/
|
||||
|
||||
/** @defgroup MCPGETMOBICOREVERSION GET_MOBICORE_VERSION
|
||||
* Get MobiCore version info.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Get MobiCore Version Command */
|
||||
struct cmd_get_version {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
};
|
||||
|
||||
/** Get MobiCore Version Command Response */
|
||||
struct rsp_get_version {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
struct mc_version_info version_info; /** MobiCore version info */
|
||||
};
|
||||
|
||||
/** @defgroup POWERCMD Power Management Commands
|
||||
*/
|
||||
|
||||
/** @defgroup MCPSUSPEND SUSPEND
|
||||
* Prepare MobiCore suspension.
|
||||
* This command allows MobiCore and MobiCore drivers to release or clean
|
||||
* resources and save device state.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Suspend Command */
|
||||
struct cmd_suspend {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
};
|
||||
|
||||
/** Suspend Command Response */
|
||||
struct rsp_suspend {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
};
|
||||
|
||||
/** @defgroup MCPRESUME RESUME
|
||||
* Resume MobiCore from suspension.
|
||||
* This command allows MobiCore and MobiCore drivers to reinitialize hardware
|
||||
* affected by suspension.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Resume Command */
|
||||
struct cmd_resume {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
};
|
||||
|
||||
/** Resume Command Response */
|
||||
struct rsp_resume {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
};
|
||||
|
||||
/** @defgroup SESSCMD Session Management Commands
|
||||
*/
|
||||
|
||||
/** @defgroup MCPOPEN OPEN
|
||||
* Load and open a session to a Trustlet.
|
||||
* The OPEN command loads Trustlet data to the MobiCore context and opens a
|
||||
* session to the Trustlet. If wsm_data_type is WSM_INVALID MobiCore tries to
|
||||
* start a pre-installed Trustlet associated with the uuid passed. The uuid
|
||||
* passed must match the uuid contained in the load data (if available).
|
||||
* On success, MobiCore returns the session ID which can be used for further
|
||||
* communication.
|
||||
*/
|
||||
|
||||
/** GP client authentication data */
|
||||
struct cmd_open_data {
|
||||
u32 mclf_magic; /** ASCII "MCLF" on older versions */
|
||||
struct identity identity; /** Login method and data */
|
||||
};
|
||||
|
||||
/** Open Command */
|
||||
struct cmd_open {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
struct mc_uuid_t uuid; /** Service UUID */
|
||||
u8 unused[4]; /** Padding to be 64-bit aligned */
|
||||
u64 adr_tci_buffer; /** Physical address of the TCI MMU */
|
||||
u64 adr_load_data; /** Physical address of the data MMU */
|
||||
u32 ofs_tci_buffer; /** Offset to the data */
|
||||
u32 len_tci_buffer; /** Length of the TCI */
|
||||
u32 wsmtype_tci; /** Type of WSM used for the TCI */
|
||||
u32 wsm_data_type; /** Type of MMU */
|
||||
u32 ofs_load_data; /** Offset to the data */
|
||||
u32 len_load_data; /** Length of the data to load */
|
||||
union {
|
||||
struct cmd_open_data cmd_open_data; /** Client login data */
|
||||
union mclf_header tl_header; /** Service header */
|
||||
};
|
||||
u32 is_gpta; /** true if looking for an SD/GP-TA */
|
||||
};
|
||||
|
||||
/** Open Command Response */
|
||||
struct rsp_open {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
u32 session_id; /** Session ID */
|
||||
};
|
||||
|
||||
/** TA Load Check Command */
|
||||
struct cmd_check_load {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
struct mc_uuid_t uuid; /** Service UUID */
|
||||
u8 unused[4]; /** Padding to be 64-bit aligned */
|
||||
u64 adr_load_data; /** Physical address of the data */
|
||||
u32 wsm_data_type; /** Type of MMU */
|
||||
u32 ofs_load_data; /** Offset to the data */
|
||||
u32 len_load_data; /** Length of the data to load */
|
||||
union mclf_header tl_header; /** Service header */
|
||||
};
|
||||
|
||||
/** TA Load Check Response */
|
||||
struct rsp_check_load {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
};
|
||||
|
||||
/** @defgroup MCPCLOSE CLOSE
|
||||
* Close an existing session to a Trustlet.
|
||||
* The CLOSE command terminates a session and frees all resources in the
|
||||
* MobiCore system which are currently occupied by the session. Before closing
|
||||
* the session, the MobiCore runtime management waits until all pending
|
||||
* operations, like calls to drivers, invoked by the Trustlet have been
|
||||
* terminated. Mapped memory will automatically be unmapped from the MobiCore
|
||||
* context. The NWd is responsible for processing the freed memory according to
|
||||
* the Rich-OS needs.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Close Command */
|
||||
struct cmd_close {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
u32 session_id; /** Session ID */
|
||||
};
|
||||
|
||||
/** Close Command Response */
|
||||
struct rsp_close {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
};
|
||||
|
||||
/** @defgroup MCPMAP MAP
|
||||
* Map a portion of memory to a session.
|
||||
* The MAP command provides a block of memory to the context of a service.
|
||||
* The memory then becomes world-shared memory (WSM).
|
||||
* The only allowed memory type here is WSM_L1.
|
||||
*/
|
||||
|
||||
/** Map Command */
|
||||
struct cmd_map {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
u32 session_id; /** Session ID */
|
||||
u32 wsm_type; /** Type of MMU */
|
||||
u32 ofs_buffer; /** Offset to the payload */
|
||||
u64 adr_buffer; /** Physical address of the MMU */
|
||||
u32 len_buffer; /** Length of the buffer */
|
||||
u32 flags; /** Attributes (read/write) */
|
||||
};
|
||||
|
||||
#define MCP_MAP_MAX 0x100000 /** Maximum length for MCP map */
|
||||
|
||||
/** Map Command Response */
|
||||
struct rsp_map {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
/** Virtual address the WSM is mapped to, may include an offset! */
|
||||
u32 secure_va;
|
||||
};
|
||||
|
||||
/** @defgroup MCPUNMAP UNMAP
|
||||
* Unmap a portion of world-shared memory from a session.
|
||||
* The UNMAP command is used to unmap a previously mapped block of
|
||||
* world shared memory from the context of a session.
|
||||
*
|
||||
* Attention: The memory block will be immediately unmapped from the specified
|
||||
* session. If the service is still accessing the memory, the service will
|
||||
* trigger a segmentation fault.
|
||||
*/
|
||||
|
||||
/** Unmap Command */
|
||||
struct cmd_unmap {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
u32 session_id; /** Session ID */
|
||||
u32 wsm_type; /** Type of WSM used of the memory */
|
||||
/** Virtual address the WSM is mapped to, may include an offset! */
|
||||
u32 secure_va;
|
||||
u32 virtual_buffer_len; /** Length of virtual buffer */
|
||||
};
|
||||
|
||||
/** Unmap Command Response */
|
||||
struct rsp_unmap {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
};
|
||||
|
||||
/** @defgroup MCPLOADTOKEN
|
||||
* Load a token from the normal world and share it with the TEE
|
||||
* If something fails, the device attestation functionality will be disabled
|
||||
*/
|
||||
|
||||
/** Load Token */
|
||||
struct cmd_load_token {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
u32 wsm_data_type; /** Type of MMU */
|
||||
u64 adr_load_data; /** Physical address of the MMU */
|
||||
u64 ofs_load_data; /** Offset to the data */
|
||||
u64 len_load_data; /** Length of the data */
|
||||
};
|
||||
|
||||
/** Load Token Command Response */
|
||||
struct rsp_load_token {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
};
|
||||
|
||||
/** @defgroup MCPLOADKEYSO
|
||||
* Load a key SO from the normal world and share it with the TEE
|
||||
* If something fails, the device attestation functionality will be disabled
|
||||
*/
|
||||
|
||||
/** Load key SO */
|
||||
struct cmd_load_key_so {
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
u32 wsm_data_type; /** Type of MMU */
|
||||
u64 adr_load_data; /** Physical address of the MMU */
|
||||
u64 ofs_load_data; /** Offset to the data */
|
||||
u64 len_load_data; /** Length of the data */
|
||||
};
|
||||
|
||||
/** Load key SO Command Response */
|
||||
struct rsp_load_key_so {
|
||||
struct rsp_header rsp_header; /** Response header */
|
||||
};
|
||||
|
||||
/** Structure of the MCP buffer */
|
||||
union mcp_message {
|
||||
struct init_values init_values; /** Initialisation values */
|
||||
struct cmd_header cmd_header; /** Command header */
|
||||
struct rsp_header rsp_header;
|
||||
struct cmd_open cmd_open; /** Load and open service */
|
||||
struct rsp_open rsp_open;
|
||||
struct cmd_close cmd_close; /** Close command */
|
||||
struct rsp_close rsp_close;
|
||||
struct cmd_map cmd_map; /** Map WSM to service */
|
||||
struct rsp_map rsp_map;
|
||||
struct cmd_unmap cmd_unmap; /** Unmap WSM from service */
|
||||
struct rsp_unmap rsp_unmap;
|
||||
struct cmd_suspend cmd_suspend; /** Suspend MobiCore */
|
||||
struct rsp_suspend rsp_suspend;
|
||||
struct cmd_resume cmd_resume; /** Resume MobiCore */
|
||||
struct rsp_resume rsp_resume;
|
||||
struct cmd_get_version cmd_get_version; /** Get MobiCore Version */
|
||||
struct rsp_get_version rsp_get_version;
|
||||
struct cmd_load_token cmd_load_token; /** Load token */
|
||||
struct rsp_load_token rsp_load_token;
|
||||
struct cmd_check_load cmd_check_load; /** TA load check */
|
||||
struct rsp_check_load rsp_check_load;
|
||||
struct cmd_load_key_so cmd_load_key_so;/** Load key SO */
|
||||
struct rsp_load_key_so rsp_load_key_so;
|
||||
};
|
||||
|
||||
#define MC_FLAG_NO_SLEEP_REQ 0
|
||||
#define MC_FLAG_REQ_TO_SLEEP 1
|
||||
|
||||
#define MC_STATE_NORMAL_EXECUTION 0
|
||||
#define MC_STATE_READY_TO_SLEEP 1
|
||||
|
||||
#define MC_STATE_FLAG_TEE_HALT_MASK BIT(0)
|
||||
|
||||
struct sleep_mode {
|
||||
u16 sleep_req; /** Ask SWd to get ready to sleep */
|
||||
u16 ready_to_sleep; /** SWd is now ready to sleep */
|
||||
};
|
||||
|
||||
/** MobiCore status flags */
|
||||
struct mcp_flags {
|
||||
/** If not MC_FLAG_SCHEDULE_IDLE, MobiCore needs scheduling */
|
||||
u32 schedule;
|
||||
struct sleep_mode sleep_mode;
|
||||
/** Secure-world sleep timeout in milliseconds */
|
||||
s32 timeout_ms;
|
||||
/** TEE flags */
|
||||
u8 tee_flags;
|
||||
/** Reserved for future use */
|
||||
u8 RFU_padding[3];
|
||||
};
|
||||
|
||||
/** MobiCore is idle. No scheduling required */
|
||||
#define MC_FLAG_SCHEDULE_IDLE 0
|
||||
/** MobiCore is non idle, scheduling is required */
|
||||
#define MC_FLAG_SCHEDULE_NON_IDLE 1
|
||||
|
||||
/** MCP buffer structure */
|
||||
struct mcp_buffer {
|
||||
struct mcp_flags flags; /** MobiCore Flags */
|
||||
union mcp_message message; /** MCP message buffer */
|
||||
};
|
||||
|
||||
#endif /* MCP_H_ */
|
91
drivers/gud/MobiCoreDriver/mcinq.h
Normal file
91
drivers/gud/MobiCoreDriver/mcinq.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef NQ_H_
|
||||
#define NQ_H_
|
||||
|
||||
/** \name NQ Size Defines
|
||||
* Minimum and maximum count of elements in the notification queue.
|
||||
*/
|
||||
#define MIN_NQ_ELEM 1 /** Minimum notification queue elements */
|
||||
#define MAX_NQ_ELEM 64 /** Maximum notification queue elements */
|
||||
|
||||
/* Compute notification queue size in bytes from its number of elements */
|
||||
#define NQ_SIZE(n) (2 * (sizeof(struct notification_queue_header)\
|
||||
+ (n) * sizeof(struct notification)))
|
||||
|
||||
/** \name NQ Length Defines
|
||||
* Note that there is one queue for NWd->SWd and one queue for SWd->NWd
|
||||
*/
|
||||
/** Minimum size for the notification queue data structure */
|
||||
#define MIN_NQ_LEN NQ_SIZE(MIN_NQ_ELEM)
|
||||
/** Maximum size for the notification queue data structure */
|
||||
#define MAX_NQ_LEN NQ_SIZE(MAX_NQ_ELEM)
|
||||
|
||||
/** \name Session ID Defines
|
||||
* Standard Session IDs.
|
||||
*/
|
||||
/** MCP session ID, used to communicate with MobiCore (e.g. to start/stop TA) */
|
||||
#define SID_MCP 0
|
||||
/** Invalid session id, returned in case of error */
|
||||
#define SID_INVALID 0xffffffff
|
||||
|
||||
/** Notification data structure */
|
||||
struct notification {
|
||||
u32 session_id; /** Session ID */
|
||||
s32 payload; /** Additional notification info */
|
||||
};
|
||||
|
||||
/** Notification payload codes.
|
||||
* 0 indicated a plain simple notification,
|
||||
* a positive value is a termination reason from the task,
|
||||
* a negative value is a termination reason from MobiCore.
|
||||
* Possible negative values are given below.
|
||||
*/
|
||||
enum notification_payload {
|
||||
/** task terminated, but exit code is invalid */
|
||||
ERR_INVALID_EXIT_CODE = -1,
|
||||
/** task terminated due to session end, no exit code available */
|
||||
ERR_SESSION_CLOSE = -2,
|
||||
/** task terminated due to invalid operation */
|
||||
ERR_INVALID_OPERATION = -3,
|
||||
/** session ID is unknown */
|
||||
ERR_INVALID_SID = -4,
|
||||
/** session is not active */
|
||||
ERR_SID_NOT_ACTIVE = -5,
|
||||
/** session was force-killed (due to an administrative command). */
|
||||
ERR_SESSION_KILLED = -6,
|
||||
};
|
||||
|
||||
/** Declaration of the notification queue header.
|
||||
* layout as specified in the data structure specification.
|
||||
*/
|
||||
struct notification_queue_header {
|
||||
u32 write_cnt; /** Write counter */
|
||||
u32 read_cnt; /** Read counter */
|
||||
u32 queue_size; /** Queue size */
|
||||
};
|
||||
|
||||
/** Queue struct which defines a queue object.
|
||||
* The queue struct is accessed by the queue<operation> type of
|
||||
* function. elementCnt must be a power of two and the power needs
|
||||
* to be smaller than power of u32 (obviously 32).
|
||||
*/
|
||||
struct notification_queue {
|
||||
struct notification_queue_header hdr; /** Queue header */
|
||||
struct notification notification[MIN_NQ_ELEM]; /** Elements */
|
||||
};
|
||||
|
||||
#endif /** NQ_H_ */
|
31
drivers/gud/MobiCoreDriver/mcitime.h
Normal file
31
drivers/gud/MobiCoreDriver/mcitime.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2015-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MCITIME_H_
|
||||
#define MCITIME_H_
|
||||
|
||||
/*
|
||||
* Trustonic TEE RICH OS Time:
|
||||
* -seconds and nanoseconds since Jan 1, 1970, UTC
|
||||
* -monotonic counter
|
||||
*/
|
||||
struct mcp_time {
|
||||
u64 wall_clock_seconds;
|
||||
u64 wall_clock_nsec;
|
||||
u64 monotonic_seconds;
|
||||
u64 monotonic_nsec;
|
||||
};
|
||||
|
||||
#endif /* MCITIME_H_ */
|
143
drivers/gud/MobiCoreDriver/mcloadformat.h
Normal file
143
drivers/gud/MobiCoreDriver/mcloadformat.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef MCLOADFORMAT_H_
|
||||
#define MCLOADFORMAT_H_
|
||||
|
||||
/** Trustlet Blob length info */
|
||||
#define MC_TLBLOBLEN_MAGIC 0x7672746C /* Magic for SWd: vrtl */
|
||||
#define MAX_SO_CONT_SIZE 512 /* Max size for a container */
|
||||
|
||||
/** MCLF magic */
|
||||
/**< "MCLF" in big endian integer representation */
|
||||
#define MC_SERVICE_HEADER_MAGIC_BE \
|
||||
((uint32_t)('M' | ('C' << 8) | ('L' << 16) | ('F' << 24)))
|
||||
/**< "MCLF" in little endian integer representation */
|
||||
#define MC_SERVICE_HEADER_MAGIC_LE \
|
||||
((uint32_t)(('M' << 24) | ('C' << 16) | ('L' << 8) | 'F'))
|
||||
|
||||
/** MCLF flags */
|
||||
/**< Loaded service cannot be unloaded from MobiCore. */
|
||||
#define MC_SERVICE_HEADER_FLAGS_PERMANENT BIT(0)
|
||||
/**< Service has no WSM control interface. */
|
||||
#define MC_SERVICE_HEADER_FLAGS_NO_CONTROL_INTERFACE BIT(1)
|
||||
/**< Service can be debugged. */
|
||||
#define MC_SERVICE_HEADER_FLAGS_DEBUGGABLE BIT(2)
|
||||
/**< New-layout trusted application or trusted driver. */
|
||||
#define MC_SERVICE_HEADER_FLAGS_EXTENDED_LAYOUT BIT(3)
|
||||
|
||||
/** Service type.
|
||||
* The service type defines the type of executable.
|
||||
*/
|
||||
enum service_type {
|
||||
SERVICE_TYPE_ILLEGAL = 0,
|
||||
SERVICE_TYPE_DRIVER = 1,
|
||||
SERVICE_TYPE_SP_TRUSTLET = 2,
|
||||
SERVICE_TYPE_SYSTEM_TRUSTLET = 3,
|
||||
SERVICE_TYPE_MIDDLEWARE = 4,
|
||||
SERVICE_TYPE_LAST_ENTRY = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* Descriptor for a memory segment.
|
||||
*/
|
||||
struct segment_descriptor {
|
||||
u32 start; /**< Virtual start address */
|
||||
u32 len; /**< Segment length in bytes */
|
||||
};
|
||||
|
||||
/**
|
||||
* MCLF intro for data structure identification.
|
||||
* Must be the first element of a valid MCLF file.
|
||||
*/
|
||||
struct mclf_intro {
|
||||
u32 magic; /**< Header magic value ASCII "MCLF" */
|
||||
u32 version; /**< Version the MCLF header struct */
|
||||
};
|
||||
|
||||
/**
|
||||
* @defgroup MCLF_VER_V2 MCLF Version 32
|
||||
* @ingroup MCLF_VER
|
||||
*
|
||||
* @addtogroup MCLF_VER_V2
|
||||
*/
|
||||
|
||||
/*
|
||||
* GP TA identity.
|
||||
*/
|
||||
struct identity {
|
||||
/**< GP TA login type */
|
||||
u32 login_type;
|
||||
/**< GP TA login data */
|
||||
u8 login_data[16];
|
||||
};
|
||||
|
||||
/**
|
||||
* Version 2.1/2.2 MCLF header.
|
||||
*/
|
||||
struct mclf_header_v2 {
|
||||
/**< MCLF header start with the mandatory intro */
|
||||
struct mclf_intro intro;
|
||||
/**< Service flags */
|
||||
u32 flags;
|
||||
/**< Type of memory the service must be executed from */
|
||||
u32 mem_type;
|
||||
/**< Type of service */
|
||||
enum service_type service_type;
|
||||
/**< Number of instances which can be run simultaneously */
|
||||
u32 num_instances;
|
||||
/**< Loadable service unique identifier (UUID) */
|
||||
struct mc_uuid_t uuid;
|
||||
/**< If the service_type is SERVICE_TYPE_DRIVER the Driver ID is used */
|
||||
u32 driver_id;
|
||||
/**<
|
||||
* Number of threads (N) in a service:
|
||||
* SERVICE_TYPE_SP_TRUSTLET: N = 1
|
||||
* SERVICE_TYPE_SYSTEM_TRUSTLET: N = 1
|
||||
* SERVICE_TYPE_DRIVER: N >= 1
|
||||
*/
|
||||
u32 num_threads;
|
||||
/**< Virtual text segment */
|
||||
struct segment_descriptor text;
|
||||
/**< Virtual data segment */
|
||||
struct segment_descriptor data;
|
||||
/**< Length of the BSS segment in bytes. MUST be at least 8 byte */
|
||||
u32 bss_len;
|
||||
/**< Virtual start address of service code */
|
||||
u32 entry;
|
||||
/**< Version of the interface the driver exports */
|
||||
u32 service_version;
|
||||
};
|
||||
|
||||
/**
|
||||
* @addtogroup MCLF
|
||||
*/
|
||||
|
||||
/** MCLF header */
|
||||
union mclf_header {
|
||||
/**< Intro for data identification */
|
||||
struct mclf_intro intro;
|
||||
/**< Version 2 header */
|
||||
struct mclf_header_v2 mclf_header_v2;
|
||||
};
|
||||
|
||||
struct mc_blob_len_info {
|
||||
u32 magic; /**< New blob format magic number */
|
||||
u32 root_size; /**< Root container size */
|
||||
u32 sp_size; /**< SP container size */
|
||||
u32 ta_size; /**< TA container size */
|
||||
u32 reserved[4]; /**< Reserved for further Use */
|
||||
};
|
||||
|
||||
#endif /* MCLOADFORMAT_H_ */
|
1038
drivers/gud/MobiCoreDriver/mcp.c
Normal file
1038
drivers/gud/MobiCoreDriver/mcp.c
Normal file
File diff suppressed because it is too large
Load diff
114
drivers/gud/MobiCoreDriver/mcp.h
Normal file
114
drivers/gud/MobiCoreDriver/mcp.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2020 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_MCP_H_
|
||||
#define _MC_MCP_H_
|
||||
|
||||
#include "mcloadformat.h" /* struct identity */
|
||||
#include "nq.h"
|
||||
|
||||
struct tee_mmu;
|
||||
|
||||
/* Structure to hold the TA/driver information at open */
|
||||
struct mcp_open_info {
|
||||
enum {
|
||||
TEE_MC_UUID,
|
||||
TEE_MC_TA,
|
||||
TEE_MC_DRIVER,
|
||||
TEE_MC_DRIVER_UUID,
|
||||
} type;
|
||||
/* TA/driver */
|
||||
const struct mc_uuid_t *uuid;
|
||||
u32 spid;
|
||||
uintptr_t va;
|
||||
size_t len;
|
||||
/* TCI */
|
||||
uintptr_t tci_va;
|
||||
size_t tci_len;
|
||||
struct tee_mmu *tci_mmu;
|
||||
/* Origin */
|
||||
int user;
|
||||
};
|
||||
|
||||
/* Structure to hold the TA/driver descriptor to pass to MCP */
|
||||
struct tee_object {
|
||||
u32 length; /* Total length */
|
||||
u32 header_length; /* Length of header before payload */
|
||||
u8 data[]; /* Header followed by payload */
|
||||
};
|
||||
|
||||
/* Structure to hold all mapped buffer data to pass to MCP */
|
||||
struct mcp_buffer_map {
|
||||
u64 addr; /** Page-aligned PA, or VA */
|
||||
unsigned long nr_pages; /** Total number of pages mapped */
|
||||
u32 secure_va; /** SWd virtual address */
|
||||
u32 offset; /** Data offset inside the first page */
|
||||
u32 length; /** Length of the data */
|
||||
u32 type; /** Type of MMU */
|
||||
u32 flags; /** Flags (typically read/write) */
|
||||
struct tee_mmu *mmu; /** MMU from which the map was made */
|
||||
};
|
||||
|
||||
struct mcp_session {
|
||||
/* Notification queue session */
|
||||
struct nq_session nq_session;
|
||||
/* Session ID */
|
||||
u32 sid;
|
||||
/* Sessions list (protected by mcp sessions_lock) */
|
||||
struct list_head list;
|
||||
/* Notification waiter lock */
|
||||
struct mutex notif_wait_lock; /* Only one at a time */
|
||||
/* Notification received */
|
||||
struct completion completion;
|
||||
/* Notification lock */
|
||||
struct mutex exit_code_lock;
|
||||
/* Last notification */
|
||||
s32 exit_code;
|
||||
/* Session state (protected by mcp sessions_lock) */
|
||||
enum mcp_session_state {
|
||||
MCP_SESSION_RUNNING,
|
||||
MCP_SESSION_CLOSE_FAILED,
|
||||
MCP_SESSION_CLOSED,
|
||||
} state;
|
||||
/* Notification counter */
|
||||
u32 notif_count;
|
||||
};
|
||||
|
||||
/* Init for the mcp_session structure */
|
||||
void mcp_session_init(struct mcp_session *session);
|
||||
|
||||
/* Commands */
|
||||
int mcp_get_version(struct mc_version_info *version_info);
|
||||
int mcp_load_token(uintptr_t data, const struct mcp_buffer_map *buffer_map);
|
||||
int mcp_load_check(const struct tee_object *obj,
|
||||
const struct mcp_buffer_map *buffer_map);
|
||||
int mcp_load_key_so(uintptr_t data, const struct mcp_buffer_map *buffer_map);
|
||||
int mcp_open_session(struct mcp_session *session, struct mcp_open_info *info,
|
||||
bool *tci_in_use);
|
||||
int mcp_close_session(struct mcp_session *session);
|
||||
void mcp_cleanup_session(struct mcp_session *session);
|
||||
int mcp_map(u32 session_id, struct tee_mmu *mmu, u32 *sva);
|
||||
int mcp_unmap(u32 session_id, const struct mcp_buffer_map *map);
|
||||
int mcp_notify(struct mcp_session *mcp_session);
|
||||
int mcp_wait(struct mcp_session *session, s32 timeout, int silent_expiry);
|
||||
int mcp_get_err(struct mcp_session *session, s32 *err);
|
||||
|
||||
/* Initialisation/cleanup */
|
||||
int mcp_init(void);
|
||||
void mcp_exit(void);
|
||||
int mcp_start(void);
|
||||
void mcp_stop(void);
|
||||
|
||||
#endif /* _MC_MCP_H_ */
|
754
drivers/gud/MobiCoreDriver/mmu.c
Normal file
754
drivers/gud/MobiCoreDriver/mmu.c
Normal file
|
@ -0,0 +1,754 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2013-2020 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/version.h>
|
||||
#ifdef CONFIG_DMA_SHARED_BUFFER
|
||||
#include <linux/dma-buf.h>
|
||||
#endif
|
||||
#ifdef CONFIG_ION
|
||||
#ifdef CONFIG_ION_SYSTEM_HEAP /* Android kernel only */
|
||||
#if KERNEL_VERSION(5, 4, 0) < LINUX_VERSION_CODE
|
||||
#include <linux/ion.h>
|
||||
#elif KERNEL_VERSION(4, 11, 12) < LINUX_VERSION_CODE
|
||||
#include "../../drivers/staging/android/ion/ion.h"
|
||||
#elif KERNEL_VERSION(3, 14, 0) < LINUX_VERSION_CODE
|
||||
#include "../../drivers/staging/android/ion/ion_priv.h"
|
||||
#endif /* KERNEL_VERSION */
|
||||
#else /* CONFIG_ION_SYSTEM_HEAP */
|
||||
#if KERNEL_VERSION(5, 4, 0) < LINUX_VERSION_CODE
|
||||
#include "../../drivers/staging/android/ion/ion.h"
|
||||
#elif KERNEL_VERSION(4, 11, 12) < LINUX_VERSION_CODE
|
||||
#include "../../drivers/staging/android/ion/ion.h"
|
||||
#elif KERNEL_VERSION(3, 14, 0) < LINUX_VERSION_CODE
|
||||
/* very old Android kernel without ION_SYSTEM_HEAP falls here */
|
||||
#include "../../drivers/staging/android/ion/ion_priv.h"
|
||||
#endif
|
||||
#endif /* CONFIG_ION_SYSTEM_HEAP */
|
||||
#endif /* CONFIG_ION */
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
/* To get the MFN */
|
||||
#include <linux/pfn.h>
|
||||
#include <xen/page.h>
|
||||
#endif
|
||||
|
||||
#include "mc_user.h"
|
||||
|
||||
#include "mcimcp.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "mcp.h" /* mcp_buffer_map */
|
||||
#include "mmu.h"
|
||||
|
||||
#define PHYS_48BIT_MASK (BIT(48) - 1)
|
||||
|
||||
/* Common */
|
||||
#define MMU_BUFFERABLE BIT(2) /* AttrIndx[0] */
|
||||
#define MMU_CACHEABLE BIT(3) /* AttrIndx[1] */
|
||||
#define MMU_EXT_NG BIT(11) /* ARMv6 and higher */
|
||||
|
||||
/* LPAE */
|
||||
#define MMU_TYPE_PAGE (3 << 0)
|
||||
#define MMU_NS BIT(5)
|
||||
#define MMU_AP_RW_ALL BIT(6) /* AP[2:1], RW, at any privilege level */
|
||||
#define MMU_AP2_RO BIT(7)
|
||||
#define MMU_EXT_SHARED_64 (3 << 8) /* SH[1:0], inner shareable */
|
||||
#define MMU_EXT_AF BIT(10) /* Access Flag */
|
||||
#define MMU_EXT_XN (((u64)1) << 54) /* XN */
|
||||
|
||||
/* Non-LPAE */
|
||||
#define MMU_TYPE_EXT (3 << 0) /* v5 */
|
||||
#define MMU_TYPE_SMALL (2 << 0)
|
||||
#define MMU_EXT_AP0 BIT(4)
|
||||
#define MMU_EXT_AP1 (2 << 4)
|
||||
#define MMU_EXT_AP2 BIT(9)
|
||||
#define MMU_EXT_TEX(x) ((x) << 6) /* v5 */
|
||||
#define MMU_EXT_SHARED_32 BIT(10) /* ARMv6 and higher */
|
||||
|
||||
/* ION */
|
||||
/* Trustonic Specific flag to detect ION mem */
|
||||
#define MMU_ION_BUF BIT(24)
|
||||
|
||||
/*
|
||||
* Specific case for kernel 4.4.168 that does not have the same
|
||||
* get_user_pages() implementation
|
||||
*/
|
||||
#if KERNEL_VERSION(4, 4, 167) < LINUX_VERSION_CODE && \
|
||||
KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE
|
||||
static inline long gup_local(struct mm_struct *mm, uintptr_t start,
|
||||
unsigned long nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
unsigned int gup_flags = 0;
|
||||
|
||||
if (write)
|
||||
gup_flags |= FOLL_WRITE;
|
||||
|
||||
return get_user_pages(NULL, mm, start, nr_pages, gup_flags, pages,
|
||||
NULL);
|
||||
}
|
||||
#elif KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE
|
||||
static inline long gup_local(struct mm_struct *mm, uintptr_t start,
|
||||
unsigned long nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
return get_user_pages(NULL, mm, start, nr_pages, write, 0, pages, NULL);
|
||||
}
|
||||
#elif KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE
|
||||
static inline long gup_local(struct mm_struct *mm, uintptr_t start,
|
||||
unsigned long nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
unsigned int gup_flags = 0;
|
||||
|
||||
if (write)
|
||||
gup_flags |= FOLL_WRITE;
|
||||
/* gup_flags |= FOLL_CMA; */
|
||||
|
||||
return get_user_pages_remote(NULL, mm, start, nr_pages, gup_flags,
|
||||
0, pages, NULL);
|
||||
}
|
||||
#elif KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE
|
||||
static inline long gup_local(struct mm_struct *mm, uintptr_t start,
|
||||
unsigned long nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
unsigned int gup_flags = 0;
|
||||
|
||||
if (write)
|
||||
gup_flags |= FOLL_WRITE;
|
||||
|
||||
return get_user_pages_remote(NULL, mm, start, nr_pages, gup_flags,
|
||||
pages, NULL);
|
||||
}
|
||||
#elif KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE
|
||||
static inline long gup_local(struct mm_struct *mm, uintptr_t start,
|
||||
unsigned long nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
unsigned int gup_flags = 0;
|
||||
|
||||
if (write)
|
||||
gup_flags |= FOLL_WRITE;
|
||||
|
||||
return get_user_pages_remote(NULL, mm, start, nr_pages, gup_flags,
|
||||
pages, NULL, NULL);
|
||||
}
|
||||
#elif KERNEL_VERSION(5, 10, 0) > LINUX_VERSION_CODE
|
||||
static inline long gup_local(struct mm_struct *mm, uintptr_t start,
|
||||
unsigned long nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
unsigned int gup_flags = 0;
|
||||
|
||||
gup_flags |= FOLL_LONGTERM;
|
||||
if (write)
|
||||
gup_flags |= FOLL_WRITE;
|
||||
|
||||
return get_user_pages(start, nr_pages, gup_flags, pages, NULL);
|
||||
}
|
||||
#else
|
||||
static inline long gup_local(struct mm_struct *mm, uintptr_t start,
|
||||
unsigned long nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
unsigned int gup_flags = 0;
|
||||
|
||||
gup_flags |= FOLL_LONGTERM;
|
||||
if (write)
|
||||
gup_flags |= FOLL_WRITE;
|
||||
|
||||
return pin_user_pages(start, nr_pages, gup_flags, pages, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline long gup_local_repeat(struct mm_struct *mm, uintptr_t start,
|
||||
unsigned long nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
int retries = 10;
|
||||
long ret = 0;
|
||||
|
||||
while (retries--) {
|
||||
ret = gup_local(mm, start, nr_pages, write, pages);
|
||||
|
||||
if (-EBUSY != ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* A table that could be either a pmd or pte
|
||||
*/
|
||||
union mmu_table {
|
||||
u64 *entries; /* Array of PTEs */
|
||||
/* Array of pages */
|
||||
struct page **pages;
|
||||
/* Array of VAs */
|
||||
uintptr_t *vas;
|
||||
/* Address of table */
|
||||
void *addr;
|
||||
/* Page for table */
|
||||
unsigned long page;
|
||||
};
|
||||
|
||||
/*
|
||||
* MMU table allocated to the Daemon or a TLC describing a world shared
|
||||
* buffer.
|
||||
* When users map a malloc()ed area into SWd, a MMU table is allocated.
|
||||
* In addition, the area of maximum 1MB virtual address space is mapped into
|
||||
* the MMU table and a handle for this table is returned to the user.
|
||||
*/
|
||||
struct tee_mmu {
|
||||
struct kref kref;
|
||||
/* Array of pages that hold buffer ptes*/
|
||||
union mmu_table pte_tables[PMD_ENTRIES_MAX];
|
||||
/* Actual number of ptes tables */
|
||||
size_t nr_pmd_entries;
|
||||
/* Contains phys @ of ptes tables */
|
||||
union mmu_table pmd_table;
|
||||
struct tee_deleter *deleter; /* Xen map to free */
|
||||
unsigned long nr_pages;
|
||||
int pages_created; /* Leak check */
|
||||
int pages_locked; /* Leak check */
|
||||
u32 offset;
|
||||
u32 length;
|
||||
u32 flags;
|
||||
/* Pages are from user space */
|
||||
bool user;
|
||||
bool use_pages_and_vas;
|
||||
/* ION case only */
|
||||
struct dma_buf *dma_buf;
|
||||
struct dma_buf_attachment *attach;
|
||||
struct sg_table *sgt;
|
||||
};
|
||||
|
||||
static void tee_mmu_delete(struct tee_mmu *mmu)
|
||||
{
|
||||
unsigned long chunk, nr_pages_left = mmu->nr_pages;
|
||||
|
||||
#ifdef CONFIG_DMA_SHARED_BUFFER
|
||||
if (mmu->dma_buf) {
|
||||
dma_buf_unmap_attachment(mmu->attach, mmu->sgt,
|
||||
DMA_BIDIRECTIONAL);
|
||||
dma_buf_detach(mmu->dma_buf, mmu->attach);
|
||||
dma_buf_put(mmu->dma_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Release all locked user space pages */
|
||||
for (chunk = 0; chunk < mmu->nr_pmd_entries; chunk++) {
|
||||
union mmu_table *pte_table = &mmu->pte_tables[chunk];
|
||||
unsigned long nr_pages = nr_pages_left;
|
||||
|
||||
if (nr_pages > PTE_ENTRIES_MAX)
|
||||
nr_pages = PTE_ENTRIES_MAX;
|
||||
|
||||
nr_pages_left -= nr_pages;
|
||||
|
||||
if (!pte_table->page)
|
||||
break;
|
||||
|
||||
if (mmu->user && mmu->use_pages_and_vas) {
|
||||
struct page **page = pte_table->pages;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++, page++)
|
||||
put_page(*page);
|
||||
|
||||
mmu->pages_locked -= nr_pages;
|
||||
} else if (mmu->user) {
|
||||
u64 *pte64 = pte_table->entries;
|
||||
pte_t pte;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
#if (KERNEL_VERSION(4, 7, 0) > LINUX_VERSION_CODE) || defined(CONFIG_ARM)
|
||||
{
|
||||
pte = *pte64++;
|
||||
/* Unused entries are 0 */
|
||||
if (!pte)
|
||||
break;
|
||||
}
|
||||
#else
|
||||
{
|
||||
pte.pte = *pte64++;
|
||||
/* Unused entries are 0 */
|
||||
if (!pte.pte)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* pte_page() cannot return NULL */
|
||||
#if KERNEL_VERSION(5, 10, 0) > LINUX_VERSION_CODE
|
||||
put_page(pte_page(pte));
|
||||
#else
|
||||
unpin_user_page(pte_page(pte));
|
||||
#endif
|
||||
}
|
||||
|
||||
mmu->pages_locked -= nr_pages;
|
||||
}
|
||||
|
||||
free_page(pte_table->page);
|
||||
mmu->pages_created--;
|
||||
}
|
||||
|
||||
if (mmu->pmd_table.page) {
|
||||
free_page(mmu->pmd_table.page);
|
||||
mmu->pages_created--;
|
||||
}
|
||||
|
||||
if (mmu->pages_created || mmu->pages_locked)
|
||||
mc_dev_err(-EUCLEAN,
|
||||
"leak detected: still in use %d, still locked %d",
|
||||
mmu->pages_created, mmu->pages_locked);
|
||||
|
||||
if (mmu->deleter)
|
||||
mmu->deleter->delete(mmu->deleter->object);
|
||||
|
||||
kfree(mmu);
|
||||
|
||||
/* Decrement debug counter */
|
||||
atomic_dec(&g_ctx.c_mmus);
|
||||
}
|
||||
|
||||
static struct tee_mmu *tee_mmu_create_common(const struct mcp_buffer_map *b_map)
|
||||
{
|
||||
struct tee_mmu *mmu;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if (b_map->nr_pages > (PMD_ENTRIES_MAX * PTE_ENTRIES_MAX)) {
|
||||
ret = -EINVAL;
|
||||
mc_dev_err(ret, "data mapping exceeds %d pages: %lu",
|
||||
PMD_ENTRIES_MAX * PTE_ENTRIES_MAX, b_map->nr_pages);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* Allocate the struct */
|
||||
mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
|
||||
if (!mmu)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* Increment debug counter */
|
||||
atomic_inc(&g_ctx.c_mmus);
|
||||
kref_init(&mmu->kref);
|
||||
|
||||
/* The Xen front-end does not use PTEs */
|
||||
if (is_xen_domu())
|
||||
mmu->use_pages_and_vas = true;
|
||||
|
||||
/* Buffer info */
|
||||
mmu->offset = b_map->offset;
|
||||
mmu->length = b_map->length;
|
||||
mmu->flags = b_map->flags;
|
||||
|
||||
/* Pages info */
|
||||
mmu->nr_pages = b_map->nr_pages;
|
||||
mmu->nr_pmd_entries = (mmu->nr_pages + PTE_ENTRIES_MAX - 1) /
|
||||
PTE_ENTRIES_MAX;
|
||||
mc_dev_devel("mmu->nr_pages %lu num_ptes_pages %zu",
|
||||
mmu->nr_pages, mmu->nr_pmd_entries);
|
||||
|
||||
/* Allocate a page for the L1 table, always used for DomU */
|
||||
mmu->pmd_table.page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!mmu->pmd_table.page)
|
||||
goto end;
|
||||
|
||||
mmu->pages_created++;
|
||||
|
||||
return mmu;
|
||||
|
||||
end:
|
||||
tee_mmu_delete(mmu);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static bool mmu_get_dma_buffer(struct tee_mmu *mmu, int va)
|
||||
{
|
||||
#ifdef CONFIG_DMA_SHARED_BUFFER
|
||||
struct dma_buf *buf;
|
||||
|
||||
buf = dma_buf_get(va);
|
||||
if (IS_ERR(buf))
|
||||
return false;
|
||||
|
||||
mmu->dma_buf = buf;
|
||||
mmu->attach = dma_buf_attach(mmu->dma_buf, g_ctx.mcd);
|
||||
if (IS_ERR(mmu->attach))
|
||||
goto err_attach;
|
||||
|
||||
mmu->sgt = dma_buf_map_attachment(mmu->attach, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(mmu->sgt))
|
||||
goto err_map;
|
||||
|
||||
return true;
|
||||
|
||||
err_map:
|
||||
dma_buf_detach(mmu->dma_buf, mmu->attach);
|
||||
|
||||
err_attach:
|
||||
dma_buf_put(mmu->dma_buf);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate MMU table and map buffer into it.
|
||||
* That is, create respective table entries.
|
||||
*/
|
||||
struct tee_mmu *tee_mmu_create(struct mm_struct *mm,
|
||||
const struct mc_ioctl_buffer *buf)
|
||||
{
|
||||
struct tee_mmu *mmu;
|
||||
const void *data = (const void *)(uintptr_t)buf->va;
|
||||
const void *reader = (const void *)((uintptr_t)data & PAGE_MASK);
|
||||
struct page **pages; /* Same as below, conveniently typed */
|
||||
unsigned long pages_page = 0; /* Page to contain the page pointers */
|
||||
unsigned long chunk;
|
||||
struct mcp_buffer_map b_map = {
|
||||
.offset = (u32)(buf->va & ~PAGE_MASK),
|
||||
.length = buf->len,
|
||||
.flags = buf->flags,
|
||||
};
|
||||
bool writeable = buf->flags & MC_IO_MAP_OUTPUT;
|
||||
int ret = 0;
|
||||
|
||||
#ifndef CONFIG_DMA_SHARED_BUFFER
|
||||
if (buf->flags & MMU_ION_BUF) {
|
||||
mc_dev_err(-EINVAL, "ION buffers not supported by kernel");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check input arguments */
|
||||
if (!(buf->flags & MMU_ION_BUF) && !buf->va)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (buf->flags & MMU_ION_BUF)
|
||||
/* buf->va is not a valid address. ION buffers are aligned */
|
||||
b_map.offset = 0;
|
||||
|
||||
/* Allocate the struct */
|
||||
b_map.nr_pages = PAGE_ALIGN(b_map.offset + b_map.length) / PAGE_SIZE;
|
||||
/* Allow Registered Shared mem with valid pointer and zero size. */
|
||||
if (!b_map.nr_pages)
|
||||
b_map.nr_pages = 1;
|
||||
|
||||
mmu = tee_mmu_create_common(&b_map);
|
||||
if (IS_ERR(mmu))
|
||||
return mmu;
|
||||
|
||||
if (buf->flags & MMU_ION_BUF) {
|
||||
mc_dev_devel("Buffer is ION");
|
||||
/* Buffer is ION -
|
||||
* va is the client's dma_buf fd, which should be converted
|
||||
* to a struct sg_table * directly.
|
||||
*/
|
||||
if (!mmu_get_dma_buffer(mmu, buf->va)) {
|
||||
mc_dev_err(ret, "mmu_get_dma_buffer failed");
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
/* Get a page to store page pointers */
|
||||
pages_page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!pages_page) {
|
||||
ret = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
mmu->pages_created++;
|
||||
|
||||
pages = (struct page **)pages_page;
|
||||
for (chunk = 0; chunk < mmu->nr_pmd_entries; chunk++) {
|
||||
unsigned long nr_pages;
|
||||
int i;
|
||||
|
||||
/* Size to map for this chunk */
|
||||
if (chunk == (mmu->nr_pmd_entries - 1))
|
||||
nr_pages = ((mmu->nr_pages - 1) % PTE_ENTRIES_MAX) + 1;
|
||||
else
|
||||
nr_pages = PTE_ENTRIES_MAX;
|
||||
|
||||
/* Allocate a page to hold ptes that describe buffer pages */
|
||||
mmu->pte_tables[chunk].page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!mmu->pte_tables[chunk].page) {
|
||||
ret = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
mmu->pages_created++;
|
||||
|
||||
/* Add page address to pmd table if needed */
|
||||
if (mmu->use_pages_and_vas)
|
||||
mmu->pmd_table.vas[chunk] =
|
||||
mmu->pte_tables[chunk].page;
|
||||
else
|
||||
mmu->pmd_table.entries[chunk] =
|
||||
virt_to_phys(mmu->pte_tables[chunk].addr);
|
||||
|
||||
/* Get pages */
|
||||
if (mmu->dma_buf) {
|
||||
/* Buffer is ION */
|
||||
struct sg_mapping_iter miter;
|
||||
struct page **page_ptr;
|
||||
unsigned int cnt = 0;
|
||||
unsigned int global_cnt = 0;
|
||||
|
||||
page_ptr = pages;
|
||||
sg_miter_start(&miter, mmu->sgt->sgl,
|
||||
mmu->sgt->nents,
|
||||
SG_MITER_FROM_SG);
|
||||
|
||||
while (sg_miter_next(&miter)) {
|
||||
if (((global_cnt) >=
|
||||
(PTE_ENTRIES_MAX * chunk)) &&
|
||||
cnt < nr_pages) {
|
||||
page_ptr[cnt] = miter.page;
|
||||
cnt++;
|
||||
}
|
||||
global_cnt++;
|
||||
}
|
||||
sg_miter_stop(&miter);
|
||||
} else if (mm) {
|
||||
long gup_ret;
|
||||
|
||||
/* Buffer was allocated in user space */
|
||||
#if KERNEL_VERSION(5, 7, 19) < LINUX_VERSION_CODE
|
||||
down_read(&mm->mmap_lock);
|
||||
#else
|
||||
down_read(&mm->mmap_sem);
|
||||
#endif
|
||||
/*
|
||||
* Always try to map read/write from a Linux PoV, so
|
||||
* Linux creates (page faults) the underlying pages if
|
||||
* missing.
|
||||
*/
|
||||
gup_ret = gup_local_repeat(mm, (uintptr_t)reader,
|
||||
nr_pages, 1, pages);
|
||||
if ((gup_ret == -EFAULT) && !writeable) {
|
||||
/*
|
||||
* If mapping read/write fails, and the buffer
|
||||
* is to be shared as input only, try to map
|
||||
* again read-only.
|
||||
*/
|
||||
gup_ret = gup_local_repeat(mm,
|
||||
(uintptr_t)reader,
|
||||
nr_pages, 0, pages);
|
||||
}
|
||||
#if KERNEL_VERSION(5, 7, 19) < LINUX_VERSION_CODE
|
||||
up_read(&mm->mmap_lock);
|
||||
#else
|
||||
up_read(&mm->mmap_sem);
|
||||
#endif
|
||||
if (gup_ret < 0) {
|
||||
ret = gup_ret;
|
||||
mc_dev_err(ret, "failed to get user pages @%p",
|
||||
reader);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* check if we could lock all pages. */
|
||||
if (gup_ret != nr_pages) {
|
||||
mc_dev_err((int)gup_ret,
|
||||
"failed to get user pages");
|
||||
#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE
|
||||
release_pages(pages, gup_ret, 0);
|
||||
#else
|
||||
release_pages(pages, gup_ret);
|
||||
#endif
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
reader += nr_pages * PAGE_SIZE;
|
||||
mmu->user = true;
|
||||
mmu->pages_locked += nr_pages;
|
||||
} else if (is_vmalloc_addr(data)) {
|
||||
/* Buffer vmalloc'ed in kernel space */
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = vmalloc_to_page(reader);
|
||||
|
||||
if (!page) {
|
||||
ret = -EINVAL;
|
||||
mc_dev_err(ret,
|
||||
"failed to map address");
|
||||
goto end;
|
||||
}
|
||||
|
||||
pages[i] = page;
|
||||
reader += PAGE_SIZE;
|
||||
}
|
||||
} else {
|
||||
/* Buffer kmalloc'ed in kernel space */
|
||||
struct page *page = virt_to_page(reader);
|
||||
|
||||
reader += nr_pages * PAGE_SIZE;
|
||||
for (i = 0; i < nr_pages; i++)
|
||||
pages[i] = page++;
|
||||
}
|
||||
|
||||
/* Create Table of physical addresses*/
|
||||
if (mmu->use_pages_and_vas) {
|
||||
memcpy(mmu->pte_tables[chunk].pages, pages,
|
||||
nr_pages * sizeof(*pages));
|
||||
} else {
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
mmu->pte_tables[chunk].entries[i] =
|
||||
page_to_phys(pages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (pages_page) {
|
||||
free_page(pages_page);
|
||||
mmu->pages_created--;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
tee_mmu_delete(mmu);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
mc_dev_devel(
|
||||
"created mmu %p: %s va %llx len %u off %u flg %x pmd table %lx",
|
||||
mmu, mmu->user ? "user" : "kernel", buf->va, mmu->length,
|
||||
mmu->offset, mmu->flags, mmu->pmd_table.page);
|
||||
return mmu;
|
||||
}
|
||||
|
||||
struct tee_mmu *tee_mmu_wrap(struct tee_deleter *deleter, struct page **pages,
|
||||
const struct mcp_buffer_map *b_map)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
#ifdef CONFIG_XEN
|
||||
struct tee_mmu *mmu;
|
||||
unsigned long chunk, nr_pages_left;
|
||||
|
||||
/* Allocate the struct */
|
||||
mmu = tee_mmu_create_common(b_map);
|
||||
if (IS_ERR(mmu))
|
||||
return mmu;
|
||||
|
||||
nr_pages_left = mmu->nr_pages;
|
||||
for (chunk = 0; chunk < mmu->nr_pmd_entries; chunk++) {
|
||||
unsigned long nr_pages = nr_pages_left;
|
||||
u64 *pte;
|
||||
int i;
|
||||
|
||||
if (nr_pages > PTE_ENTRIES_MAX)
|
||||
nr_pages = PTE_ENTRIES_MAX;
|
||||
|
||||
nr_pages_left -= nr_pages;
|
||||
|
||||
/* Allocate a page to hold ptes that describe buffer pages */
|
||||
mmu->pte_tables[chunk].page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!mmu->pte_tables[chunk].page) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
mmu->pages_created++;
|
||||
|
||||
/* Add page address to pmd table if needed */
|
||||
mmu->pmd_table.entries[chunk] =
|
||||
virt_to_phys(mmu->pte_tables[chunk].addr);
|
||||
|
||||
/* Convert to PTEs */
|
||||
pte = &mmu->pte_tables[chunk].entries[0];
|
||||
|
||||
for (i = 0; i < nr_pages; i++, pages++, pte++) {
|
||||
unsigned long phys;
|
||||
unsigned long pfn;
|
||||
|
||||
phys = page_to_phys(*pages);
|
||||
#if defined CONFIG_ARM64
|
||||
phys &= PHYS_48BIT_MASK;
|
||||
#endif
|
||||
pfn = PFN_DOWN(phys);
|
||||
*pte = __pfn_to_mfn(pfn) << PAGE_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
mmu->deleter = deleter;
|
||||
mc_dev_devel("wrapped mmu %p: len %u off %u flg %x pmd table %lx",
|
||||
mmu, mmu->length, mmu->offset, mmu->flags,
|
||||
mmu->pmd_table.page);
|
||||
return mmu;
|
||||
|
||||
err:
|
||||
tee_mmu_delete(mmu);
|
||||
#endif
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void tee_mmu_set_deleter(struct tee_mmu *mmu, struct tee_deleter *deleter)
|
||||
{
|
||||
mmu->deleter = deleter;
|
||||
}
|
||||
|
||||
static void tee_mmu_release(struct kref *kref)
|
||||
{
|
||||
struct tee_mmu *mmu = container_of(kref, struct tee_mmu, kref);
|
||||
|
||||
mc_dev_devel("free mmu %p: %s len %u off %u pmd table %lx",
|
||||
mmu, mmu->user ? "user" : "kernel", mmu->length,
|
||||
mmu->offset, mmu->pmd_table.page);
|
||||
tee_mmu_delete(mmu);
|
||||
}
|
||||
|
||||
void tee_mmu_get(struct tee_mmu *mmu)
|
||||
{
|
||||
kref_get(&mmu->kref);
|
||||
}
|
||||
|
||||
void tee_mmu_put(struct tee_mmu *mmu)
|
||||
{
|
||||
kref_put(&mmu->kref, tee_mmu_release);
|
||||
}
|
||||
|
||||
void tee_mmu_buffer(struct tee_mmu *mmu, struct mcp_buffer_map *map)
|
||||
{
|
||||
if (mmu->use_pages_and_vas)
|
||||
map->addr = mmu->pmd_table.page;
|
||||
else
|
||||
map->addr = virt_to_phys(mmu->pmd_table.addr);
|
||||
|
||||
map->secure_va = 0;
|
||||
map->offset = mmu->offset;
|
||||
map->length = mmu->length;
|
||||
map->nr_pages = mmu->nr_pages;
|
||||
map->flags = mmu->flags;
|
||||
map->type = WSM_L1;
|
||||
map->mmu = mmu;
|
||||
}
|
||||
|
||||
int tee_mmu_debug_structs(struct kasnprintf_buf *buf, const struct tee_mmu *mmu)
|
||||
{
|
||||
return kasnprintf(buf,
|
||||
"\t\t\tmmu %pK: %s len %u off %u table %pK\n",
|
||||
mmu, mmu->user ? "user" : "kernel", mmu->length,
|
||||
mmu->offset, (void *)mmu->pmd_table.page);
|
||||
}
|
82
drivers/gud/MobiCoreDriver/mmu.h
Normal file
82
drivers/gud/MobiCoreDriver/mmu.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _TBASE_MEM_H_
|
||||
#define _TBASE_MEM_H_
|
||||
|
||||
/*
|
||||
* This represents the maximum number of entries in a Page Table Entries
|
||||
* array which maps one 4KiB page. Each entry is 64 bits long physical
|
||||
* address with some possible flags. With 512 entries it is possible
|
||||
* to map 2MiB memory block.
|
||||
*/
|
||||
#define PTE_ENTRIES_MAX 512
|
||||
|
||||
/*
|
||||
* This represents the maximum number of entries in a Page Middle Directory
|
||||
* which maps one 4KiB page. Each entry is a 64 bits physical address that
|
||||
* points to a PTE. With 512 entries t is possible to map 1GB memory block.
|
||||
*/
|
||||
#define PMD_ENTRIES_MAX 512
|
||||
|
||||
struct tee_mmu;
|
||||
struct mcp_buffer_map;
|
||||
|
||||
struct tee_deleter {
|
||||
void *object;
|
||||
void (*delete)(void *object);
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocate MMU table and map buffer into it.
|
||||
* That is, create respective table entries.
|
||||
*/
|
||||
struct tee_mmu *tee_mmu_create(struct mm_struct *mm,
|
||||
const struct mc_ioctl_buffer *buf);
|
||||
|
||||
/*
|
||||
* Allocate MMU table and map pages into it.
|
||||
* This is for Xen Dom0 to re-create a buffer with existing pages.
|
||||
*/
|
||||
struct tee_mmu *tee_mmu_wrap(struct tee_deleter *deleter, struct page **pages,
|
||||
const struct mcp_buffer_map *buf);
|
||||
|
||||
/*
|
||||
* Give the MMU an object to release when released
|
||||
*/
|
||||
void tee_mmu_set_deleter(struct tee_mmu *mmu, struct tee_deleter *deleter);
|
||||
|
||||
/*
|
||||
* Gets a reference on a MMU table.
|
||||
*/
|
||||
void tee_mmu_get(struct tee_mmu *mmu);
|
||||
|
||||
/*
|
||||
* Puts a reference on a MMU table.
|
||||
*/
|
||||
void tee_mmu_put(struct tee_mmu *mmu);
|
||||
|
||||
/*
|
||||
* Fill in buffer info for MMU table.
|
||||
*/
|
||||
void tee_mmu_buffer(struct tee_mmu *mmu, struct mcp_buffer_map *map);
|
||||
|
||||
/*
|
||||
* Add info to debug buffer.
|
||||
*/
|
||||
int tee_mmu_debug_structs(struct kasnprintf_buf *buf,
|
||||
const struct tee_mmu *mmu);
|
||||
|
||||
#endif /* _TBASE_MEM_H_ */
|
467
drivers/gud/MobiCoreDriver/mobicore_driver_api.h
Normal file
467
drivers/gud/MobiCoreDriver/mobicore_driver_api.h
Normal file
|
@ -0,0 +1,467 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef _MOBICORE_DRIVER_API_H_
|
||||
#define _MOBICORE_DRIVER_API_H_
|
||||
|
||||
#include "mc_user.h"
|
||||
|
||||
#define __MC_CLIENT_LIB_API
|
||||
|
||||
/*
|
||||
* Return values of MobiCore driver functions.
|
||||
*/
|
||||
enum mc_result {
|
||||
/* Function call succeeded. */
|
||||
MC_DRV_OK = 0,
|
||||
/* No notification available. */
|
||||
MC_DRV_NO_NOTIFICATION = 1,
|
||||
/* Error during notification on communication level. */
|
||||
MC_DRV_ERR_NOTIFICATION = 2,
|
||||
/* Function not implemented. */
|
||||
MC_DRV_ERR_NOT_IMPLEMENTED = 3,
|
||||
/* No more resources available. */
|
||||
MC_DRV_ERR_OUT_OF_RESOURCES = 4,
|
||||
/* Driver initialization failed. */
|
||||
MC_DRV_ERR_INIT = 5,
|
||||
/* Unknown error. */
|
||||
MC_DRV_ERR_UNKNOWN = 6,
|
||||
/* The specified device is unknown. */
|
||||
MC_DRV_ERR_UNKNOWN_DEVICE = 7,
|
||||
/* The specified session is unknown.*/
|
||||
MC_DRV_ERR_UNKNOWN_SESSION = 8,
|
||||
/* The specified operation is not allowed. */
|
||||
MC_DRV_ERR_INVALID_OPERATION = 9,
|
||||
/* The response header from the MC is invalid. */
|
||||
MC_DRV_ERR_INVALID_RESPONSE = 10,
|
||||
/* Function call timed out. */
|
||||
MC_DRV_ERR_TIMEOUT = 11,
|
||||
/* Can not allocate additional memory. */
|
||||
MC_DRV_ERR_NO_FREE_MEMORY = 12,
|
||||
/* Free memory failed. */
|
||||
MC_DRV_ERR_FREE_MEMORY_FAILED = 13,
|
||||
/* Still some open sessions pending. */
|
||||
MC_DRV_ERR_SESSION_PENDING = 14,
|
||||
/* MC daemon not reachable */
|
||||
MC_DRV_ERR_DAEMON_UNREACHABLE = 15,
|
||||
/* The device file of the kernel module could not be opened. */
|
||||
MC_DRV_ERR_INVALID_DEVICE_FILE = 16,
|
||||
/* Invalid parameter. */
|
||||
MC_DRV_ERR_INVALID_PARAMETER = 17,
|
||||
/* Unspecified error from Kernel Module*/
|
||||
MC_DRV_ERR_KERNEL_MODULE = 18,
|
||||
/* Error during mapping of additional bulk memory to session. */
|
||||
MC_DRV_ERR_BULK_MAPPING = 19,
|
||||
/* Error during unmapping of additional bulk memory to session. */
|
||||
MC_DRV_ERR_BULK_UNMAPPING = 20,
|
||||
/* Notification received, exit code available. */
|
||||
MC_DRV_INFO_NOTIFICATION = 21,
|
||||
/* Set up of NWd connection failed. */
|
||||
MC_DRV_ERR_NQ_FAILED = 22,
|
||||
/* Wrong daemon version. */
|
||||
MC_DRV_ERR_DAEMON_VERSION = 23,
|
||||
/* Wrong container version. */
|
||||
MC_DRV_ERR_CONTAINER_VERSION = 24,
|
||||
/* System Trustlet public key is wrong. */
|
||||
MC_DRV_ERR_WRONG_PUBLIC_KEY = 25,
|
||||
/* Wrong container type(s). */
|
||||
MC_DRV_ERR_CONTAINER_TYPE_MISMATCH = 26,
|
||||
/* Container is locked (or not activated). */
|
||||
MC_DRV_ERR_CONTAINER_LOCKED = 27,
|
||||
/* SPID is not registered with root container. */
|
||||
MC_DRV_ERR_SP_NO_CHILD = 28,
|
||||
/* UUID is not registered with sp container. */
|
||||
MC_DRV_ERR_TL_NO_CHILD = 29,
|
||||
/* Unwrapping of root container failed. */
|
||||
MC_DRV_ERR_UNWRAP_ROOT_FAILED = 30,
|
||||
/* Unwrapping of service provider container failed. */
|
||||
MC_DRV_ERR_UNWRAP_SP_FAILED = 31,
|
||||
/* Unwrapping of Trustlet container failed. */
|
||||
MC_DRV_ERR_UNWRAP_TRUSTLET_FAILED = 32,
|
||||
/* No device associated with connection. */
|
||||
MC_DRV_ERR_DAEMON_DEVICE_NOT_OPEN = 33,
|
||||
/* TA blob attestation is incorrect. */
|
||||
MC_DRV_ERR_TA_ATTESTATION_ERROR = 34,
|
||||
/* Interrupted system call. */
|
||||
MC_DRV_ERR_INTERRUPTED_BY_SIGNAL = 35,
|
||||
/* Service is blocked and opensession is thus not allowed. */
|
||||
MC_DRV_ERR_SERVICE_BLOCKED = 36,
|
||||
/* Service is locked and opensession is thus not allowed. */
|
||||
MC_DRV_ERR_SERVICE_LOCKED = 37,
|
||||
/* Service was killed by the TEE (due to an administrative command). */
|
||||
MC_DRV_ERR_SERVICE_KILLED = 38,
|
||||
/* All permitted instances to the service are used */
|
||||
MC_DRV_ERR_NO_FREE_INSTANCES = 39,
|
||||
/* TA blob header is incorrect. */
|
||||
MC_DRV_ERR_TA_HEADER_ERROR = 40,
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of Session Handle, includes the Session ID and the Device ID the
|
||||
* Session belongs to.
|
||||
* The session handle will be used for session-based MobiCore communication.
|
||||
* It will be passed to calls which address a communication end point in the
|
||||
* MobiCore environment.
|
||||
*/
|
||||
struct mc_session_handle {
|
||||
u32 session_id; /* MobiCore session ID */
|
||||
u32 device_id; /* Device ID the session belongs to */
|
||||
};
|
||||
|
||||
/*
|
||||
* Information structure about additional mapped Bulk buffer between the
|
||||
* Trustlet Connector (NWd) and the Trustlet (SWd). This structure is
|
||||
* initialized from a Trustlet Connector by calling mc_map().
|
||||
* In order to use the memory within a Trustlet the Trustlet Connector has to
|
||||
* inform the Trustlet with the content of this structure via the TCI.
|
||||
*/
|
||||
struct mc_bulk_map {
|
||||
/*
|
||||
* The virtual address of the Bulk buffer regarding the address space
|
||||
* of the Trustlet, already includes a possible offset!
|
||||
*/
|
||||
u32 secure_virt_addr;
|
||||
u32 secure_virt_len; /* Length of the mapped Bulk buffer */
|
||||
};
|
||||
|
||||
/* The default device ID */
|
||||
#define MC_DEVICE_ID_DEFAULT 0
|
||||
/* Wait infinite for a response of the MC. */
|
||||
#define MC_INFINITE_TIMEOUT ((s32)(-1))
|
||||
/* Do not wait for a response of the MC. */
|
||||
#define MC_NO_TIMEOUT 0
|
||||
/* TCI/DCI must not exceed 1MiB */
|
||||
#define MC_MAX_TCI_LEN 0x100000
|
||||
|
||||
/**
|
||||
* mc_open_device() - Open a new connection to a MobiCore device.
|
||||
* @device_id: Identifier for the MobiCore device to be used.
|
||||
* MC_DEVICE_ID_DEFAULT refers to the default device.
|
||||
*
|
||||
* Initializes all device specific resources required to communicate with a
|
||||
* MobiCore instance located on the specified device in the system. If the
|
||||
* device does not exist the function will return MC_DRV_ERR_UNKNOWN_DEVICE.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_ERR_INVALID_OPERATION: device already opened
|
||||
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device_id unknown
|
||||
* MC_DRV_ERR_INVALID_DEVICE_FILE: kernel module under /dev/mobicore
|
||||
* cannot be opened
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_open_device(
|
||||
u32 device_id);
|
||||
|
||||
/**
|
||||
* mc_close_device() - Close the connection to a MobiCore device.
|
||||
* @device_id: Identifier for the MobiCore device.
|
||||
*
|
||||
* When closing a device, active sessions have to be closed beforehand.
|
||||
* Resources associated with the device will be released.
|
||||
* The device may be opened again after it has been closed.
|
||||
*
|
||||
* MC_DEVICE_ID_DEFAULT refers to the default device.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
|
||||
* MC_DRV_ERR_SESSION_PENDING: a session is still open
|
||||
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_close_device(
|
||||
u32 device_id);
|
||||
|
||||
/**
|
||||
* mc_open_session() - Open a new session to a Trustlet.
|
||||
* @session: On success, the session data will be returned
|
||||
* @uuid: UUID of the Trustlet to be opened
|
||||
* @tci: TCI buffer for communicating with the Trustlet
|
||||
* @tci_len: Length of the TCI buffer. Maximum allowed value
|
||||
* is MC_MAX_TCI_LEN
|
||||
*
|
||||
* The Trustlet with the given UUID has to be available in the flash filesystem.
|
||||
*
|
||||
* Write MCP open message to buffer and notify MobiCore about the availability
|
||||
* of a new command.
|
||||
*
|
||||
* Waits till the MobiCore responses with the new session ID (stored in the MCP
|
||||
* buffer).
|
||||
*
|
||||
* Note that session.device_id has to be the device id of an opened device.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: session parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
|
||||
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon socket occur
|
||||
* MC_DRV_ERR_NQ_FAILED: daemon returns an error
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_open_session(
|
||||
struct mc_session_handle *session,
|
||||
const struct mc_uuid_t *uuid,
|
||||
u8 *tci,
|
||||
u32 tci_len);
|
||||
|
||||
/**
|
||||
* mc_open_trustlet() - Open a new session to the provided Trustlet.
|
||||
* @session: On success, the session data will be returned
|
||||
* @spid: Service Provider ID (for SP trustlets otherwise ignored)
|
||||
* @trustlet Memory buffer containing the Trusted Application binary
|
||||
* @trustlet_len Trusted Application length
|
||||
* @tci: TCI buffer for communicating with the Trustlet
|
||||
* @tci_len: Length of the TCI buffer. Maximum allowed value
|
||||
* is MC_MAX_TCI_LEN
|
||||
*
|
||||
* Write MCP open message to buffer and notify MobiCore about the availability
|
||||
* of a new command.
|
||||
*
|
||||
* Waits till the MobiCore responses with the new session ID (stored in the MCP
|
||||
* buffer).
|
||||
*
|
||||
* Note that session.device_id has to be the device id of an opened device.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: session parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
|
||||
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon socket occur
|
||||
* MC_DRV_ERR_NQ_FAILED: daemon returns an error
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_open_trustlet(
|
||||
struct mc_session_handle *session,
|
||||
u32 spid,
|
||||
u8 *trustlet,
|
||||
u32 trustlet_len,
|
||||
u8 *tci,
|
||||
u32 len);
|
||||
|
||||
/**
|
||||
* mc_close_session() - Close a Trustlet session.
|
||||
* @session: Session to be closed.
|
||||
*
|
||||
* Closes the specified MobiCore session. The call will block until the
|
||||
* session has been closed.
|
||||
*
|
||||
* Device device_id has to be opened in advance.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: session parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
|
||||
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
|
||||
* MC_DRV_ERR_INVALID_DEVICE_FILE: daemon cannot open Trustlet file
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_close_session(
|
||||
struct mc_session_handle *session);
|
||||
|
||||
/**
|
||||
* mc_notify() - Notify a session.
|
||||
* @session: The session to be notified.
|
||||
*
|
||||
* Notifies the session end point about available message data.
|
||||
* If the session parameter is correct, notify will always succeed.
|
||||
* Corresponding errors can only be received by mc_wait_notification().
|
||||
*
|
||||
* A session has to be opened in advance.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: session parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_notify(
|
||||
struct mc_session_handle *session);
|
||||
|
||||
/**
|
||||
* mc_wait_notification() - Wait for a notification.
|
||||
* @session: The session the notification should correspond to.
|
||||
* @timeout: Time in milliseconds to wait
|
||||
* (MC_NO_TIMEOUT : direct return, > 0 : milliseconds,
|
||||
* MC_INFINITE_TIMEOUT : wait infinitely)
|
||||
*
|
||||
* Wait for a notification issued by the MobiCore for a specific session.
|
||||
* The timeout parameter specifies the number of milliseconds the call will wait
|
||||
* for a notification.
|
||||
*
|
||||
* If the caller passes 0 as timeout value the call will immediately return.
|
||||
* If timeout value is below 0 the call will block until a notification for the
|
||||
* session has been received.
|
||||
*
|
||||
* If timeout is below 0, call will block.
|
||||
*
|
||||
* Caller has to trust the other side to send a notification to wake him up
|
||||
* again.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_ERR_TIMEOUT: no notification arrived in time
|
||||
* MC_DRV_INFO_NOTIFICATION: a problem with the session was
|
||||
* encountered. Get more details with
|
||||
* mc_get_session_error_code()
|
||||
* MC_DRV_ERR_NOTIFICATION: a problem with the socket occurred
|
||||
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_wait_notification(
|
||||
struct mc_session_handle *session,
|
||||
s32 timeout);
|
||||
|
||||
/**
|
||||
* mc_malloc_wsm() - Allocate a block of world shared memory (WSM).
|
||||
* @device_id: The ID of an opened device to retrieve the WSM from.
|
||||
* @align: The alignment (number of pages) of the memory block
|
||||
* (e.g. 0x00000001 for 4kb).
|
||||
* @len: Length of the block in bytes.
|
||||
* @wsm: Virtual address of the world shared memory block.
|
||||
* @wsm_flags: Platform specific flags describing the memory to
|
||||
* be allocated.
|
||||
*
|
||||
* The MC driver allocates a contiguous block of memory which can be used as
|
||||
* WSM.
|
||||
* This implicates that the allocated memory is aligned according to the
|
||||
* alignment parameter.
|
||||
*
|
||||
* Always returns a buffer of size WSM_SIZE aligned to 4K.
|
||||
*
|
||||
* Align and wsm_flags are currently ignored
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id is invalid
|
||||
* MC_DRV_ERR_NO_FREE_MEMORY: no more contiguous memory is
|
||||
* available in this size or for this
|
||||
* process
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm(
|
||||
u32 device_id,
|
||||
u32 align,
|
||||
u32 len,
|
||||
u8 **wsm,
|
||||
u32 wsm_flags);
|
||||
|
||||
/**
|
||||
* mc_free_wsm() - Free a block of world shared memory (WSM).
|
||||
* @device_id: The ID to which the given address belongs
|
||||
* @wsm: Address of WSM block to be freed
|
||||
*
|
||||
* The MC driver will free a block of world shared memory (WSM) previously
|
||||
* allocated with mc_malloc_wsm(). The caller has to assure that the address
|
||||
* handed over to the driver is a valid WSM address.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: when device id is invalid
|
||||
* MC_DRV_ERR_FREE_MEMORY_FAILED: on failure
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(
|
||||
u32 device_id,
|
||||
u8 *wsm);
|
||||
|
||||
/**
|
||||
*mc_map() - Map additional bulk buffer between a Trustlet Connector (TLC)
|
||||
* and the Trustlet (TL) for a session
|
||||
* @session: Session handle with information of the device_id and
|
||||
* the session_id. The given buffer is mapped to the
|
||||
* session specified in the sessionHandle
|
||||
* @buf: Virtual address of a memory portion (relative to TLC)
|
||||
* to be shared with the Trustlet, already includes a
|
||||
* possible offset!
|
||||
* @len: length of buffer block in bytes.
|
||||
* @map_info: Information structure about the mapped Bulk buffer
|
||||
* between the TLC (NWd) and the TL (SWd).
|
||||
*
|
||||
* Memory allocated in user space of the TLC can be mapped as additional
|
||||
* communication channel (besides TCI) to the Trustlet. Limitation of the
|
||||
* Trustlet memory structure apply: only 6 chunks can be mapped with a maximum
|
||||
* chunk size of 1 MiB each.
|
||||
*
|
||||
* It is up to the application layer (TLC) to inform the Trustlet
|
||||
* about the additional mapped bulk memory.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
|
||||
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
|
||||
* MC_DRV_ERR_BULK_MAPPING: buf is already uses as bulk buffer or
|
||||
* when registering the buffer failed
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_map(
|
||||
struct mc_session_handle *session,
|
||||
void *buf,
|
||||
u32 len,
|
||||
struct mc_bulk_map *map_info);
|
||||
|
||||
/**
|
||||
* mc_unmap() - Remove additional mapped bulk buffer between Trustlet Connector
|
||||
* (TLC) and the Trustlet (TL) for a session
|
||||
* @session: Session handle with information of the device_id and
|
||||
* the session_id. The given buffer is unmapped from the
|
||||
* session specified in the sessionHandle.
|
||||
* @buf: Virtual address of a memory portion (relative to TLC)
|
||||
* shared with the TL, already includes a possible offset!
|
||||
* @map_info: Information structure about the mapped Bulk buffer
|
||||
* between the TLC (NWd) and the TL (SWd)
|
||||
*
|
||||
* The bulk buffer will immediately be unmapped from the session context.
|
||||
*
|
||||
* The application layer (TLC) must inform the TL about unmapping of the
|
||||
* additional bulk memory before calling mc_unmap!
|
||||
*
|
||||
* The clientlib currently ignores the len field in map_info.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
|
||||
* MC_DRV_ERR_DAEMON_UNREACHABLE: problems with daemon occur
|
||||
* MC_DRV_ERR_BULK_UNMAPPING: buf was not registered earlier
|
||||
* or when unregistering failed
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_unmap(
|
||||
struct mc_session_handle *session,
|
||||
void *buf,
|
||||
struct mc_bulk_map *map_info);
|
||||
|
||||
/*
|
||||
* mc_get_session_error_code() - Get additional error information of the last
|
||||
* error that occurred on a session.
|
||||
* @session: Session handle with information of the device_id and
|
||||
* the session_id
|
||||
* @exit_code: >0 Trustlet has terminated itself with this value,
|
||||
* <0 Trustlet is dead because of an error within the
|
||||
* MobiCore (e.g. Kernel exception). See also MCI
|
||||
* definition.
|
||||
*
|
||||
* After the request the stored error code will be deleted.
|
||||
*
|
||||
* Return codes:
|
||||
* MC_DRV_OK: operation completed successfully
|
||||
* MC_DRV_INVALID_PARAMETER: a parameter is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_SESSION: session id is invalid
|
||||
* MC_DRV_ERR_UNKNOWN_DEVICE: device id of session is invalid
|
||||
*/
|
||||
__MC_CLIENT_LIB_API enum mc_result mc_get_session_error_code(
|
||||
struct mc_session_handle *session,
|
||||
s32 *exit_code);
|
||||
|
||||
#endif /* _MOBICORE_DRIVER_API_H_ */
|
1179
drivers/gud/MobiCoreDriver/nq.c
Normal file
1179
drivers/gud/MobiCoreDriver/nq.c
Normal file
File diff suppressed because it is too large
Load diff
87
drivers/gud/MobiCoreDriver/nq.h
Normal file
87
drivers/gud/MobiCoreDriver/nq.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2020 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_NQ_H_
|
||||
#define _MC_NQ_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
/** Max number of interworld session allocated in MCI buffer */
|
||||
#define MAX_IW_SESSION 256
|
||||
|
||||
enum nq_notif_state {
|
||||
NQ_NOTIF_IDLE, /* Nothing happened yet */
|
||||
NQ_NOTIF_QUEUED, /* Notification in overflow queue */
|
||||
NQ_NOTIF_SENT, /* Notification in send queue */
|
||||
NQ_NOTIF_RECEIVED, /* Notification received */
|
||||
NQ_NOTIF_CONSUMED, /* Notification reported to CA */
|
||||
NQ_NOTIF_DEAD, /* Error reported to CA */
|
||||
};
|
||||
|
||||
/* FIXME to be renamed */
|
||||
struct nq_session {
|
||||
/* Notification id */
|
||||
u32 id;
|
||||
/* Notification payload */
|
||||
u32 payload;
|
||||
/* Notifications list */
|
||||
struct list_head list;
|
||||
/* Notification debug mutex */
|
||||
struct mutex mutex;
|
||||
/* Current notification/session state */
|
||||
enum nq_notif_state state;
|
||||
/* Time at notification state change */
|
||||
u64 cpu_clk;
|
||||
/* This TA is of Global Platform type, set by upper layer */
|
||||
int is_gp;
|
||||
};
|
||||
|
||||
/* Notification queue channel */
|
||||
void nq_session_init(struct nq_session *session, bool is_gp);
|
||||
void nq_session_exit(struct nq_session *session);
|
||||
void nq_session_state_update(struct nq_session *session,
|
||||
enum nq_notif_state state);
|
||||
int nq_session_notify(struct nq_session *session, u32 id, u32 payload);
|
||||
const char *nq_session_state(const struct nq_session *session, u64 *cpu_clk);
|
||||
|
||||
/* Services */
|
||||
union mcp_message *nq_get_mcp_buffer(void);
|
||||
struct interworld_session *nq_get_iwp_buffer(void);
|
||||
void nq_set_version_ptr(char *version);
|
||||
void nq_register_notif_handler(void (*handler)(u32 id, u32 payload), bool iwp);
|
||||
int nq_register_tee_stop_notifier(struct notifier_block *nb);
|
||||
int nq_unregister_tee_stop_notifier(struct notifier_block *nb);
|
||||
ssize_t nq_get_stop_message(char __user *buffer, size_t size);
|
||||
void nq_signal_tee_hung(void);
|
||||
|
||||
/* SWd suspend/resume */
|
||||
void add_core_to_mask(unsigned int cpu);
|
||||
void remove_core_from_mask(unsigned int cpu);
|
||||
int nq_cpu_on(unsigned int cpu);
|
||||
int nq_cpu_off(unsigned int cpu);
|
||||
int nq_suspend(void);
|
||||
int nq_resume(void);
|
||||
|
||||
/* Start/stop TEE */
|
||||
int nq_start(void);
|
||||
void nq_stop(void);
|
||||
|
||||
/* Initialisation/cleanup */
|
||||
int nq_init(void);
|
||||
void nq_exit(void);
|
||||
|
||||
#endif /* _MC_NQ_H_ */
|
178
drivers/gud/MobiCoreDriver/platform.h
Normal file
178
drivers/gud/MobiCoreDriver/platform.h
Normal file
|
@ -0,0 +1,178 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2020 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef _MC_PLATFORM_H_
|
||||
#define _MC_PLATFORM_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#if KERNEL_VERSION(4, 19, 0) <= LINUX_VERSION_CODE
|
||||
#define USE_SHM_BRIDGE
|
||||
#endif
|
||||
|
||||
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
|
||||
#include <linux/qcom_scm.h>
|
||||
#include <soc/qcom/qseecomi.h>
|
||||
#if defined USE_SHM_BRIDGE
|
||||
#include <linux/qtee_shmbridge.h>
|
||||
#endif
|
||||
#elif KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE
|
||||
#include <soc/qcom/scm.h>
|
||||
#include <soc/qcom/qseecomi.h>
|
||||
#if defined USE_SHM_BRIDGE
|
||||
#include <soc/qcom/qtee_shmbridge.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*--------------- Implementation -------------- */
|
||||
/* MobiCore Interrupt for Qualcomm (DT IRQ has priority if present) */
|
||||
#define MC_INTR_SSIQ 280
|
||||
|
||||
/* Use SMC for fastcalls */
|
||||
#define MC_SMC_FASTCALL
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 4, 0)
|
||||
#define SCM_MOBIOS_FNID(s, c) (((((s) & 0xFF) << 8) | ((c) & 0xFF)) \
|
||||
| 0x33000000)
|
||||
|
||||
#define TZ_EXECUTIVE_EXT_ID_PARAM_ID \
|
||||
TZ_SYSCALL_CREATE_PARAM_ID_4( \
|
||||
TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
||||
TZ_SYSCALL_PARAM_TYPE_VAL, \
|
||||
TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
||||
TZ_SYSCALL_PARAM_TYPE_VAL)
|
||||
#endif
|
||||
|
||||
/* from following file */
|
||||
#define SCM_SVC_MOBICORE 250
|
||||
#define SCM_CMD_MOBICORE 1
|
||||
|
||||
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
|
||||
extern int trustonic_smc_fastcall(void *fc_generic, size_t size);
|
||||
static inline int smc_fastcall(void *fc_generic, size_t size)
|
||||
{
|
||||
return trustonic_smc_fastcall(fc_generic, size);
|
||||
}
|
||||
|
||||
#elif KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE
|
||||
static inline int smc_fastcall(void *fc_generic, size_t size)
|
||||
{
|
||||
#if !defined(USE_SHM_BRIDGE)
|
||||
if (is_scm_armv8()) {
|
||||
#endif
|
||||
struct scm_desc desc = {0};
|
||||
int ret;
|
||||
static void *scm_buf;
|
||||
static phys_addr_t scm_buf_pa;
|
||||
|
||||
if (!scm_buf) {
|
||||
#if defined USE_SHM_BRIDGE
|
||||
static struct qtee_shm scm_shm = {0};
|
||||
|
||||
ret = qtee_shmbridge_allocate_shm(PAGE_ALIGN(size),
|
||||
&scm_shm);
|
||||
scm_buf = scm_shm.vaddr;
|
||||
scm_buf_pa = scm_shm.paddr;
|
||||
#else
|
||||
scm_buf = kzalloc(PAGE_ALIGN(size), GFP_KERNEL);
|
||||
scm_buf_pa = virt_to_phys(scm_buf);
|
||||
#endif
|
||||
}
|
||||
if (!scm_buf)
|
||||
return -ENOMEM;
|
||||
memcpy(scm_buf, fc_generic, size);
|
||||
dmac_flush_range(scm_buf, scm_buf + size);
|
||||
|
||||
desc.arginfo = TZ_EXECUTIVE_EXT_ID_PARAM_ID;
|
||||
desc.args[0] = scm_buf_pa;
|
||||
desc.args[1] = (u32)size;
|
||||
desc.args[2] = scm_buf_pa;
|
||||
desc.args[3] = (u32)size;
|
||||
|
||||
ret = scm_call2(
|
||||
SCM_MOBIOS_FNID(SCM_SVC_MOBICORE, SCM_CMD_MOBICORE),
|
||||
&desc);
|
||||
|
||||
dmac_flush_range(scm_buf, scm_buf + size);
|
||||
|
||||
memcpy(fc_generic, scm_buf, size);
|
||||
return ret;
|
||||
#if !defined(USE_SHM_BRIDGE)
|
||||
}
|
||||
return scm_call(SCM_SVC_MOBICORE, SCM_CMD_MOBICORE,
|
||||
fc_generic, size,
|
||||
fc_generic, size);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do not start the TEE at driver init
|
||||
*/
|
||||
#define MC_DELAYED_TEE_START
|
||||
|
||||
/*
|
||||
* Perform crypto clock enable/disable
|
||||
* of clocks
|
||||
* "bus_clk"
|
||||
* "core_clk"
|
||||
* "iface_clk"
|
||||
*/
|
||||
#ifndef RSU_INTERNAL_CLOCK
|
||||
#define MC_CRYPTO_CLOCK_MANAGEMENT
|
||||
#endif
|
||||
/*
|
||||
* This should be defined only on platforms without ICE clock e.g SDM845, SM6150, SM7225
|
||||
* #define TT_CRYPTO_NO_CLOCK_SUPPORT_FEATURE "qcom,no-clock-support"
|
||||
*/
|
||||
#define MC_CRYPTO_CLOCK_CORESRC_PROPNAME "qcom,ce-opp-freq"
|
||||
|
||||
#if defined USE_SHM_BRIDGE
|
||||
#define MC_CLOCK_CORESRC_DEFAULTRATE 192000000
|
||||
#else
|
||||
#define MC_CLOCK_CORESRC_DEFAULTRATE 100000000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Perform clock enable/disable for clock "core_clk_src"
|
||||
*/
|
||||
#define MC_DEVICE_PROPNAME "qcom,mcd"
|
||||
/*
|
||||
* Platform Node
|
||||
*/
|
||||
#define TT_CLOCK_DEVICE_NAME "qcom,qseecom"
|
||||
|
||||
/* All TZBSPv4 targets are using AARCH32_FC flag */
|
||||
#define MC_AARCH32_FC
|
||||
|
||||
/* This should be defined only on some platforms e.g SM8150, SM6150, SM7225
|
||||
* from which the Gold cores do not support TEE interfaces
|
||||
* so that CPU_IDS should list only Silver cores.
|
||||
*/
|
||||
/* Enforce/restrict statically CPUs potentially running TEE
|
||||
* (Customize to match platform CPU layout... 0xF0 for big cores only for ex).
|
||||
* If not defined TEE dynamically using all platform CPUs (recommended)
|
||||
* Warning: Both PLAT_DEFAULT_TEE_AFFINITY_MASK and
|
||||
* BIG_CORE_SWITCH_AFFINITY_MASK have to be defined
|
||||
*/
|
||||
#define PLAT_DEFAULT_TEE_AFFINITY_MASK (0xF)
|
||||
#define BIG_CORE_SWITCH_AFFINITY_MASK (0xF)
|
||||
|
||||
#endif /* _MC_PLATFORM_H_ */
|
1013
drivers/gud/MobiCoreDriver/session.c
Normal file
1013
drivers/gud/MobiCoreDriver/session.c
Normal file
File diff suppressed because it is too large
Load diff
114
drivers/gud/MobiCoreDriver/session.h
Normal file
114
drivers/gud/MobiCoreDriver/session.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2020 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _SESSION_H_
|
||||
#define _SESSION_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "mcp.h"
|
||||
#include "iwp.h"
|
||||
|
||||
struct tee_object;
|
||||
struct tee_mmu;
|
||||
struct mc_ioctl_buffer;
|
||||
|
||||
struct tee_wsm {
|
||||
/* Buffer NWd address (uva or kva, used only for lookup) */
|
||||
uintptr_t va;
|
||||
/* Buffer length */
|
||||
u32 len;
|
||||
/* Buffer flags */
|
||||
u32 flags;
|
||||
/* Buffer SWd address */
|
||||
u32 sva;
|
||||
union {
|
||||
/* MMU table */
|
||||
struct tee_mmu *mmu;
|
||||
/* Index of re-used buffer (temporary) */
|
||||
int index;
|
||||
};
|
||||
/* Pointer to associated cbuf, if relevant */
|
||||
struct cbuf *cbuf;
|
||||
/* State of this WSM */
|
||||
int in_use;
|
||||
};
|
||||
|
||||
struct tee_session {
|
||||
/* Session descriptor */
|
||||
union {
|
||||
struct mcp_session mcp_session;
|
||||
struct iwp_session iwp_session;
|
||||
};
|
||||
/* Owner */
|
||||
struct tee_client *client;
|
||||
/* Number of references kept to this object */
|
||||
struct kref kref;
|
||||
/* WSM for the TCI */
|
||||
struct tee_wsm tci;
|
||||
/* The list entry to attach to session list of owner */
|
||||
struct list_head list;
|
||||
/* Session WSMs lock */
|
||||
struct mutex wsms_lock;
|
||||
/* WSMs for a session */
|
||||
struct tee_wsm wsms[MC_MAP_MAX];
|
||||
/* This TA is of Global Platform type */
|
||||
int is_gp;
|
||||
};
|
||||
|
||||
struct tee_session *session_create(struct tee_client *client,
|
||||
const struct mc_identity *identity);
|
||||
static inline void session_get(struct tee_session *session)
|
||||
{
|
||||
kref_get(&session->kref);
|
||||
}
|
||||
|
||||
int session_put(struct tee_session *session);
|
||||
int session_close(struct tee_session *session);
|
||||
|
||||
int session_mc_open_session(struct tee_session *session,
|
||||
struct mcp_open_info *info);
|
||||
int session_mc_cleanup_session(struct tee_session *session);
|
||||
int session_mc_notify(struct tee_session *session);
|
||||
int session_mc_wait(struct tee_session *session, s32 timeout,
|
||||
int silent_expiry);
|
||||
int session_mc_map(struct tee_session *session, struct tee_mmu *mmu,
|
||||
struct mc_ioctl_buffer *bufs);
|
||||
int session_mc_unmap(struct tee_session *session,
|
||||
const struct mc_ioctl_buffer *bufs);
|
||||
int session_mc_get_err(struct tee_session *session, s32 *err);
|
||||
|
||||
int session_gp_open_session(struct tee_session *session,
|
||||
const struct mc_uuid_t *uuid,
|
||||
struct gp_operation *operation,
|
||||
struct gp_return *gp_ret);
|
||||
int session_gp_open_session_domu(struct tee_session *session,
|
||||
const struct mc_uuid_t *uuid, u64 started,
|
||||
struct interworld_session *iws,
|
||||
struct tee_mmu **mmus,
|
||||
struct gp_return *gp_ret);
|
||||
int session_gp_invoke_command(struct tee_session *session, u32 command_id,
|
||||
struct gp_operation *operation,
|
||||
struct gp_return *gp_ret);
|
||||
int session_gp_invoke_command_domu(struct tee_session *session,
|
||||
u64 started, struct interworld_session *iws,
|
||||
struct tee_mmu **mmus,
|
||||
struct gp_return *gp_ret);
|
||||
int session_gp_request_cancellation(u64 slot);
|
||||
|
||||
int session_debug_structs(struct kasnprintf_buf *buf,
|
||||
struct tee_session *session, bool is_closing);
|
||||
|
||||
#endif /* _SESSION_H_ */
|
162
drivers/gud/MobiCoreDriver/tee_client_api.h
Normal file
162
drivers/gud/MobiCoreDriver/tee_client_api.h
Normal file
|
@ -0,0 +1,162 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header file corresponds to V1.0 of the GlobalPlatform
|
||||
* TEE Client API Specification
|
||||
*/
|
||||
#ifndef __TEE_CLIENT_API_H__
|
||||
#define __TEE_CLIENT_API_H__
|
||||
|
||||
#include "tee_client_types.h"
|
||||
#include "tee_client_error.h"
|
||||
|
||||
#include "tee_client_api_imp.h"
|
||||
|
||||
#define TEEC_EXPORT
|
||||
|
||||
/*
|
||||
* The header tee_client_api_imp.h must define implementation-dependent types,
|
||||
* constants and macros.
|
||||
*
|
||||
* The implementation-dependent types are:
|
||||
* - teec_context_imp
|
||||
* - teec_session_imp
|
||||
* - teec_shared_memory_imp
|
||||
* - teec_operation_imp
|
||||
*
|
||||
* The implementation-dependent constants are:
|
||||
* - TEEC_CONFIG_SHAREDMEM_MAX_SIZE
|
||||
* The implementation-dependent macros are:
|
||||
* - TEEC_PARAM_TYPES
|
||||
*/
|
||||
|
||||
struct teec_value {
|
||||
u32 a;
|
||||
u32 b;
|
||||
};
|
||||
|
||||
/* Type definitions */
|
||||
struct teec_context {
|
||||
struct teec_context_imp imp;
|
||||
};
|
||||
|
||||
struct teec_session {
|
||||
struct teec_session_imp imp;
|
||||
};
|
||||
|
||||
struct teec_shared_memory {
|
||||
void *buffer;
|
||||
size_t size;
|
||||
u32 flags;
|
||||
struct teec_shared_memory_imp imp;
|
||||
};
|
||||
|
||||
struct teec_temp_memory_reference {
|
||||
void *buffer;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct teec_registered_memory_reference {
|
||||
struct teec_shared_memory *parent;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
union teec_parameter {
|
||||
struct teec_temp_memory_reference tmpref;
|
||||
struct teec_registered_memory_reference memref;
|
||||
struct teec_value value;
|
||||
};
|
||||
|
||||
struct teec_operation {
|
||||
u32 started;
|
||||
u32 param_types;
|
||||
union teec_parameter params[4];
|
||||
struct teec_operation_imp imp;
|
||||
};
|
||||
|
||||
#define TEEC_ORIGIN_API 0x00000001
|
||||
#define TEEC_ORIGIN_COMMS 0x00000002
|
||||
#define TEEC_ORIGIN_TEE 0x00000003
|
||||
#define TEEC_ORIGIN_TRUSTED_APP 0x00000004
|
||||
|
||||
#define TEEC_MEM_INPUT 0x00000001
|
||||
#define TEEC_MEM_OUTPUT 0x00000002
|
||||
|
||||
#define TEEC_NONE 0x0
|
||||
#define TEEC_VALUE_INPUT 0x1
|
||||
#define TEEC_VALUE_OUTPUT 0x2
|
||||
#define TEEC_VALUE_INOUT 0x3
|
||||
#define TEEC_MEMREF_TEMP_INPUT 0x5
|
||||
#define TEEC_MEMREF_TEMP_OUTPUT 0x6
|
||||
#define TEEC_MEMREF_TEMP_INOUT 0x7
|
||||
#define TEEC_MEMREF_WHOLE 0xC
|
||||
#define TEEC_MEMREF_PARTIAL_INPUT 0xD
|
||||
#define TEEC_MEMREF_PARTIAL_OUTPUT 0xE
|
||||
#define TEEC_MEMREF_PARTIAL_INOUT 0xF
|
||||
|
||||
#define TEEC_LOGIN_PUBLIC 0x00000000
|
||||
#define TEEC_LOGIN_USER 0x00000001
|
||||
#define TEEC_LOGIN_GROUP 0x00000002
|
||||
#define TEEC_LOGIN_APPLICATION 0x00000004
|
||||
#define TEEC_LOGIN_USER_APPLICATION 0x00000005
|
||||
#define TEEC_LOGIN_GROUP_APPLICATION 0x00000006
|
||||
|
||||
#define TEEC_TIMEOUT_INFINITE 0xFFFFFFFF
|
||||
|
||||
#pragma GCC visibility push(default)
|
||||
|
||||
TEEC_EXPORT u32
|
||||
teec_initialize_context(const char *name, struct teec_context *context);
|
||||
|
||||
TEEC_EXPORT void
|
||||
teec_finalize_context(struct teec_context *context);
|
||||
|
||||
TEEC_EXPORT u32
|
||||
teec_register_shared_memory(struct teec_context *context,
|
||||
struct teec_shared_memory *shared_mem);
|
||||
|
||||
TEEC_EXPORT u32
|
||||
teec_allocate_shared_memory(struct teec_context *context,
|
||||
struct teec_shared_memory *shared_mem);
|
||||
|
||||
TEEC_EXPORT void
|
||||
teec_release_shared_memory(struct teec_shared_memory *shared_mem);
|
||||
|
||||
TEEC_EXPORT u32
|
||||
teec_open_session(struct teec_context *context,
|
||||
struct teec_session *session,
|
||||
const struct teec_uuid *destination,
|
||||
u32 connection_method, /* Should be 0 */
|
||||
const void *connection_data,
|
||||
struct teec_operation *operation,
|
||||
u32 *return_origin);
|
||||
|
||||
TEEC_EXPORT void
|
||||
teec_close_session(struct teec_session *session);
|
||||
|
||||
TEEC_EXPORT u32
|
||||
teec_invoke_command(struct teec_session *session,
|
||||
u32 command_id,
|
||||
struct teec_operation *operation,
|
||||
u32 *return_origin);
|
||||
|
||||
TEEC_EXPORT void
|
||||
teec_request_cancellation(struct teec_operation *operation);
|
||||
|
||||
#pragma GCC visibility pop
|
||||
|
||||
#endif /* __TEE_CLIENT_API_H__ */
|
56
drivers/gud/MobiCoreDriver/tee_client_api_imp.h
Normal file
56
drivers/gud/MobiCoreDriver/tee_client_api_imp.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header file defines the implementation-dependent types,
|
||||
* constants and macros for all the Kinibi implementations of the TEE Client API
|
||||
*/
|
||||
#ifndef __TEE_CLIENT_API_IMP_H__
|
||||
#define __TEE_CLIENT_API_IMP_H__
|
||||
|
||||
#define TEEC_MEM_INOUT (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)
|
||||
|
||||
struct tee_client;
|
||||
|
||||
struct teec_context_imp {
|
||||
struct tee_client *client;
|
||||
};
|
||||
|
||||
struct teec_session_imp {
|
||||
u32 session_id;
|
||||
struct teec_context_imp context;
|
||||
int active;
|
||||
};
|
||||
|
||||
struct teec_shared_memory_imp {
|
||||
struct tee_client *client;
|
||||
int implementation_allocated;
|
||||
};
|
||||
|
||||
struct teec_operation_imp {
|
||||
struct teec_session_imp *session;
|
||||
};
|
||||
|
||||
/*
|
||||
* There is no natural, compile-time limit on the shared memory, but a specific
|
||||
* implementation may introduce a limit (in particular on TrustZone)
|
||||
*/
|
||||
#define TEEC_CONFIG_SHAREDMEM_MAX_SIZE ((size_t)0xFFFFFFFF)
|
||||
|
||||
#define TEEC_PARAM_TYPES(entry0_type, entry1_type, entry2_type, entry3_type) \
|
||||
((entry0_type) | ((entry1_type) << 4) | \
|
||||
((entry2_type) << 8) | ((entry3_type) << 12))
|
||||
|
||||
#endif /* __TEE_CLIENT_API_IMP_H__ */
|
120
drivers/gud/MobiCoreDriver/tee_client_error.h
Normal file
120
drivers/gud/MobiCoreDriver/tee_client_error.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __TEE_CLIENT_ERROR_H__
|
||||
#define __TEE_CLIENT_ERROR_H__
|
||||
|
||||
#define TEEC_SUCCESS ((uint32_t)0x00000000)
|
||||
|
||||
/**
|
||||
* Generic error code : Generic error
|
||||
**/
|
||||
#define TEEC_ERROR_GENERIC ((uint32_t)0xFFFF0000)
|
||||
|
||||
/**
|
||||
* Generic error code : The underlying security system denies the access to the
|
||||
* object
|
||||
**/
|
||||
#define TEEC_ERROR_ACCESS_DENIED ((uint32_t)0xFFFF0001)
|
||||
|
||||
/**
|
||||
* Generic error code : The pending operation is cancelled.
|
||||
**/
|
||||
#define TEEC_ERROR_CANCEL ((uint32_t)0xFFFF0002)
|
||||
|
||||
/**
|
||||
* Generic error code : The underlying system detects a conflict
|
||||
**/
|
||||
#define TEEC_ERROR_ACCESS_CONFLICT ((uint32_t)0xFFFF0003)
|
||||
|
||||
/**
|
||||
* Generic error code : Too much data for the operation or some data remain
|
||||
* unprocessed by the operation.
|
||||
**/
|
||||
#define TEEC_ERROR_EXCESS_DATA ((uint32_t)0xFFFF0004)
|
||||
|
||||
/**
|
||||
* Generic error code : Error of data format
|
||||
**/
|
||||
#define TEEC_ERROR_BAD_FORMAT ((uint32_t)0xFFFF0005)
|
||||
|
||||
/**
|
||||
* Generic error code : The specified parameters are invalid
|
||||
**/
|
||||
#define TEEC_ERROR_BAD_PARAMETERS ((uint32_t)0xFFFF0006)
|
||||
|
||||
/**
|
||||
* Generic error code : Illegal state for the operation.
|
||||
**/
|
||||
#define TEEC_ERROR_BAD_STATE ((uint32_t)0xFFFF0007)
|
||||
|
||||
/**
|
||||
* Generic error code : The item is not found
|
||||
**/
|
||||
#define TEEC_ERROR_ITEM_NOT_FOUND ((uint32_t)0xFFFF0008)
|
||||
|
||||
/**
|
||||
* Generic error code : The specified operation is not implemented
|
||||
**/
|
||||
#define TEEC_ERROR_NOT_IMPLEMENTED ((uint32_t)0xFFFF0009)
|
||||
|
||||
/**
|
||||
* Generic error code : The specified operation is not supported
|
||||
**/
|
||||
#define TEEC_ERROR_NOT_SUPPORTED ((uint32_t)0xFFFF000A)
|
||||
|
||||
/**
|
||||
* Generic error code : Insufficient data is available for the operation.
|
||||
**/
|
||||
#define TEEC_ERROR_NO_DATA ((uint32_t)0xFFFF000B)
|
||||
|
||||
/**
|
||||
* Generic error code : Not enough memory to perform the operation
|
||||
**/
|
||||
#define TEEC_ERROR_OUT_OF_MEMORY ((uint32_t)0xFFFF000C)
|
||||
|
||||
/**
|
||||
* Generic error code : The service is currently unable to handle the request;
|
||||
* try later
|
||||
**/
|
||||
#define TEEC_ERROR_BUSY ((uint32_t)0xFFFF000D)
|
||||
|
||||
/**
|
||||
* Generic communication error
|
||||
**/
|
||||
#define TEEC_ERROR_COMMUNICATION ((uint32_t)0xFFFF000E)
|
||||
|
||||
/**
|
||||
* Generic error code : security violation
|
||||
**/
|
||||
#define TEEC_ERROR_SECURITY ((uint32_t)0xFFFF000F)
|
||||
|
||||
/**
|
||||
* Generic error code : the buffer is too short
|
||||
**/
|
||||
#define TEEC_ERROR_SHORT_BUFFER ((uint32_t)0xFFFF0010)
|
||||
|
||||
/**
|
||||
* Error of communication: The target of the connection is dead
|
||||
**/
|
||||
#define TEEC_ERROR_TARGET_DEAD ((uint32_t)0xFFFF3024)
|
||||
|
||||
/**
|
||||
* File system error code: not enough space to complete the operation.
|
||||
**/
|
||||
#define TEEC_ERROR_STORAGE_NO_SPACE ((uint32_t)0xFFFF3041)
|
||||
|
||||
#endif /* __TEE_CLIENT_ERROR_H__ */
|
||||
|
33
drivers/gud/MobiCoreDriver/tee_client_types.h
Normal file
33
drivers/gud/MobiCoreDriver/tee_client_types.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __TEE_CLIENT_TYPES_H__
|
||||
#define __TEE_CLIENT_TYPES_H__
|
||||
|
||||
/* Definition of an UUID (from RFC 4122 http://www.ietf.org/rfc/rfc4122.txt) */
|
||||
struct teec_uuid {
|
||||
u32 time_low;
|
||||
u16 time_mid;
|
||||
u16 time_hi_and_version;
|
||||
u8 clock_seq_and_node[8];
|
||||
};
|
||||
|
||||
/* Type definition for a TEE Identity */
|
||||
struct tee_identity {
|
||||
u32 login;
|
||||
struct teec_uuid uuid;
|
||||
};
|
||||
|
||||
#endif /* __TEE_CLIENT_TYPES_H__ */
|
596
drivers/gud/MobiCoreDriver/teeclientapi.c
Normal file
596
drivers/gud/MobiCoreDriver/teeclientapi.c
Normal file
|
@ -0,0 +1,596 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "tee_client_api.h"
|
||||
#include "mc_user.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "mcinq.h" /* TA termination codes */
|
||||
#include "client.h"
|
||||
|
||||
/* Macros */
|
||||
#define _TEEC_GET_PARAM_TYPE(t, i) (((t) >> (4 * (i))) & 0xF)
|
||||
|
||||
/* Parameter number */
|
||||
#define _TEEC_PARAMETER_NUMBER 4
|
||||
|
||||
/**teec_shared_memory
|
||||
* These error codes are still to be decided by GP and as we do not wish to
|
||||
* expose any part of the GP TAF as of yet, for now they will have to live here
|
||||
* until we decide what to do about them.
|
||||
*/
|
||||
#define TEEC_ERROR_TA_LOCKED 0xFFFF0257
|
||||
#define TEEC_ERROR_SD_BLOCKED 0xFFFF0258
|
||||
#define TEEC_ERROR_TARGET_KILLED 0xFFFF0259
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(operations_wq);
|
||||
|
||||
static void _lib_uuid_to_array(const struct teec_uuid *uuid, u8 *uuid_array)
|
||||
{
|
||||
u8 *identifier_cursor = (u8 *)uuid;
|
||||
/* offsets and syntax constants. See explanations above */
|
||||
#ifdef S_BIG_ENDIAN
|
||||
u32 offsets = 0;
|
||||
#else
|
||||
u32 offsets = 0xF1F1DF13;
|
||||
#endif
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < sizeof(struct teec_uuid); i++) {
|
||||
/* Two-digit hex number */
|
||||
s32 offset = ((s32)((offsets & 0xF) << 28)) >> 28;
|
||||
u8 number = identifier_cursor[offset];
|
||||
|
||||
offsets >>= 4;
|
||||
identifier_cursor++;
|
||||
|
||||
uuid_array[i] = number;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 _teec_to_gp_operation(struct teec_operation *teec_op,
|
||||
struct gp_operation *gp_op)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < _TEEC_PARAMETER_NUMBER; i++) {
|
||||
switch (_TEEC_GET_PARAM_TYPE(teec_op->param_types, i)) {
|
||||
case TEEC_VALUE_INPUT:
|
||||
case TEEC_VALUE_INOUT:
|
||||
gp_op->params[i].value.a = teec_op->params[i].value.a;
|
||||
gp_op->params[i].value.b = teec_op->params[i].value.b;
|
||||
break;
|
||||
case TEEC_MEMREF_TEMP_INPUT:
|
||||
case TEEC_MEMREF_TEMP_OUTPUT:
|
||||
case TEEC_MEMREF_TEMP_INOUT:
|
||||
gp_op->params[i].tmpref.buffer =
|
||||
(uintptr_t)teec_op->params[i].tmpref.buffer;
|
||||
gp_op->params[i].tmpref.size =
|
||||
teec_op->params[i].tmpref.size;
|
||||
break;
|
||||
case TEEC_MEMREF_WHOLE:
|
||||
case TEEC_MEMREF_PARTIAL_INPUT:
|
||||
case TEEC_MEMREF_PARTIAL_OUTPUT:
|
||||
case TEEC_MEMREF_PARTIAL_INOUT:
|
||||
gp_op->params[i].memref.offset =
|
||||
teec_op->params[i].memref.offset;
|
||||
gp_op->params[i].memref.size =
|
||||
teec_op->params[i].memref.size;
|
||||
gp_op->params[i].memref.parent.buffer =
|
||||
(uintptr_t)teec_op->params[i].memref.parent->buffer;
|
||||
gp_op->params[i].memref.parent.size =
|
||||
teec_op->params[i].memref.parent->size;
|
||||
gp_op->params[i].memref.parent.flags =
|
||||
teec_op->params[i].memref.parent->flags;
|
||||
break;
|
||||
case TEEC_NONE:
|
||||
case TEEC_VALUE_OUTPUT:
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
gp_op->param_types = teec_op->param_types;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _teec_from_gp_operation(struct gp_operation *gp_op,
|
||||
struct teec_operation *teec_op)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _TEEC_PARAMETER_NUMBER; i++) {
|
||||
switch (_TEEC_GET_PARAM_TYPE(gp_op->param_types, i)) {
|
||||
case TEEC_VALUE_OUTPUT:
|
||||
case TEEC_VALUE_INOUT:
|
||||
teec_op->params[i].value.a = gp_op->params[i].value.a;
|
||||
teec_op->params[i].value.b = gp_op->params[i].value.b;
|
||||
break;
|
||||
case TEEC_MEMREF_TEMP_INPUT:
|
||||
case TEEC_MEMREF_TEMP_OUTPUT:
|
||||
case TEEC_MEMREF_TEMP_INOUT:
|
||||
teec_op->params[i].tmpref.size =
|
||||
gp_op->params[i].tmpref.size;
|
||||
break;
|
||||
case TEEC_MEMREF_WHOLE:
|
||||
break;
|
||||
case TEEC_MEMREF_PARTIAL_INPUT:
|
||||
case TEEC_MEMREF_PARTIAL_OUTPUT:
|
||||
case TEEC_MEMREF_PARTIAL_INOUT:
|
||||
teec_op->params[i].memref.size =
|
||||
gp_op->params[i].memref.size;
|
||||
break;
|
||||
case TEEC_NONE:
|
||||
case TEEC_VALUE_INPUT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u32 _teec_convert_error(int errno)
|
||||
{
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
return TEEC_ERROR_ITEM_NOT_FOUND;
|
||||
case EACCES:
|
||||
return TEEC_ERROR_ACCESS_DENIED;
|
||||
case EINVAL:
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
case ENOSPC:
|
||||
return TEEC_ERROR_OUT_OF_MEMORY;
|
||||
case ECONNREFUSED:
|
||||
return TEEC_ERROR_SD_BLOCKED;
|
||||
case ECONNABORTED:
|
||||
return TEEC_ERROR_TA_LOCKED;
|
||||
case ECONNRESET:
|
||||
return TEEC_ERROR_TARGET_KILLED;
|
||||
case EBUSY:
|
||||
return TEEC_ERROR_BUSY;
|
||||
case EKEYREJECTED:
|
||||
return TEEC_ERROR_SECURITY;
|
||||
case ETIME:
|
||||
return TEEC_ERROR_TARGET_DEAD;
|
||||
default:
|
||||
return TEEC_ERROR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
/* teec_initialize_context: TEEC_SUCCESS, Another error code from Table 4-2 */
|
||||
u32 teec_initialize_context(const char *name, struct teec_context *context)
|
||||
{
|
||||
struct tee_client *client;
|
||||
int ret;
|
||||
(void)name;
|
||||
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
|
||||
if (!context) {
|
||||
mc_dev_devel("context is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
/* Make sure TEE was started */
|
||||
ret = mc_wait_tee_start();
|
||||
if (ret) {
|
||||
mc_dev_err(ret, "TEE failed to start, now or in the past");
|
||||
return TEEC_ERROR_BAD_STATE;
|
||||
}
|
||||
|
||||
/* Create client */
|
||||
client = client_create(true);
|
||||
if (!client)
|
||||
return TEEC_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* Store client in context */
|
||||
context->imp.client = client;
|
||||
|
||||
return TEEC_SUCCESS;
|
||||
}
|
||||
EXPORT_SYMBOL(teec_initialize_context);
|
||||
|
||||
/*
|
||||
* The implementation of this function MUST NOT be able to fail: after this
|
||||
* function returns the Client Application must be able to consider that the
|
||||
* Context has been closed
|
||||
*/
|
||||
void teec_finalize_context(struct teec_context *context)
|
||||
{
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
|
||||
/* The parameter context MUST point to an initialized TEE Context */
|
||||
if (!context) {
|
||||
mc_dev_devel("context is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
/* The implementation of this function MUST NOT be able to fail: after
|
||||
* this function returns the Client Application must be able to
|
||||
* consider that the Context has been closed
|
||||
*/
|
||||
client_close(context->imp.client);
|
||||
context->imp.client = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(teec_finalize_context);
|
||||
|
||||
/*
|
||||
* If the return_origin is different from TEEC_ORIGIN_TRUSTED_APP, an error code
|
||||
* from Table 4-2. If the return_origin is equal to TEEC_ORIGIN_TRUSTED_APP, a
|
||||
* return code defined by the protocol between the Client Application and the
|
||||
* Trusted Application
|
||||
*/
|
||||
u32 teec_open_session(struct teec_context *context,
|
||||
struct teec_session *session,
|
||||
const struct teec_uuid *destination,
|
||||
u32 connection_method,
|
||||
const void *connection_data,
|
||||
struct teec_operation *operation,
|
||||
u32 *return_origin)
|
||||
{
|
||||
struct mc_uuid_t uuid;
|
||||
struct mc_identity identity = {0};
|
||||
struct tee_client *client = NULL;
|
||||
struct gp_operation gp_op;
|
||||
struct gp_return gp_ret;
|
||||
int ret = 0, timeout;
|
||||
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
gp_ret.value = TEEC_SUCCESS;
|
||||
if (return_origin)
|
||||
*return_origin = TEEC_ORIGIN_API;
|
||||
|
||||
/* The parameter context MUST point to an initialized TEE Context */
|
||||
if (!context) {
|
||||
mc_dev_devel("context is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
if (!context->imp.client) {
|
||||
mc_dev_devel("context not initialized");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
client = context->imp.client;
|
||||
|
||||
if (!session) {
|
||||
mc_dev_devel("session is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
connection_method = TEEC_TT_LOGIN_KERNEL;
|
||||
session->imp.active = false;
|
||||
|
||||
_lib_uuid_to_array(destination, uuid.value);
|
||||
|
||||
memset(&gp_op, 0, sizeof(gp_op));
|
||||
if (operation) {
|
||||
operation->imp.session = &session->imp;
|
||||
ret = _teec_to_gp_operation(operation, &gp_op);
|
||||
if (ret)
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
identity.login_type = (enum mc_login_type)connection_method;
|
||||
|
||||
/* Wait for GP loading to be possible, maximum 30s */
|
||||
timeout = 30;
|
||||
do {
|
||||
ret = client_gp_open_session(client, &uuid, &gp_op, &identity,
|
||||
&gp_ret, &session->imp.session_id);
|
||||
if (!ret || ret != EAGAIN)
|
||||
break;
|
||||
|
||||
msleep(1000);
|
||||
} while (--timeout);
|
||||
|
||||
if (ret || gp_ret.value != TEEC_SUCCESS) {
|
||||
mc_dev_devel("client_gp_open_session failed(%08x) %08x", ret,
|
||||
gp_ret.value);
|
||||
if (ret && ret != -ECHILD)
|
||||
gp_ret.value = _teec_convert_error(-ret);
|
||||
else if (return_origin)
|
||||
/* Update origin as it's not the API */
|
||||
*return_origin = gp_ret.origin;
|
||||
} else {
|
||||
mc_dev_devel(" created session ID %x", session->imp.session_id);
|
||||
session->imp.context = context->imp;
|
||||
session->imp.active = true;
|
||||
if (operation)
|
||||
_teec_from_gp_operation(&gp_op, operation);
|
||||
}
|
||||
|
||||
mc_dev_devel(" %s() = 0x%x", __func__, gp_ret.value);
|
||||
return gp_ret.value;
|
||||
}
|
||||
EXPORT_SYMBOL(teec_open_session);
|
||||
|
||||
u32 teec_invoke_command(struct teec_session *session,
|
||||
u32 command_id,
|
||||
struct teec_operation *operation,
|
||||
u32 *return_origin)
|
||||
{
|
||||
struct tee_client *client = NULL;
|
||||
struct gp_operation gp_op = {0};
|
||||
struct gp_return gp_ret = {0};
|
||||
int ret = 0;
|
||||
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
|
||||
gp_ret.value = TEEC_SUCCESS;
|
||||
if (return_origin)
|
||||
*return_origin = TEEC_ORIGIN_API;
|
||||
|
||||
if (!session) {
|
||||
mc_dev_devel("session is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
if (!session->imp.active) {
|
||||
mc_dev_devel("session is inactive");
|
||||
return TEEC_ERROR_BAD_STATE;
|
||||
}
|
||||
client = session->imp.context.client;
|
||||
|
||||
if (operation) {
|
||||
operation->imp.session = &session->imp;
|
||||
if (_teec_to_gp_operation(operation, &gp_op))
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
} else {
|
||||
gp_op.param_types = 0;
|
||||
}
|
||||
|
||||
ret = client_gp_invoke_command(client, session->imp.session_id,
|
||||
command_id, &gp_op, &gp_ret);
|
||||
|
||||
if (ret || gp_ret.value != TEEC_SUCCESS) {
|
||||
mc_dev_devel("client_gp_invoke_command failed(%08x) %08x", ret,
|
||||
gp_ret.value);
|
||||
if (ret && ret != -ECHILD)
|
||||
gp_ret.value = _teec_convert_error(-ret);
|
||||
else if (return_origin)
|
||||
/* Update origin as it's not the API */
|
||||
*return_origin = gp_ret.origin;
|
||||
} else if (operation) {
|
||||
_teec_from_gp_operation(&gp_op, operation);
|
||||
}
|
||||
|
||||
mc_dev_devel(" %s() = 0x%x", __func__, gp_ret.value);
|
||||
return gp_ret.value;
|
||||
}
|
||||
EXPORT_SYMBOL(teec_invoke_command);
|
||||
|
||||
void teec_close_session(struct teec_session *session)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tee_client *client = NULL;
|
||||
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
|
||||
/* The implementation MUST do nothing if session is NULL */
|
||||
if (!session) {
|
||||
mc_dev_devel("session is NULL");
|
||||
return;
|
||||
}
|
||||
client = session->imp.context.client;
|
||||
|
||||
if (session->imp.active) {
|
||||
ret = client_gp_close_session(client, session->imp.session_id);
|
||||
|
||||
if (ret)
|
||||
/* continue even in case of error */
|
||||
mc_dev_devel("client_gp_close failed(%08x)", ret);
|
||||
|
||||
session->imp.active = false;
|
||||
}
|
||||
|
||||
mc_dev_devel(" %s() = 0x%x", __func__, ret);
|
||||
}
|
||||
EXPORT_SYMBOL(teec_close_session);
|
||||
|
||||
/*
|
||||
* Implementation note. We handle internally 2 kind of pointers : kernel memory
|
||||
* (kmalloc, get_pages, ...) and dynamic memory (vmalloc). A global pointer from
|
||||
* a kernel module has the same format as a vmalloc buffer. However, our code
|
||||
* cannot detect that, so it considers it a kmalloc buffer. The TA trying to use
|
||||
* that shared buffer is likely to crash
|
||||
*/
|
||||
u32 teec_register_shared_memory(struct teec_context *context,
|
||||
struct teec_shared_memory *shared_mem)
|
||||
{
|
||||
struct gp_shared_memory memref;
|
||||
struct gp_return gp_ret;
|
||||
int ret = 0;
|
||||
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
|
||||
/* The parameter context MUST point to an initialized TEE Context */
|
||||
if (!context) {
|
||||
mc_dev_devel("context is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
/*
|
||||
* The parameter shared_mem MUST point to the Shared Memory structure
|
||||
* defining the memory region to register
|
||||
*/
|
||||
if (!shared_mem) {
|
||||
mc_dev_devel("shared_mem is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
/*
|
||||
* The buffer field MUST point to the memory region to be shared,
|
||||
* and MUST not be NULL
|
||||
*/
|
||||
if (!shared_mem->buffer) {
|
||||
mc_dev_devel("shared_mem->buffer is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
if (shared_mem->flags & ~TEEC_MEM_INOUT) {
|
||||
mc_dev_devel("shared_mem->flags is incorrect");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
if (!shared_mem->flags) {
|
||||
mc_dev_devel("shared_mem->flags is incorrect");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
memref.buffer = (uintptr_t)shared_mem->buffer;
|
||||
memref.flags = shared_mem->flags;
|
||||
memref.size = shared_mem->size;
|
||||
ret = client_gp_register_shared_mem(context->imp.client, NULL, NULL,
|
||||
&memref, &gp_ret);
|
||||
|
||||
if (ret)
|
||||
return _teec_convert_error(-ret);
|
||||
|
||||
shared_mem->imp.client = context->imp.client;
|
||||
shared_mem->imp.implementation_allocated = false;
|
||||
|
||||
return TEEC_SUCCESS;
|
||||
}
|
||||
EXPORT_SYMBOL(teec_register_shared_memory);
|
||||
|
||||
u32 teec_allocate_shared_memory(struct teec_context *context,
|
||||
struct teec_shared_memory *shared_mem)
|
||||
{
|
||||
struct gp_shared_memory memref;
|
||||
struct gp_return gp_ret;
|
||||
int ret = 0;
|
||||
|
||||
/* No connection to "context"? */
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
|
||||
/* The parameter context MUST point to an initialized TEE Context */
|
||||
if (!context) {
|
||||
mc_dev_devel("context is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
/*
|
||||
* The parameter shared_mem MUST point to the Shared Memory structure
|
||||
* defining the memory region to register
|
||||
*/
|
||||
if (!shared_mem) {
|
||||
mc_dev_devel("shared_mem is NULL");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
if (shared_mem->flags & ~TEEC_MEM_INOUT) {
|
||||
mc_dev_devel("shared_mem->flags is incorrect");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
if (!shared_mem->flags) {
|
||||
mc_dev_devel("shared_mem->flags is incorrect");
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
shared_mem->buffer = vmalloc(shared_mem->size);
|
||||
if (!shared_mem->buffer)
|
||||
return TEEC_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
memref.buffer = (uintptr_t)shared_mem->buffer;
|
||||
memref.flags = shared_mem->flags;
|
||||
memref.size = shared_mem->size;
|
||||
ret = client_gp_register_shared_mem(context->imp.client, NULL, NULL,
|
||||
&memref, &gp_ret);
|
||||
|
||||
if (ret) {
|
||||
vfree(shared_mem->buffer);
|
||||
shared_mem->buffer = NULL;
|
||||
shared_mem->size = 0;
|
||||
return _teec_convert_error(-ret);
|
||||
}
|
||||
|
||||
shared_mem->imp.client = context->imp.client;
|
||||
shared_mem->imp.implementation_allocated = true;
|
||||
|
||||
return TEEC_SUCCESS;
|
||||
}
|
||||
EXPORT_SYMBOL(teec_allocate_shared_memory);
|
||||
|
||||
void teec_release_shared_memory(struct teec_shared_memory *shared_mem)
|
||||
{
|
||||
struct gp_shared_memory memref;
|
||||
|
||||
/* No connection to "context"? */
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
|
||||
/* The implementation MUST do nothing if shared_mem is NULL */
|
||||
if (!shared_mem) {
|
||||
mc_dev_devel("shared_mem is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
memref.buffer = (uintptr_t)shared_mem->buffer;
|
||||
memref.flags = shared_mem->flags;
|
||||
memref.size = shared_mem->size;
|
||||
(void)client_gp_release_shared_mem(shared_mem->imp.client, &memref);
|
||||
|
||||
/*
|
||||
* For a memory buffer allocated using teec_allocate_shared_memory the
|
||||
* Implementation MUST free the underlying memory
|
||||
*/
|
||||
if (shared_mem->imp.implementation_allocated) {
|
||||
if (shared_mem->buffer) {
|
||||
vfree(shared_mem->buffer);
|
||||
shared_mem->buffer = NULL;
|
||||
shared_mem->size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(teec_release_shared_memory);
|
||||
|
||||
void teec_request_cancellation(struct teec_operation *operation)
|
||||
{
|
||||
struct teec_session_imp *session;
|
||||
int ret;
|
||||
|
||||
mc_dev_devel("== %s() ==============", __func__);
|
||||
|
||||
ret = wait_event_interruptible(operations_wq, operation->started);
|
||||
if (ret == -ERESTARTSYS) {
|
||||
mc_dev_devel("signal received");
|
||||
return;
|
||||
}
|
||||
|
||||
mc_dev_devel("operation->started changed from 0 to %d",
|
||||
operation->started);
|
||||
|
||||
if (operation->started > 1) {
|
||||
mc_dev_devel("the operation has finished");
|
||||
return;
|
||||
}
|
||||
|
||||
session = operation->imp.session;
|
||||
operation->started = 2;
|
||||
wake_up_interruptible(&operations_wq);
|
||||
|
||||
if (!session->active) {
|
||||
mc_dev_devel("Corresponding session is not active");
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: handle cancellation */
|
||||
|
||||
/* Signal the Trustlet */
|
||||
ret = client_notify_session(session->context.client,
|
||||
session->session_id);
|
||||
if (ret)
|
||||
mc_dev_devel("Notify failed: %d", ret);
|
||||
}
|
||||
EXPORT_SYMBOL(teec_request_cancellation);
|
423
drivers/gud/MobiCoreDriver/user.c
Normal file
423
drivers/gud/MobiCoreDriver/user.c
Normal file
|
@ -0,0 +1,423 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2013-2018 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm_types.h> /* struct vm_area_struct */
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "mc_user.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "user.h"
|
||||
#include "client.h"
|
||||
#include "mcp.h" /* mcp_get_version */
|
||||
|
||||
/*
|
||||
* Get client object from file pointer
|
||||
*/
|
||||
static inline struct tee_client *get_client(struct file *file)
|
||||
{
|
||||
return (struct tee_client *)file->private_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for system open()
|
||||
* A set of internal client data are created and initialized.
|
||||
*
|
||||
* @inode
|
||||
* @file
|
||||
* Returns 0 if OK or -ENOMEM if no allocation was possible.
|
||||
*/
|
||||
static int user_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct tee_client *client;
|
||||
|
||||
/* Create client */
|
||||
mc_dev_devel("from %s (%d)", current->comm, current->pid);
|
||||
client = client_create(false);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Store client in user file */
|
||||
file->private_data = client;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for system close()
|
||||
* The client object is freed.
|
||||
* @inode
|
||||
* @file
|
||||
* Returns 0
|
||||
*/
|
||||
static int user_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct tee_client *client = get_client(file);
|
||||
|
||||
/* Close client */
|
||||
mc_dev_devel("from %s (%d)", current->comm, current->pid);
|
||||
if (!client)
|
||||
return -EPROTO;
|
||||
|
||||
/* Detach client from user file */
|
||||
file->private_data = NULL;
|
||||
|
||||
/* Destroy client, including remaining sessions */
|
||||
client_close(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check r/w access to referenced memory
|
||||
*/
|
||||
static inline int ioctl_check_pointer(unsigned int cmd, int __user *uarg)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (_IOC_DIR(cmd) & _IOC_READ)
|
||||
#if KERNEL_VERSION(5, 0, 0) > LINUX_VERSION_CODE
|
||||
err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
|
||||
#else
|
||||
err = !access_ok(uarg, _IOC_SIZE(cmd));
|
||||
#endif
|
||||
else if (_IOC_DIR(cmd) & _IOC_WRITE)
|
||||
#if KERNEL_VERSION(5, 0, 0) > LINUX_VERSION_CODE
|
||||
err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
|
||||
#else
|
||||
err = !access_ok(uarg, _IOC_SIZE(cmd));
|
||||
#endif
|
||||
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for system ioctl()
|
||||
* Implement most of ClientLib API functions
|
||||
* @file pointer to file
|
||||
* @cmd command
|
||||
* @arg arguments
|
||||
*
|
||||
* Returns 0 for OK and an errno in case of error
|
||||
*/
|
||||
static long user_ioctl(struct file *file, unsigned int id, unsigned long arg)
|
||||
{
|
||||
struct tee_client *client = get_client(file);
|
||||
int __user *uarg = (int __user *)arg;
|
||||
int ret = -EINVAL;
|
||||
|
||||
mc_dev_devel("%u from %s", _IOC_NR(id), current->comm);
|
||||
|
||||
if (!client)
|
||||
return -EPROTO;
|
||||
|
||||
if (ioctl_check_pointer(id, uarg))
|
||||
return -EFAULT;
|
||||
|
||||
switch (id) {
|
||||
case MC_IO_HAS_SESSIONS:
|
||||
/* Freeze the client */
|
||||
if (client_has_sessions(client))
|
||||
ret = -ENOTEMPTY;
|
||||
else
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case MC_IO_OPEN_SESSION: {
|
||||
struct mc_ioctl_open_session session;
|
||||
|
||||
if (copy_from_user(&session, uarg, sizeof(session))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_mc_open_session(client, &session.uuid,
|
||||
session.tci, session.tcilen,
|
||||
&session.sid);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (copy_to_user(uarg, &session, sizeof(session))) {
|
||||
ret = -EFAULT;
|
||||
client_remove_session(client, session.sid);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MC_IO_OPEN_TRUSTLET: {
|
||||
struct mc_ioctl_open_trustlet trustlet;
|
||||
|
||||
if (copy_from_user(&trustlet, uarg, sizeof(trustlet))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_mc_open_trustlet(client, trustlet.spid,
|
||||
trustlet.buffer, trustlet.tlen,
|
||||
trustlet.tci, trustlet.tcilen,
|
||||
&trustlet.sid);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (copy_to_user(uarg, &trustlet, sizeof(trustlet))) {
|
||||
ret = -EFAULT;
|
||||
client_remove_session(client, trustlet.sid);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MC_IO_CLOSE_SESSION: {
|
||||
u32 sid = (u32)arg;
|
||||
|
||||
ret = client_remove_session(client, sid);
|
||||
break;
|
||||
}
|
||||
case MC_IO_NOTIFY: {
|
||||
u32 sid = (u32)arg;
|
||||
|
||||
ret = client_notify_session(client, sid);
|
||||
break;
|
||||
}
|
||||
case MC_IO_WAIT: {
|
||||
struct mc_ioctl_wait wait;
|
||||
|
||||
if (copy_from_user(&wait, uarg, sizeof(wait))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
ret = client_waitnotif_session(client, wait.sid, wait.timeout,
|
||||
wait.partial);
|
||||
break;
|
||||
}
|
||||
case MC_IO_MAP: {
|
||||
struct mc_ioctl_map map;
|
||||
|
||||
if (copy_from_user(&map, uarg, sizeof(map))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_mc_map(client, map.sid, NULL, &map.buf);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
/* Fill in return struct */
|
||||
if (copy_to_user(uarg, &map, sizeof(map))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MC_IO_UNMAP: {
|
||||
struct mc_ioctl_map map;
|
||||
|
||||
if (copy_from_user(&map, uarg, sizeof(map))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_mc_unmap(client, map.sid, &map.buf);
|
||||
break;
|
||||
}
|
||||
case MC_IO_ERR: {
|
||||
struct mc_ioctl_geterr __user *uerr =
|
||||
(struct mc_ioctl_geterr __user *)uarg;
|
||||
u32 sid;
|
||||
s32 exit_code;
|
||||
|
||||
if (get_user(sid, &uerr->sid)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_get_session_exitcode(client, sid, &exit_code);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
/* Fill in return struct */
|
||||
if (put_user(exit_code, &uerr->value)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MC_IO_VERSION: {
|
||||
struct mc_version_info version_info;
|
||||
|
||||
ret = mcp_get_version(&version_info);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (copy_to_user(uarg, &version_info, sizeof(version_info)))
|
||||
ret = -EFAULT;
|
||||
|
||||
break;
|
||||
}
|
||||
case MC_IO_GP_INITIALIZE_CONTEXT: {
|
||||
struct mc_ioctl_gp_initialize_context context;
|
||||
|
||||
if (copy_from_user(&context, uarg, sizeof(context))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_gp_initialize_context(client, &context.ret);
|
||||
|
||||
if (copy_to_user(uarg, &context, sizeof(context))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MC_IO_GP_REGISTER_SHARED_MEM: {
|
||||
struct mc_ioctl_gp_register_shared_mem shared_mem;
|
||||
|
||||
if (copy_from_user(&shared_mem, uarg, sizeof(shared_mem))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_gp_register_shared_mem(client, NULL, NULL,
|
||||
&shared_mem.memref,
|
||||
&shared_mem.ret);
|
||||
|
||||
if (copy_to_user(uarg, &shared_mem, sizeof(shared_mem))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MC_IO_GP_RELEASE_SHARED_MEM: {
|
||||
struct mc_ioctl_gp_release_shared_mem shared_mem;
|
||||
|
||||
if (copy_from_user(&shared_mem, uarg, sizeof(shared_mem))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_gp_release_shared_mem(client, &shared_mem.memref);
|
||||
break;
|
||||
}
|
||||
case MC_IO_GP_OPEN_SESSION: {
|
||||
struct mc_ioctl_gp_open_session session;
|
||||
|
||||
if (copy_from_user(&session, uarg, sizeof(session))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_gp_open_session(client, &session.uuid,
|
||||
&session.operation,
|
||||
&session.identity,
|
||||
&session.ret, &session.session_id);
|
||||
|
||||
if (copy_to_user(uarg, &session, sizeof(session))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MC_IO_GP_CLOSE_SESSION: {
|
||||
struct mc_ioctl_gp_close_session session;
|
||||
|
||||
if (copy_from_user(&session, uarg, sizeof(session))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_gp_close_session(client, session.session_id);
|
||||
break;
|
||||
}
|
||||
case MC_IO_GP_INVOKE_COMMAND: {
|
||||
struct mc_ioctl_gp_invoke_command command;
|
||||
|
||||
if (copy_from_user(&command, uarg, sizeof(command))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = client_gp_invoke_command(client, command.session_id,
|
||||
command.command_id,
|
||||
&command.operation,
|
||||
&command.ret);
|
||||
|
||||
if (copy_to_user(uarg, &command, sizeof(command))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MC_IO_GP_REQUEST_CANCELLATION: {
|
||||
struct mc_ioctl_gp_request_cancellation cancel;
|
||||
|
||||
if (copy_from_user(&cancel, uarg, sizeof(cancel))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
client_gp_request_cancellation(client,
|
||||
cancel.operation.started);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
mc_dev_err(ret, "unsupported command no %d", id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for system mmap()
|
||||
*/
|
||||
static int user_mmap(struct file *file, struct vm_area_struct *vmarea)
|
||||
{
|
||||
struct tee_client *client = get_client(file);
|
||||
|
||||
if ((vmarea->vm_end - vmarea->vm_start) > BUFFER_LENGTH_MAX) {
|
||||
mc_dev_err(-EINVAL, "buffer size %lu too big",
|
||||
vmarea->vm_end - vmarea->vm_start);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Alloc contiguous buffer for this client */
|
||||
return client_cbuf_create(client,
|
||||
(u32)(vmarea->vm_end - vmarea->vm_start),
|
||||
NULL, vmarea);
|
||||
}
|
||||
|
||||
static const struct file_operations mc_user_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = user_open,
|
||||
.release = user_release,
|
||||
.unlocked_ioctl = user_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = user_ioctl,
|
||||
#endif
|
||||
.mmap = user_mmap,
|
||||
};
|
||||
|
||||
int mc_user_init(struct cdev *cdev)
|
||||
{
|
||||
cdev_init(cdev, &mc_user_fops);
|
||||
return 0;
|
||||
}
|
26
drivers/gud/MobiCoreDriver/user.h
Normal file
26
drivers/gud/MobiCoreDriver/user.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2013-2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _USER_H_
|
||||
#define _USER_H_
|
||||
|
||||
struct cdev;
|
||||
|
||||
int mc_user_init(struct cdev *cdev);
|
||||
static inline void mc_user_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* _USER_H_ */
|
1163
drivers/gud/MobiCoreDriver/xen_be.c
Normal file
1163
drivers/gud/MobiCoreDriver/xen_be.c
Normal file
File diff suppressed because it is too large
Load diff
37
drivers/gud/MobiCoreDriver/xen_be.h
Normal file
37
drivers/gud/MobiCoreDriver/xen_be.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_XEN_BE_H_
|
||||
#define _MC_XEN_BE_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
struct xen_be_map;
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
int xen_be_init(void);
|
||||
void xen_be_exit(void);
|
||||
#else
|
||||
static inline int xen_be_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void xen_be_exit(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MC_XEN_BE_H_ */
|
62
drivers/gud/MobiCoreDriver/xen_common.c
Normal file
62
drivers/gud/MobiCoreDriver/xen_common.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
|
||||
#include "main.h"
|
||||
#include "client.h"
|
||||
#include "xen_common.h"
|
||||
|
||||
struct tee_xfe *tee_xfe_create(struct xenbus_device *xdev)
|
||||
{
|
||||
struct tee_xfe *xfe;
|
||||
|
||||
/* Alloc */
|
||||
xfe = kzalloc(sizeof(*xfe), GFP_KERNEL);
|
||||
if (!xfe)
|
||||
return NULL;
|
||||
|
||||
atomic_inc(&g_ctx.c_xen_fes);
|
||||
/* Init */
|
||||
dev_set_drvdata(&xdev->dev, xfe);
|
||||
xfe->xdev = xdev;
|
||||
kref_init(&xfe->kref);
|
||||
xfe->evtchn_domu = -1;
|
||||
xfe->evtchn_dom0 = -1;
|
||||
xfe->irq_domu = -1;
|
||||
xfe->irq_dom0 = -1;
|
||||
INIT_LIST_HEAD(&xfe->list);
|
||||
mutex_init(&xfe->ring_mutex);
|
||||
init_completion(&xfe->ring_completion);
|
||||
return xfe;
|
||||
}
|
||||
|
||||
static void tee_xfe_release(struct kref *kref)
|
||||
{
|
||||
struct tee_xfe *xfe = container_of(kref, struct tee_xfe, kref);
|
||||
|
||||
if (xfe->client)
|
||||
client_close(xfe->client);
|
||||
|
||||
kfree(xfe);
|
||||
atomic_dec(&g_ctx.c_xen_fes);
|
||||
}
|
||||
|
||||
void tee_xfe_put(struct tee_xfe *xfe)
|
||||
{
|
||||
kref_put(&xfe->kref, tee_xfe_release);
|
||||
}
|
||||
|
||||
#endif
|
179
drivers/gud/MobiCoreDriver/xen_common.h
Normal file
179
drivers/gud/MobiCoreDriver/xen_common.h
Normal file
|
@ -0,0 +1,179 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_XEN_COMMON_H_
|
||||
#define _MC_XEN_COMMON_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <xen/events.h>
|
||||
#include <xen/grant_table.h>
|
||||
#include <xen/xen.h>
|
||||
#include <xen/xenbus.h>
|
||||
|
||||
#include "mc_user.h" /* many types */
|
||||
#include "mciiwp.h"
|
||||
#include "mcimcp.h"
|
||||
#include "mmu.h" /* PMD/PTE max entries */
|
||||
#include "client.h" /* For BE to treat other VMs as clients */
|
||||
|
||||
#define TEE_XEN_VERSION 3
|
||||
|
||||
#define TEE_BUFFERS 4
|
||||
|
||||
enum tee_xen_domu_cmd {
|
||||
TEE_XEN_DOMU_NONE,
|
||||
TEE_XEN_GET_VERSION,
|
||||
/* TEE_XEN_MC_OPEN_DEVICE = 11, SWd does not support this */
|
||||
/* TEE_XEN_MC_CLOSE_DEVICE, SWd does not support this */
|
||||
TEE_XEN_MC_HAS_SESSIONS = 13,
|
||||
TEE_XEN_MC_OPEN_SESSION,
|
||||
TEE_XEN_MC_OPEN_TRUSTLET,
|
||||
TEE_XEN_MC_CLOSE_SESSION,
|
||||
TEE_XEN_MC_NOTIFY,
|
||||
TEE_XEN_MC_WAIT,
|
||||
TEE_XEN_MC_MAP,
|
||||
TEE_XEN_MC_UNMAP,
|
||||
TEE_XEN_MC_GET_ERR,
|
||||
/* TEE_XEN_GP_INITIALIZE_CONTEXT = 21, SWd does not support this */
|
||||
/* TEE_XEN_GP_FINALIZE_CONTEXT, SWd does not support this */
|
||||
TEE_XEN_GP_REGISTER_SHARED_MEM = 23,
|
||||
TEE_XEN_GP_RELEASE_SHARED_MEM,
|
||||
TEE_XEN_GP_OPEN_SESSION,
|
||||
TEE_XEN_GP_CLOSE_SESSION,
|
||||
TEE_XEN_GP_INVOKE_COMMAND,
|
||||
TEE_XEN_GP_REQUEST_CANCELLATION,
|
||||
};
|
||||
|
||||
enum tee_xen_dom0_cmd {
|
||||
TEE_XEN_DOM0_NONE,
|
||||
TEE_XEN_MC_WAIT_DONE = TEE_XEN_MC_WAIT,
|
||||
TEE_XEN_GP_OPEN_SESSION_DONE = TEE_XEN_GP_OPEN_SESSION,
|
||||
TEE_XEN_GP_CLOSE_SESSION_DONE = TEE_XEN_GP_CLOSE_SESSION,
|
||||
TEE_XEN_GP_INVOKE_COMMAND_DONE = TEE_XEN_GP_INVOKE_COMMAND,
|
||||
};
|
||||
|
||||
union tee_xen_mmu_table {
|
||||
/* Array of references to pages (PTE_ENTRIES_MAX or PMD_ENTRIES_MAX) */
|
||||
grant_ref_t *refs;
|
||||
/* Address of table */
|
||||
void *addr;
|
||||
/* Page for table */
|
||||
unsigned long page;
|
||||
};
|
||||
|
||||
struct tee_xen_buffer_info {
|
||||
/* Page Middle Directory, refs to tee_xen_pte_table's (full pages) */
|
||||
grant_ref_t pmd_ref;
|
||||
/* Total number of refs for buffer */
|
||||
u32 nr_refs;
|
||||
u64 addr; /* Unique VM address */
|
||||
u32 offset;
|
||||
u32 length;
|
||||
u32 flags;
|
||||
u32 sva;
|
||||
};
|
||||
|
||||
/* Convenience structure to get buffer info and contents in one place */
|
||||
struct tee_xen_buffer {
|
||||
struct tee_xen_buffer_info *info;
|
||||
union tee_xen_mmu_table data;
|
||||
};
|
||||
|
||||
struct tee_xen_ring {
|
||||
/* DomU side, synchronous and asynchronous commands */
|
||||
struct {
|
||||
enum tee_xen_domu_cmd cmd; /* in */
|
||||
u32 id; /* in (debug) */
|
||||
/* Return code of this command from Dom0 */
|
||||
int otherend_ret; /* out */
|
||||
struct mc_uuid_t uuid; /* in */
|
||||
u32 session_id; /* in/out */
|
||||
/* Buffers to share (4 for GP, 2 for mcOpenTrustlet) */
|
||||
struct tee_xen_buffer_info buffers[TEE_BUFFERS]; /* in */
|
||||
/* MC */
|
||||
struct mc_version_info version_info; /* out */
|
||||
u32 spid; /* in */
|
||||
s32 timeout; /* in */
|
||||
s32 err; /* out */
|
||||
/* GP */
|
||||
u64 operation_id; /* in */
|
||||
struct gp_return gp_ret; /* out */
|
||||
struct interworld_session iws; /* in */
|
||||
} domu;
|
||||
|
||||
/* Dom0 side, response to asynchronous command, never read by Dom0 */
|
||||
struct {
|
||||
enum tee_xen_dom0_cmd cmd; /* in */
|
||||
u32 id; /* in (debug) */
|
||||
/* Return code from command */
|
||||
int cmd_ret; /* in */
|
||||
/* The operation id is used to match GP request and response */
|
||||
u64 operation_id; /* in */
|
||||
struct gp_return gp_ret; /* in */
|
||||
struct interworld_session iws; /* in */
|
||||
/* The session id is used to match MC request and response */
|
||||
u32 session_id; /* in */
|
||||
} dom0;
|
||||
};
|
||||
|
||||
struct tee_xfe {
|
||||
struct xenbus_device *xdev;
|
||||
struct kref kref;
|
||||
grant_ref_t ring_ref;
|
||||
int pte_entries_max;
|
||||
int evtchn_domu;
|
||||
int evtchn_dom0;
|
||||
int irq_domu;
|
||||
int irq_dom0;
|
||||
struct list_head list;
|
||||
struct tee_client *client;
|
||||
struct work_struct work;
|
||||
/* Ring page */
|
||||
union {
|
||||
unsigned long ring_ul;
|
||||
void *ring_p;
|
||||
struct tee_xen_ring *ring;
|
||||
};
|
||||
/* Buffer pages */
|
||||
struct tee_xen_buffer buffers[TEE_BUFFERS];
|
||||
struct mutex ring_mutex; /* Protect our side of ring */
|
||||
struct completion ring_completion;
|
||||
int ring_busy;
|
||||
/* Unique ID for commands */
|
||||
u32 domu_cmd_id;
|
||||
};
|
||||
|
||||
struct tee_xfe *tee_xfe_create(struct xenbus_device *xdev);
|
||||
static inline void tee_xfe_get(struct tee_xfe *xfe)
|
||||
{
|
||||
kref_get(&xfe->kref);
|
||||
}
|
||||
|
||||
void tee_xfe_put(struct tee_xfe *xfe);
|
||||
|
||||
static inline void ring_get(struct tee_xfe *xfe)
|
||||
{
|
||||
mutex_lock(&xfe->ring_mutex);
|
||||
xfe->ring_busy = true;
|
||||
}
|
||||
|
||||
static inline void ring_put(struct tee_xfe *xfe)
|
||||
{
|
||||
xfe->ring_busy = false;
|
||||
mutex_unlock(&xfe->ring_mutex);
|
||||
}
|
||||
|
||||
#endif /* _MC_XEN_COMMON_H_ */
|
1194
drivers/gud/MobiCoreDriver/xen_fe.c
Normal file
1194
drivers/gud/MobiCoreDriver/xen_fe.c
Normal file
File diff suppressed because it is too large
Load diff
67
drivers/gud/MobiCoreDriver/xen_fe.h
Normal file
67
drivers/gud/MobiCoreDriver/xen_fe.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2017 TRUSTONIC LIMITED
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MC_XEN_FE_H_
|
||||
#define _MC_XEN_FE_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "client.h"
|
||||
#include "iwp.h"
|
||||
#include "mcp.h"
|
||||
|
||||
#ifdef TRUSTONIC_XEN_DOMU
|
||||
/* MC protocol interface */
|
||||
int xen_mc_get_version(struct mc_version_info *version_info);
|
||||
int xen_mc_open_session(struct mcp_session *session,
|
||||
struct mcp_open_info *info);
|
||||
int xen_mc_close_session(struct mcp_session *session);
|
||||
int xen_mc_map(u32 session_id, struct tee_mmu *mmu, u32 *sva);
|
||||
int xen_mc_unmap(u32 session_id, const struct mcp_buffer_map *map);
|
||||
int xen_mc_notify(struct mcp_session *session);
|
||||
int xen_mc_wait(struct mcp_session *session, s32 timeout, bool silent_expiry);
|
||||
int xen_mc_get_err(struct mcp_session *session, s32 *err);
|
||||
/* GP protocol interface */
|
||||
int xen_gp_register_shared_mem(struct tee_mmu *mmu, u32 *sva,
|
||||
struct gp_return *gp_ret);
|
||||
int xen_gp_release_shared_mem(struct mcp_buffer_map *map);
|
||||
int xen_gp_open_session(struct iwp_session *session,
|
||||
const struct mc_uuid_t *uuid,
|
||||
const struct iwp_buffer_map *maps,
|
||||
struct interworld_session *iws,
|
||||
struct interworld_session *op_iws,
|
||||
struct gp_return *gp_ret);
|
||||
int xen_gp_close_session(struct iwp_session *session);
|
||||
int xen_gp_invoke_command(struct iwp_session *session,
|
||||
const struct iwp_buffer_map *maps,
|
||||
struct interworld_session *iws,
|
||||
struct gp_return *gp_ret);
|
||||
int xen_gp_request_cancellation(u64 slot);
|
||||
|
||||
int xen_fe_init(int (*probe)(void), int (*start)(void));
|
||||
void xen_fe_exit(void);
|
||||
#else
|
||||
static inline int xen_fe_init(int (*probe)(void), int (*start)(void))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void xen_fe_exit(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MC_XEN_FE_H_ */
|
8
drivers/gud/README
Normal file
8
drivers/gud/README
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
Trustonic TEE is an operating system being shipped with TZBSP
|
||||
on MSM chipsets. t-base consists of several components in
|
||||
the secure world(TrustZone) and non-secure world(linux
|
||||
kernel, Android user space). The t-base driver
|
||||
communicates with the Trustonic TEE kernel that exists in
|
||||
TrustZone.
|
||||
|
10
drivers/input/misc/bos0614_mmi/Android.mk
Normal file
10
drivers/input/misc/bos0614_mmi/Android.mk
Normal file
|
@ -0,0 +1,10 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := bos0614_mmi.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
KBUILD_OPTIONS_GKI += GKI_OBJ_MODULE_DIR=gki
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
14
drivers/input/misc/bos0614_mmi/Kbuild
Normal file
14
drivers/input/misc/bos0614_mmi/Kbuild
Normal file
|
@ -0,0 +1,14 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include \
|
||||
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/input/misc/bos0614_mmi \
|
||||
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/input/misc/bos0614_mmi/libs/dk-core/src \
|
||||
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/input/misc/bos0614_mmi/libs/dk-core
|
||||
|
||||
EXTRA_CFLAGS += -DMOTOROLA
|
||||
EXTRA_CFLAGS += -DLITTLE_ENDIAN=1234 -DBYTE_ORDER=LITTLE_ENDIAN
|
||||
|
||||
obj-m := bos0614_mmi.o
|
||||
bos0614_mmi-objs := i2cLinux.o bosDriver.o
|
||||
bos0614_mmi-objs += libs/dk-core/src/bsp/drivers/haptic/bos0614Driver.o
|
||||
bos0614_mmi-objs += libs/dk-core/contribs/comm-stack-dk/data.o
|
339
drivers/input/misc/bos0614_mmi/LICENSE
Normal file
339
drivers/input/misc/bos0614_mmi/LICENSE
Normal file
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
10
drivers/input/misc/bos0614_mmi/Makefile
Normal file
10
drivers/input/misc/bos0614_mmi/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue